package org.papervision3d.core.geom { import flash.utils.Dictionary; import org.papervision3d.core.culling.ITriangleCuller; import org.papervision3d.core.geom.renderables.Triangle3D; import org.papervision3d.core.geom.renderables.Triangle3DInstance; import org.papervision3d.core.geom.renderables.Vertex3D; import org.papervision3d.core.geom.renderables.Vertex3DInstance; import org.papervision3d.core.math.NumberUV; import org.papervision3d.core.proto.*; import org.papervision3d.core.render.command.RenderTriangle; import org.papervision3d.core.render.data.RenderSessionData; import org.papervision3d.core.render.draw.ITriangleDrawer; import org.papervision3d.objects.DisplayObject3D; /** * The Mesh3D class lets you create and display solid 3D objects made of vertices and triangular polygons. */ public class student_ar_org_papervision3d_core_geom_TriangleMesh3D extends Vertices3D { // ___________________________________________________________________________________________________ // N E W // NN NN EEEEEE WW WW // NNN NN EE WW WW WW // NNNNNN EEEE WWWWWWWW // NN NNN EE WWW WWW // NN NN EEEEEE WW WW /** * Creates a new Mesh object. * * The Mesh DisplayObject3D class lets you create and display solid 3D objects made of vertices and triangular polygons. *
* @param material A MaterialObject3D object that contains the material properties of the object. * * @param vertices An array of Vertex3D objects for the vertices of the mesh. * * @param faces An array of Face3D objects for the faces of the mesh. * */ public function student_ar_org_papervision3d_core_geom_TriangleMesh3D( material:MaterialObject3D, vertices:Array, faces:Array, name:String=null ) { super( vertices, name ); this.geometry.faces = faces || new Array(); this.material = material || MaterialObject3D.DEFAULT; } /** * Clones this object. * * @return The cloned DisplayObject3D. */ public override function clone():DisplayObject3D { var object:DisplayObject3D = super.clone(); var mesh:student_ar_org_papervision3d_core_geom_TriangleMesh3D = new student_ar_org_papervision3d_core_geom_TriangleMesh3D(this.material, [], [], object.name); if(this.materials) mesh.materials = this.materials.clone(); if(object.geometry) mesh.geometry = object.geometry.clone(mesh); mesh.copyTransform(this.transform); return mesh; } // ___________________________________________________________________________________________________ // P R O J E C T // PPPPP RRRRR OOOO JJ EEEEEE CCCC TTTTTT // PP PP RR RR OO OO JJ EE CC CC TT // PPPPP RRRRR OO OO JJ EEEE CC TT // PP RR RR OO OO JJ JJ EE CC CC TT // PP RR RR OOOO JJJJ EEEEEE CCCC TT /** * Projects three dimensional coordinates onto a two dimensional plane to simulate the relationship of the camera to subject. * * This is the first step in the process of representing three dimensional shapes two dimensionally. * * @param camera Camera3D object to render from. */ public override function project( parent :DisplayObject3D, renderSessionData:RenderSessionData):Number { // Vertices //super.project(parent, renderSessionData); _dtStore = [];//_dtStore.concat(_dtActive); _dtActive = new Array(); var ps:Array = []; if(renderSessionData.clipping && this.useClipping && !this.culled && (renderSessionData.camera.useCulling?cullTest==0:true)){ super.projectEmpty(parent, renderSessionData); renderSessionData.clipping.setDisplayObject(this, renderSessionData); for each(var f:Triangle3D in this.geometry.faces){ if(renderSessionData.clipping.testFace(f, this, renderSessionData)){ renderSessionData.clipping.clipFace(f, this, mat, renderSessionData, ps); }else{ ps.push(f); } } renderSessionData.camera.projectFaces(ps, this, renderSessionData); }else{ super.project(parent, renderSessionData); ps = this.geometry.faces; } if(!this.culled){ // Faces var faces:Array = this.geometry.faces, screenZs:Number = 0, visibleFaces :Number = 0, triCuller:ITriangleCuller = renderSessionData.triangleCuller, vertex0:Vertex3DInstance, vertex1:Vertex3DInstance, vertex2:Vertex3DInstance, iFace:Triangle3DInstance, face:Triangle3D, mat:MaterialObject3D, rc:RenderTriangle; for each(face in ps){ mat = face.material ? face.material : material; //iFace = face.face3DInstance; vertex0 = face.v0.vertex3DInstance; vertex1 = face.v1.vertex3DInstance; vertex2 = face.v2.vertex3DInstance; //clip first, then cull, then ignore if(triCuller.testFace(face, vertex0, vertex1, vertex2)){ rc = face.renderCommand; screenZs += rc.screenZ = setScreenZ(meshSort, vertex0, vertex1, vertex2); visibleFaces++; rc.renderer = mat as ITriangleDrawer; rc.v0 = vertex0; rc.v1 = vertex1; rc.v2 = vertex2; rc.uv0 = face.uv0; rc.uv1 = face.uv1; rc.uv2 = face.uv2; //we only want to perform some operations if we have quadtree on //we can simplify this, but calling update on each rendercommand will slow the loop if(renderSessionData.quadrantTree){ if(rc.create == null) rc.create = createRenderTriangle; //update the rendercommand for the tree rc.update(); //if we should see the back of the triangle - flip it so quad will work on it if(rc.area < 0 && (face.material.doubleSided || (face.material.oneSide && face.material.opposite)) ){ var vt:Vertex3DInstance = rc.v1; rc.v1 = rc.v2; rc.v2 = vt; rc.area = - rc.area; rc.uv0 = face.uv0; rc.uv1 = face.uv2; rc.uv2 = face.uv1; } } renderSessionData.renderer.addToRenderList(rc); }else{ renderSessionData.renderStatistics.culledTriangles++; } } return this.screenZ = screenZs / visibleFaces; }else{ renderSessionData.renderStatistics.culledObjects++; return 0; } } private function setScreenZ(meshSort:uint, vertex0:Vertex3DInstance, vertex1:Vertex3DInstance, vertex2:Vertex3DInstance):Number{ switch(meshSort) { case DisplayObject3D.MESH_SORT_CENTER: return (vertex0.z + vertex1.z + vertex2.z)/3; case DisplayObject3D.MESH_SORT_FAR: return Math.max(vertex0.z,vertex1.z,vertex2.z); case DisplayObject3D.MESH_SORT_CLOSE: return Math.min(vertex0.z,vertex1.z,vertex2.z); } return 0; } /** * Planar projection from the specified plane. * * @param u The texture horizontal axis. Can be "x", "y" or "z". The default value is "x". * @param v The texture vertical axis. Can be "x", "y" or "z". The default value is "y". */ public function projectTexture( u:String="x", v:String="y" ):void { var faces :Array = this.geometry.faces, bBox :Object = this.boundingBox(), minX :Number = bBox.min[u], sizeX :Number = bBox.size[u], minY :Number = bBox.min[v], sizeY :Number = bBox.size[v]; var objectMaterial :MaterialObject3D = this.material; for( var i:String in faces ) { var myFace :Triangle3D = faces[Number(i)], myVertices :Array = myFace.vertices, a :Vertex3D = myVertices[0], b :Vertex3D = myVertices[1], c :Vertex3D = myVertices[2], uvA :NumberUV = new NumberUV( (a[u] - minX) / sizeX, (a[v] - minY) / sizeY ), uvB :NumberUV = new NumberUV( (b[u] - minX) / sizeX, (b[v] - minY) / sizeY ), uvC :NumberUV = new NumberUV( (c[u] - minX) / sizeX, (c[v] - minY) / sizeY ); myFace.uv = [ uvA, uvB, uvC ]; } } /** * Divides all faces into 4. */ public function quarterFaces():void { var newverts:Array = new Array(); var newfaces:Array = new Array(); var faces:Array = this.geometry.faces; var face:Triangle3D; var i:int = faces.length; while( face = faces[--i] ) { var v0:Vertex3D = face.v0; var v1:Vertex3D = face.v1; var v2:Vertex3D = face.v2; var v01:Vertex3D = new Vertex3D((v0.x+v1.x)/2, (v0.y+v1.y)/2, (v0.z+v1.z)/2); var v12:Vertex3D = new Vertex3D((v1.x+v2.x)/2, (v1.y+v2.y)/2, (v1.z+v2.z)/2); var v20:Vertex3D = new Vertex3D((v2.x+v0.x)/2, (v2.y+v0.y)/2, (v2.z+v0.z)/2); this.geometry.vertices.push(v01, v12, v20); var t0:NumberUV = face.uv[0]; var t1:NumberUV = face.uv[1]; var t2:NumberUV = face.uv[2]; var t01:NumberUV = new NumberUV((t0.u+t1.u)/2, (t0.v+t1.v)/2); var t12:NumberUV = new NumberUV((t1.u+t2.u)/2, (t1.v+t2.v)/2); var t20:NumberUV = new NumberUV((t2.u+t0.u)/2, (t2.v+t0.v)/2); var f0:Triangle3D = new Triangle3D(this, [v0, v01, v20], face.material, [t0, t01, t20]); var f1:Triangle3D = new Triangle3D(this, [v01, v1, v12], face.material, [t01, t1, t12]); var f2:Triangle3D = new Triangle3D(this, [v20, v12, v2], face.material, [t20, t12, t2]); var f3:Triangle3D = new Triangle3D(this, [v01, v12, v20], face.material, [t01, t12, t20]); newfaces.push(f0, f1, f2, f3); } this.geometry.faces = newfaces; this.mergeVertices(); this.geometry.ready = true; } /** * Merges duplicated vertices. */ public function mergeVertices():void { var uniqueDic :Dictionary = new Dictionary(), uniqueList :Array = new Array(); // Find unique vertices for each( var v:Vertex3D in this.geometry.vertices ) { for each( var vu:Vertex3D in uniqueDic ) { if( v.x == vu.x && v.y == vu.y && v.z == vu.z ) { uniqueDic[ v ] = vu; break; } } if( ! uniqueDic[ v ] ) { uniqueDic[ v ] = v; uniqueList.push( v ); } } // Use unique vertices list this.geometry.vertices = uniqueList; // Update faces for each( var f:Triangle3D in geometry.faces ) { f.v0 = uniqueDic[ f.v0 ]; f.v1 = uniqueDic[ f.v1 ]; f.v2 = uniqueDic[ f.v2 ]; } } override public function set material(material:MaterialObject3D):void { super.material = material; for each(var triangle:Triangle3D in geometry.faces){ triangle.material = material; } } private var _dtStore:Array = new Array(); private var _dtActive:Array = new Array(); private var _tri:RenderTriangle; public function createRenderTriangle(face:Triangle3D, material:MaterialObject3D, v0:Vertex3DInstance, v1:Vertex3DInstance, v2:Vertex3DInstance, uv0:NumberUV, uv1:NumberUV, uv2:NumberUV):RenderTriangle { if (_dtStore.length) { _dtActive.push(_tri = _dtStore.pop()); } else { _dtActive.push(_tri = new RenderTriangle(face)); } _tri.instance = this; _tri.triangle = face; _tri.renderableInstance = face; _tri.renderer = material; _tri.create = createRenderTriangle; _tri.v0 = v0; _tri.v1 = v1; _tri.v2 = v2; _tri.uv0 = uv0; _tri.uv1 = uv1; _tri.uv2 = uv2; _tri.update(); return _tri; } } }