因爲項目需要,我們需要在瀏覽器展現3D建築模型。經過一段時間的技術選型,我們覺得Flex是現在瀏覽器展現3D模型比較成熟技術。我們工作流程也是美工根據實際物體或者場景製作3D的模型爲DAE文件。Flex通過Papervision3D的引擎來加載DAE的模型展現和交互。
3D模型加載源代碼:
<?xml version="1.0" encoding="utf-8"?>
<view:BaseSimpleContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:view="com.shine.framework.core.view.*"
creationComplete="{complete()}"
xmlns:view1="com.shine.framework.Papervision3D.view.*">
<view:layout>
<s:BasicLayout/>
</view:layout>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.MoveEvent;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.cameras.SpringCamera3D;
import org.papervision3d.events.FileLoadEvent;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.lights.PointLight3D;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.parsers.DAE;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
private var daeFilePath:String;
//3D視窗
private var viewport:Viewport3D;
//3D場景
private var scene:Scene3D;
//3D照相機
private var camera:Camera3D;
//定位
private var renderer:BasicRenderEngine;
private var dae:DAE;
private var controlDisplayObject3D:DisplayObject3D;
private var oMouseX:Number;
private var oMouseY:Number;
private var tMouseX:Number;
private var tMouseY:Number;
private var cameraX:Number;
private var cameraY:Number;
private var target:DisplayObject3D;
private var configFilePath:String;
[Bindle]
private var debug:Boolean;
private function complete():void{
////
}
public function changeDebug(value:Boolean):void{
this.debug=value;
}
//加載DAE file
public function loadDaeFile(value:String):void{
this.daeFilePath=value;
initDae3D();
}
public function loadConfigFile(value:String):void{
this.configFilePath=value;
}
//繪畫3D
private function initDae3D():void{
dae = new DAE();
dae.load(this.daeFilePath);
dae.addEventListener(FileLoadEvent.LOAD_COMPLETE, handleLoadComplete);
dae.addEventListener(FileLoadEvent.LOAD_ERROR, handleLoadError);
dae.addEventListener(FileLoadEvent.LOAD_PROGRESS, handleProgress);
dae.addEventListener(FileLoadEvent.SECURITY_LOAD_ERROR, handleSecurity);
dae.addEventListener(FileLoadEvent.COLLADA_MATERIALS_DONE, handleMaterialsDone);
}
//Load Collada
private function handleLoadComplete(e:Event):void
{
this.completeLoading();
initViewPort();
//messageText.text = "COLLADA LOAD COMPLETE";
}
private function handleLoadError(e:Event):void
{
}
private function handleProgress(e:Event):void
{
}
private function handleSecurity(e:Event):void
{
}
private function handleMaterialsDone(e:Event):void
{
//initViewPort();
}
private function initViewPort():void{
//Setup viewport, add to stage
viewport = new Viewport3D(this.width,this.height,false,false);
canvas.rawChildren.addChild(viewport);
//Setup renderer
renderer = new BasicRenderEngine();
//Setup camera
camera = new Camera3D();
camera.fov=18;
camera.x=0;
camera.y=0;
camera.z=-1000;
target=new DisplayObject3D();
target.x=0;
target.y=0;
target.z=0;
camera.target=target;
//Setup scene
scene = new Scene3D();
//Setup container, add dae to container, add container to scene.
scene.addChild(dae);
//Alert.show(dae.childrenList());
//Alert.show(dae.getChildByName("COLLADA_Scene").childrenList());
//Alert.show(dae.getChildByName("COLLADA_Scene").getChildByName("Pyramid001").childrenList());
//dae.getChildByName("COLLADA_Scene").getChildByName("Pyramid001").addEventListener(InteractiveScene3DEvent.OBJECT_CLICK,onClick);
//dae.getChildByName("COLLADA_Scene",true).addEventListener(InteractiveScene3DEvent.OBJECT_PRESS,onClick);
dae.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS,onClick);
placePosition();
render();
}
private function onClick(event:InteractiveScene3DEvent):void{
}
private function placePosition():void{
dae.x=0;
dae.y=0;
dae.rotationZ=0;
}
private function render():void
{
renderer.renderScene(scene,camera,viewport);
}
//設置攝像頭位置
public function setCameraPosition(x:Number,y:Number,z:Number):void{
camera.x=x;
camera.y=y;
camera.z=z;
render();
}
private function setCameraFov(value:Number):void{
camera.fov=value;
render();
}
private function zoomAdd():void{
camera.moveForward(100);
render();
}
private function zoomRemove():void{
camera.moveBackward(100);
render();
}
private function zoomUp():void{
camera.moveUp(100);
render();
}
private function zoomDown():void{
camera.moveDown(100);
render();
}
private function zoomLeft():void{
camera.moveLeft(100);
render();
}
private function zoomRight():void{
camera.moveRight(100);
render();
}
private function zoomTargetUp():void{
target.x=camera.target.x;
target.y=camera.target.y+100;
target.z=camera.target.z;
label.text=target.x+","+target.y+","+target.z;
render();
}
private function zoomTargetDown():void{
target.x=camera.target.x;
target.y=camera.target.y-100;
target.z=camera.target.z;
label.text=target.x+","+target.y+","+target.z;
render();
}
private function zoomTargetLeft():void{
target.x=camera.target.x-100;
target.y=camera.target.y;
target.z=camera.target.z;
label.text=target.x+","+target.y+","+target.z;
render();
}
private function zoomTargetRight():void{
target.x=camera.target.x+100;
target.y=camera.target.y;
target.z=camera.target.z;
label.text=target.x+","+target.y+","+target.z;
render();
}
private function reset():void{
target.x=0;
target.y=0;
target.z=0;
label.text=0+","+0+","+0;
camera.x=0;
camera.y=0;
camera.z=-1000;
render();
}
]]>
</fx:Script>
<mx:Canvas id="canvas" width="100%" height="100%"/>
<view1:EdgeContainer id="topEdge" width="100%" height="20" click="{zoomTargetUp()}"/>
<view1:EdgeContainer id="downEdge" y="{this.height-20}" width="100%" height="20" click="{zoomTargetDown()}"/>
<view1:EdgeContainer id="leftEdge" width="20" height="100%" click="{zoomTargetLeft()}"/>
<view1:EdgeContainer id="rightEdge" x="{this.width-20}" width="20" height="100%" click="{zoomTargetRight()}"/>
<s:VGroup id="group" x="{this.width-120}" y="0" width="120" height="100">
<s:Button label="放大" click="{zoomAdd()}"/>
<s:Button label="縮小" click="{zoomRemove()}"/>
<s:Button label="上" click="{zoomUp()}"/>
<s:Button label="下" click="{zoomDown()}"/>
<s:Button label="左" click="{zoomLeft()}"/>
<s:Button label="右" click="{zoomRight()}"/>
<s:Button label="重置" click="{reset()}"/>
<s:Label id="label" text="0,0,0"/>
</s:VGroup>
</view:BaseSimpleContainer>
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:Papervision3D="com.shine.framework.Papervision3D.*">
<fx:Declarations>
<!-- 將非可視元素(例如服務、值對象)放在此處 -->
</fx:Declarations>
<Papervision3D:Papervision3DForDaeContainer id="papervision3DContainer"
width="100%" height="100%"
creationComplete="{papervision3DContainer.loadDaeFile('room/house-new.DAE')}" />
</s:Application>
DAE源代碼:
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Administrator</author>
<authoring_tool>OpenCOLLADA for 3ds Max; Version: 1.2.5; Revision: 68731:68732; Platform: x64; Configuration: Release Max2011</authoring_tool>
<source_data>file:///E:/%E9%99%86%E8%90%8D/3D/3Dmax%E7%BB%83%E4%B9%A0/house.max</source_data>
</contributor>
<created>2012-07-05T14:47:24</created>
<modified>2012-07-05T14:47:24</modified>
<unit name="millimeter" meter="0.001"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_effects>
<effect id="____">
<profile_COMMON>
<newparam sid="house_jpg-surface">
<surface type="2D">
<init_from>house_jpg</init_from>
</surface>
</newparam>
<newparam sid="house_jpg-sampler">
<sampler2D>
<source>house_jpg-surface</source>
</sampler2D>
</newparam>
<technique sid="common">
<blinn>
<emission>
<color>0 0 0 1</color>
</emission>
<ambient>
<color>0.5960785 0.5960785 0.5960785 1</color>
</ambient>
<diffuse>
<texture texture="house_jpg-sampler" texcoord="CHANNEL1"/>
</diffuse>
<specular>
<color>0.9 0.9 0.9 1</color>
</specular>
<shininess>
<float>9.999999</float>
</shininess>
<reflective>
<color>0 0 0 1</color>
</reflective>
<transparent opaque="A_ONE">
<color>1 1 1 1</color>
</transparent>
<transparency>
<float>1</float>
</transparency>
</blinn>
</technique>
</profile_COMMON>
<extra>
<technique profile="OpenCOLLADA3dsMax">
<extended_shader>
<apply_reflection_dimming>0</apply_reflection_dimming>
<dim_level>0</dim_level>
<falloff_type>0</falloff_type>
<index_of_refraction>1.5</index_of_refraction>
<opacity_type>0</opacity_type>
<reflection_level>3</reflection_level>
<wire_size>1</wire_size>
<wire_units>0</wire_units>
</extended_shader>
<shader>
<ambient_diffuse_lock>1</ambient_diffuse_lock>
<ambient_diffuse_texture_lock>1</ambient_diffuse_texture_lock>
<diffuse_specular_lock>0</diffuse_specular_lock>
<soften>0.1</soften>
<use_self_illum_color>0</use_self_illum_color>
</shader>
</technique>
</extra>
</effect>
</library_effects>
<library_materials>
<material id="____-material" name="____">
<instance_effect url="#____"/>
</material>
</library_materials>
<library_geometries>
<geometry id="geom-Pyramid001" name="Pyramid001">
<mesh>
<source id="geom-Pyramid001-positions">
<float_array id="geom-Pyramid001-positions-array" count="18">0 0 1836.045 -663.0164 -2320.557 0 663.0164 -2320.557 0 663.0164 2320.557 0 -663.0164 2320.557 0 0 0 0</float_array>
<technique_common>
<accessor source="#geom-Pyramid001-positions-array" count="6" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="geom-Pyramid001-normals">
<float_array id="geom-Pyramid001-normals-array" count="51">0 -0.6204822 0.7842206 0 -0.6204822 0.7842205 0 -0.6204822 0.7842205 0.9405539 0 0.3396445 0.9405539 0 0.3396445 0.9405539 0 0.3396445 0 0.6204822 0.7842206 0 0.6204822 0.7842205 0 0.6204822 0.7842205 -0.9405539 0 0.3396445 -0.9405539 0 0.3396445 -0.9405539 0 0.3396445 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1</float_array>
<technique_common>
<accessor source="#geom-Pyramid001-normals-array" count="17" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="geom-Pyramid001-map1">
<float_array id="geom-Pyramid001-map1-array" count="51">0.9014655 0.3870191 0 0.8135806 0.3851358 0 0.7504084 0.6062383 0 0.6872362 0.387019 0 0.6872362 0.8292241 0 0.8135806 0.8273408 0 0.2524371 0.2311026 0 0.4273754 0.01 0 0.4273754 0.4522052 0 0.2524371 0.6897829 0 0.4273754 0.4686803 0 0.07317217 0.9686654 0 0.01 0.7475629 0 0.1363443 0.7475629 0 0.4273754 0.9108855 0 0.9646376 0.6081216 0 0.8382932 0.6081216 0</float_array>
<technique_common>
<accessor source="#geom-Pyramid001-map1-array" count="17" stride="3">
<param name="S" type="float"/>
<param name="T" type="float"/>
<param name="P" type="float"/>
</accessor>
</technique_common>
</source>
<source id="geom-Pyramid001-map1-textangents">
<float_array id="geom-Pyramid001-map1-textangents-array" count="51">-1 0 0 -1 0 0 -1 0 0 0.3396445 5.50797e-8 -0.9405539 0.3396445 5.50797e-8 -0.9405539 0.3396445 5.50797e-8 -0.9405539 -1 0 0 -1 0 0 -1 0 0 -0.3396445 -1.60232e-7 -0.9405539 -0.3396445 -1.60232e-7 -0.9405539 -0.3396445 -1.60232e-7 -0.9405539 -0.999944 0.007483723 0 -0.9998334 0.01490172 0 -0.999722 0.02238306 0 -0.9997229 0.02231972 0 -0.9999449 0.00742038 0</float_array>
<technique_common>
<accessor source="#geom-Pyramid001-map1-textangents-array" count="17" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="geom-Pyramid001-map1-texbinormals">
<float_array id="geom-Pyramid001-map1-texbinormals-array" count="51">0 0.7842205 0.6204822 0 0.7842205 0.6204822 0 0.7842205 0.6204822 1.87075e-8 -1 -5.18054e-8 1.87075e-8 -1 -5.18054e-8 1.87075e-8 -1 -5.18054e-8 0 0.7842205 -0.6204822 0 0.7842205 -0.6204822 0 0.7842205 -0.6204822 -5.44219e-8 1 -1.50707e-7 -5.44219e-8 1 -1.50707e-7 -5.44219e-8 1 -1.50707e-7 -0.007483933 -0.999972 0 -0.01490255 -0.999889 0 -0.02238368 -0.9997495 0 -0.02232034 -0.9997509 0 -0.007420584 -0.9999725 0</float_array>
<technique_common>
<accessor source="#geom-Pyramid001-map1-texbinormals-array" count="17" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="geom-Pyramid001-vertices">
<input semantic="POSITION" source="#geom-Pyramid001-positions"/>
</vertices>
<triangles material="_____1" count="8">
<input semantic="VERTEX" source="#geom-Pyramid001-vertices" offset="0"/>
<input semantic="NORMAL" source="#geom-Pyramid001-normals" offset="1"/>
<input semantic="TEXCOORD" source="#geom-Pyramid001-map1" offset="2" set="1"/>
<input semantic="TEXTANGENT" source="#geom-Pyramid001-map1-textangents" offset="3" set="1"/>
<input semantic="TEXBINORMAL" source="#geom-Pyramid001-map1-texbinormals" offset="3" set="1"/>
<p>0 0 0 0 1 1 15 1 2 2 16 2 0 3 6 3 2 4 7 4 3 5 8 5 0 6 11 6 3 7 12 7 4 8 13 8 0 9 9 9 4 10 10 10 1 11 14 11 1 12 1 12 5 13 2 13 2 14 3 14 2 14 3 14 5 13 2 13 3 15 4 15 3 15 4 15 5 13 2 13 4 16 5 16 4 16 5 16 5 13 2 13 1 12 1 12</p>
</triangles>
</mesh>
</geometry>
</library_geometries>
<library_lights>
<light id="EnvironmentAmbientLight" name="EnvironmentAmbientLight">
<technique_common>
<ambient>
<color>0 0 0</color>
</ambient>
</technique_common>
</light>
</library_lights>
<library_images>
<image id="house_jpg">
<init_from>./images/house.jpg</init_from>
</image>
</library_images>
<library_visual_scenes>
<visual_scene id="MaxScene">
<node name="EnvironmentAmbientLight">
<instance_light url="#EnvironmentAmbientLight"/>
</node>
<node id="node-Pyramid001" name="Pyramid001">
<matrix>2.023743 0 0 1331.657 0 0.9331092 0 2349.663 0 0 1 2324.805 0 0 0 1</matrix>
<instance_geometry url="#geom-Pyramid001">
<bind_material>
<technique_common>
<instance_material symbol="_____1" target="#____-material">
<bind_vertex_input semantic="CHANNEL1" input_semantic="TEXCOORD" input_set="1"/>
</instance_material>
</technique_common>
</bind_material>
</instance_geometry>
<extra>
<technique profile="Alternativa3D">
<instance xmlns="http://alternativaplatform.com/a3d/Instance">
<instance_mesh url="#Pyramid001-mesh"/>
</instance>
</technique>
</extra>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#MaxScene"/>
</scene>
<extra>
<technique profile="Alternativa3D">
<library xmlns="http://alternativaplatform.com/a3d/Library">
<library_meshes>
<mesh id="Pyramid001-mesh"/>
</library_meshes>
<version>2.4</version>
</library>
</technique>
</extra>
</COLLADA>
實際效果: