📄 dae.as
字号:
* Build all animation channels. */ private function buildAnimationChannels():void { var target:DisplayObject3D; var channel:DaeChannel; var channelsByObject:Dictionary = new Dictionary(true); var i:int; _channelsByTarget = new Dictionary(true); for each(var animation:DaeAnimation in this.document.animations) { for(i = 0; i < animation.channels.length; i++) { channel = animation.channels[i]; target = _colladaIDToObject[channel.syntax.targetID]; if(!target) throw new Error("damn"); if(!channelsByObject[target]) channelsByObject[target] = new Array(); channelsByObject[target].push(channel); } } for(var object:* in channelsByObject) { target = object as DisplayObject3D; var channels:Array = channelsByObject[object]; var node:DaeNode = _objectToNode[target]; if(!node) throw new Error("Couldn't find the targeted object with name '" + node.name + "'"); node.channels = channels; if(!channels.length) continue; channel = channels[0]; var transform:DaeTransform = node.findMatrixBySID(channel.syntax.targetSID); if(!transform) { trace("Could not find a transform with SID=" + channel.syntax.targetSID); continue; } // the object has a single <matrix> channel if(channels.length == 1 && transform.type == ASCollada.DAE_MATRIX_ELEMENT) { _channelsByTarget[target] = [buildAnimationChannel(target, channel)]; continue; } // the object has multiple channels, lets bake 'm into a single channel var allTimes:Array = new Array(); var times:Array = new Array(); var lastTime:Number; // fetch all times for all channels for each(channel in channels) allTimes = allTimes.concat(channel.input); allTimes.sort(Array.NUMERIC); // make array with unique times for(i = 0; i < allTimes.length; i++) { var t:Number = allTimes[i]; if(i == 0) times.push(t); else if(t - lastTime > 0.01) times.push(t); lastTime = t; } // build the MatrixChannel3D's for this object var mcs:Object = new Object(); for each(channel in channels) { var animationChannel:MatrixChannel3D = buildAnimationChannel(target, channel); if(animationChannel) mcs[ channel.syntax.targetSID ] = buildAnimationChannel(target, channel); } var bakedChannel:MatrixChannel3D = new MatrixChannel3D(target); // build a baked channel for(i = 0; i < times.length; i++) { var keyframeTime:Number = times[i]; var bakedMatrix:Matrix3D = Matrix3D.IDENTITY; // loop over the DaeNode's transform-stack for(var j:int = 0; j < node.transforms.length; j++) { transform = node.transforms[j]; var matrixChannel:MatrixChannel3D = mcs[ transform.sid ]; if(matrixChannel) { // this transform is animated, so lets determine the matrix for the current keyframeTime var time:Number; if(keyframeTime < matrixChannel.startTime) time = 0; else if(keyframeTime > matrixChannel.endTime) time = 1; else time = keyframeTime / (matrixChannel.endTime - matrixChannel.startTime); // update the channel by time, so the matrix for the current keyframe is setup matrixChannel.updateToTime(time); // bake the matrix bakedMatrix = Matrix3D.multiply(bakedMatrix, target.transform); } else { // this transform isn't animated, simply bake the transform into the matrix bakedMatrix = Matrix3D.multiply(bakedMatrix, buildMatrixFromTransform(transform)); } } // now we can add the baked matrix as a new keyframe bakedChannel.addKeyFrame(new AnimationKeyFrame3D("frame_" + i, keyframeTime, [bakedMatrix])); } _channelsByTarget[target] = [bakedChannel]; } } /** * Build a color from RGB values. * * @param rgb * * @return */ private function buildColor( rgb:Array ):uint { var r:uint = rgb[0] * 0xff; var g:uint = rgb[1] * 0xff; var b:uint = rgb[2] * 0xff; return (r<<16|g<<8|b); } /** * Creates the faces for a COLLADA primitive. @see org.ascollada.core.DaePrimitive * * @param primitive * @param geometry * @param voffset * * @return The created faces. */ private function buildFaces(primitive:DaePrimitive, geometry:GeometryObject3D, voffset:uint):void { var faces:Array = new Array(); var material:MaterialObject3D = this.materials.getMaterialByName(primitive.material); material = material || MaterialObject3D.DEFAULT; // retreive correct texcoord-set for the material. var obj:DaeBindVertexInput = _textureSets[primitive.material] is DaeBindVertexInput ? _textureSets[primitive.material] : null; var setID:int = (obj is DaeBindVertexInput) ? obj.input_set : 1; var texCoordSet:Array = primitive.getTexCoords(setID); var texcoords:Array = new Array(); var i:int, j:int = 0, k:int; // texture coords for( i = 0; i < texCoordSet.length; i++ ) texcoords.push(new NumberUV(texCoordSet[i][0], texCoordSet[i][1])); var hasUV:Boolean = (texcoords.length == primitive.vertices.length); var idx:Array = new Array(); var v:Array = new Array(); var uv:Array = new Array(); switch( primitive.type ) { // Each line described by the mesh has two vertices. The first line is formed // from first and second vertices. The second line is formed from the third and fourth // vertices and so on. case ASCollada.DAE_LINES_ELEMENT: for( i = 0; i < primitive.vertices.length; i += 2 ) { v[0] = geometry.vertices[ primitive.vertices[i] ]; v[1] = geometry.vertices[ primitive.vertices[i+1] ]; uv[0] = hasUV ? texcoords[ i ] : new NumberUV(); uv[1] = hasUV ? texcoords[ i+1 ] : new NumberUV(); //geometry.faces.push( new Triangle3D(instance, [v[0], v[1], v[1]], material, [uv[0], uv[1], uv[1]]) ); } break; // simple triangles case ASCollada.DAE_TRIANGLES_ELEMENT: for(i = 0, j = 0; i < primitive.vertices.length; i += 3, j++) { idx[0] = voffset + primitive.vertices[i]; idx[1] = voffset + primitive.vertices[i+1]; idx[2] = voffset + primitive.vertices[i+2]; v[0] = geometry.vertices[ idx[0] ]; v[1] = geometry.vertices[ idx[1] ]; v[2] = geometry.vertices[ idx[2] ]; uv[0] = hasUV ? texcoords[ i+0 ] : new NumberUV(); uv[1] = hasUV ? texcoords[ i+1 ] : new NumberUV(); uv[2] = hasUV ? texcoords[ i+2 ] : new NumberUV(); geometry.faces.push(new Triangle3D(null, [v[0], v[1], v[2]], material, [uv[0], uv[1], uv[2]])); } break; // polygon with *no* holes case ASCollada.DAE_POLYLIST_ELEMENT: for( i = 0, k = 0; i < primitive.vcount.length; i++ ) { var poly:Array = new Array(); var uvs:Array = new Array(); for( j = 0; j < primitive.vcount[i]; j++ ) { uvs.push( (hasUV ? texcoords[ k ] : new NumberUV()) ); poly.push( geometry.vertices[primitive.vertices[k++]] ); } if( !geometry || !geometry.faces || !geometry.vertices ) throw new Error( "no geometry" ); v[0] = poly[0]; uv[0] = uvs[0]; for( j = 1; j < poly.length - 1; j++ ) { v[1] = poly[j]; v[2] = poly[j+1]; uv[1] = uvs[j]; uv[2] = uvs[j+1]; geometry.faces.push(new Triangle3D(null, [v[0], v[1], v[2]], material, [uv[0], uv[1], uv[2]])); } } break; // polygons *with* holes (but holes not yet processed...) case ASCollada.DAE_POLYGONS_ELEMENT: for(i = 0, k = 0; i < primitive.polygons.length; i++) { var p:Array = primitive.polygons[i]; var np:Array = new Array(); var nuv:Array = new Array(); for(j = 0; j < p.length; j++) { nuv.push( (hasUV ? texcoords[ k ] : new NumberUV()) ); np.push( geometry.vertices[primitive.vertices[k++]] ); } v[0] = np[0]; uv[0] = nuv[0]; for(j = 1; j < np.length - 1; j++) { v[1] = np[j]; v[2] = np[j+1]; uv[1] = nuv[j]; uv[2] = nuv[j+1]; geometry.faces.push(new Triangle3D(null, [v[0], v[1], v[2]], material, [uv[0], uv[1], uv[2]])); } } break; default: throw new Error("Don't know how to create face for a DaePrimitive with type = " + primitive.type); } } /** * * @param asset * @return */ private function buildFileInfo( asset:* ):void { this.filename = asset is String ? String(asset) : "./meshes/rawdata_dae"; // make sure we've got forward slashes! this.filename = this.filename.split("\\").join("/"); if( this.filename.indexOf("/") != -1 ) { // dae is located in a sub-directory of the swf. var parts:Array = this.filename.split("/"); this.fileTitle = String( parts.pop() ); this.baseUrl = parts.join("/"); } else { // dae is located in root directory of swf. this.fileTitle = this.filename; this.baseUrl = ""; } } /** * Builds all COLLADA geometries. */ private function buildGeometries():void { var i:int, j:int, k:int; _geometries = new Object(); for each(var geometry:DaeGeometry in this.document.geometries) { if(geometry.mesh) { var g:GeometryObject3D = new GeometryObject3D(); g.vertices = buildVertices(geometry.mesh); g.faces = new Array(); for(i = 0; i < geometry.mesh.primitives.length; i++) { buildFaces(geometry.mesh.primitives[i], g, 0); } _geometries[geometry.id] = g; } else if(geometry.spline && geometry.splines) { var lines:Lines3D = new Lines3D(new LineMaterial(DEFAULT_LINE_COLOR), geometry.id); for(i = 0; i < geometry.splines.length; i++) { var spline:DaeSpline = geometry.splines[i]; for(j = 0; j < spline.vertices.length; j++) { k = (j+1) % spline.vertices.length; var v0:Vertex3D = new Vertex3D(spline.vertices[j][0], spline.vertices[j][1], spline.vertices[j][2]); var v1:Vertex3D = new Vertex3D(spline.vertices[k][0], spline.vertices[k][1], spline.vertices[k][2]); var line:Line3D = new Line3D(lines, lines.material as LineMaterial, DEFAULT_LINE_WIDTH, v0, v1); lines.addLine(line); } } _geometries[geometry.id] = lines; } } } /** * * @return */ private function buildImagePath( meshFolderPath:String, imgPath:String ):String { if (texturePath != null) imgPath = texturePath + imgPath.slice( imgPath.lastIndexOf("/") + 1 ); var baseParts:Array = meshFolderPath.split("/"); var imgParts:Array = imgPath.split("/"); while( baseParts[0] == "." ) baseParts.shift(); while( imgParts[0] == "." ) imgParts.shift(); while( imgParts[0] == ".." ) { imgParts.shift(); baseParts.pop(); } var imgUrl:String = baseParts.length > 1 ? baseParts.join("/") : (baseParts.length?baseParts[0]:""); imgUrl = imgUrl != "" ? imgUrl + "/" + imgParts.join("/") : imgParts.join("/"); return imgUrl; } /** * Builds the materials. */ private function buildMaterials():void { _queuedMaterials = new Array(); for( var materialId:String in this.document.materials ) { var material:MaterialObject3D = null; var daeMaterial:DaeMaterial = this.document.materials[ materialId ]; var symbol:String = this.document.materialTargetToSymbol[ daeMaterial.id ]; // material already exists in our materialsList, no need to process if(this.materials.getMaterialByName(symbol)) continue; var effect:DaeEffect = document.effects[ daeMaterial.effect ]; var lambert:DaeLambert = effect.color as DaeLambert; // save the texture-set if necessary if(lambert && lambert.diffuse.texture) { _textureSets[daeMaterial.id] = lambert.diffuse.texture.texcoord; } // if the material has a texture, qeueu the bitmap if(effect && effect.texture_url) { var image:DaeImage = document.images[effect.texture_url]; if(image) { var imageUrl:String = buildImagePath(this.baseUrl, image.init_from); material = new BitmapFileMaterial(); material.doubleSided = effect.double_sided; _queuedMaterials.push({symbol:symbol, url:imageUrl, material:material}); continue; } } if(lambert && lambert.diffuse.color) { if(effect.wireframe) material = new WireframeMaterial(buildColor(lambert.diffuse.color)); else material = new ColorMaterial(buildColor(lambert.diffuse.color)); } else material = MaterialObject3D.DEFAULT; material.doubleSided = effect.double_sided; this.materials.addMaterial(material, symbol); } } /** * Builds a Matrix3D from a node's transform array. @see org.ascollada.core.DaeNode#transforms * * @param node * * @return */ private function buildMatrix(node:DaeNode):Matrix3D { var stack:Array = buildMatrixStack(node); var matrix:Matrix3D = Matrix3D.IDENTITY; for( var i:int = 0; i < stack.length; i++ ) matrix.calculateMultiply4x4(matrix, stack[i]); return matrix; } /** * * @param node * @return */ private function buildMatrixFromTransform(transform:DaeTransform):Matrix3D { var matrix:Matrix3D; var toRadians:Number = Math.PI/180; var v:Array = transform.values; switch(transform.type) { case ASCollada.DAE_ROTATE_ELEMENT: matrix = Matrix3D.rotationMatrix(v[0], v[1], v[2], v[3] * toRadians); break; case ASCollada.DAE_SCALE_ELEMENT: matrix = Matrix3D.scaleMatrix(v[0], v[1], v[2]); break; case ASCollada.DAE_TRANSLATE_ELEMENT: matrix = Matrix3D.translationMatrix(v[0], v[1], v[2]); break; case ASCollada.DAE_MATRIX_ELEMENT: matrix = new Matrix3D(v); break; default: throw new Error("Unknown transform type: " + transform.type); } return matrix; } /** * * @param node * @return */ private function buildMatrixStack(node:DaeNode):Array { var stack:Array = new Array(); for( var i:int = 0; i < node.transforms.length; i++ ) stack.push(buildMatrixFromTransform(node.transforms[i])); return stack; } /** * Builds a DisplayObject3D from a node. @see org.ascollada.core.DaeNode * * @param node * * @return The created DisplayObject3D. @see org.papervision3d.objects.DisplayObject3D */ private function buildNode(node:DaeNode, parent:DisplayObject3D):void { var instance:DisplayObject3D; var material:MaterialObject3D; var i:int; if(node.controllers.length) { // controllers, can be of type 'skin' or 'morph' for(i = 0; i < node.controllers.length; i++) { var instanceController:DaeInstanceController = node.controllers[i]; var colladaController:DaeController = document.controllers[instanceController.url]; if(colladaController.skin) { instance = new Skin3D(null, [], [], node.name); buildSkin(instance as Skin3D, colladaController.skin, instanceController.skeletons, node); } else if(colladaController.morph) { throw new Error("morph!"); } else throw new Error("A COLLADA controller should be of type <skin> or <morph>!"); // dunnu yet how to handle multiple controllers. break; } } else if(node.geometries.length) { // got geometry, so create a TriangleMesh3D
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -