public void ExpandLibraryNode( LibraryNode lnode, string referrerId, Matrix4 localTransform, Matrix4 transform, ColladaMeshInfo meshInfo ) { // recurse through any child nodes int childNo = 0; foreach( LibraryNode child in lnode.children ) ExpandLibraryNode( child, referrerId + "." + (childNo++).ToString(), localTransform, transform, meshInfo ); // expand geometry_instance references int instNo = 0; foreach( string geoInstanceId in lnode.geoInstanceIds ) { GeometryInstance geoInstance = new GeometryInstance( referrerId + "." + (instNo++).ToString(), null, localTransform, transform ); if( meshInfo.Geometries.ContainsKey( geoInstanceId ) ) { // this was an instance_geometry instead of an instance_controller in 1.4 terms geoInstance.controller = null; geoInstance.geoSet = meshInfo.Geometries[ geoInstanceId ].Clone( geoInstance.name ); meshInfo.GeoInstances.Add( geoInstance ); } } }
private static void ConvertFile( string srcDir, string dstDir, string name, Matrix4 transform, bool build_tangents, bool extract_collision_volumes, bool optimize_mesh, string skeleton_file ) { if( String.IsNullOrEmpty( name ) ) { // TODO: It would be better to catch this while parsing command args, but // that's a bit too hairy for now. This will at least inform the user. throw new ArgumentException( "No file named for conversion" ); } string dir = string.Empty; string path = string.Empty; SplitPath( ref dir, ref path, name ); if( srcDir == string.Empty ) srcDir = dir; if( dstDir == string.Empty ) dstDir = dir; name = path; // get the resource data from MeshManager string extension = Path.GetExtension( name ).ToLower(); string baseFile = Path.GetFileNameWithoutExtension( name ); if( baseFile.EndsWith( ".mesh" ) ) baseFile = baseFile.Substring( 0, baseFile.Length - 5 ); string baseSkeletonName = null; if( skeleton_file != null ) baseSkeletonName = Path.GetFileName( skeleton_file ); // mesh loading stats int before, after; // get the tick count before loading the mesh before = Environment.TickCount; string materialScript = null; Mesh mesh = ReadMesh( ref materialScript, transform, srcDir, dstDir, name ); if( optimize_mesh ) mesh = MeshUtility.CopyMesh( mesh ); // get the tick count after loading the mesh after = Environment.TickCount; // record the time elapsed while loading the mesh log.InfoFormat( "Mesh: Loaded '{0}', took {1}ms", mesh.Name, (after - before) ); // Build tangent vectors if( build_tangents ) { log.Info( "Building tangent vectors from uv map" ); MeshHelper.BuildTangentVectors( mesh ); } if( extract_collision_volumes ) { log.InfoFormat( "Extracting collision volumes from '{0}'", mesh.Name ); CVExtractor.ExtractCollisionShapes( mesh, dstDir + baseFile ); } //// prepare the mesh for a shadow volume? //if (MeshManager.Instance.PrepareAllMeshesForShadowVolumes) { // if (edgeListsBuilt || autoBuildEdgeLists) { // PrepareForShadowVolume(); // } // if (!edgeListsBuilt && autoBuildEdgeLists) { // BuildEdgeList(); // } //} // Allow them to override the skeleton reference of the mesh if( baseSkeletonName != null ) mesh.SkeletonName = baseSkeletonName; string meshFile = baseFile + ".mesh"; MeshSerializer meshWriter = new MeshSerializer(); meshWriter.ExportMesh( mesh, dstDir + meshFile ); // If it was a .dae file, we will need to export the material and skeleton as well if( extension != ".dae" && extension != ".kmz" ) return; if( materialScript != null ) { string materialFile = baseFile + ".material"; Stream materialData = new FileStream( dstDir + materialFile, FileMode.Create ); StreamWriter materialWriter = new StreamWriter( materialData ); materialWriter.Write( materialScript ); materialWriter.Close(); } if( mesh.Skeleton == null ) return; #if USE_XML string skelFile = baseFile + ".skeleton.xml"; Stream skelData = new FileStream(dstDir + skelFile, FileMode.Create); OgreXmlSkeletonWriter skelWriter = new OgreXmlSkeletonWriter(skelData); skelWriter.Export(mesh.Skeleton); skelData.Close(); #else // DEBUG foreach( AttachmentPoint socket in mesh.Skeleton.AttachmentPoints ) { log.InfoFormat( "Created attachment point with parent {0}", socket.ParentBone ); log.InfoFormat( " Relative Position: {0}", socket.Position ); log.InfoFormat( " Relative Up: {0}", socket.Orientation * Vector3.UnitZ ); Bone bone = mesh.Skeleton.GetBone( socket.ParentBone ); Vector3 derivedPos = bone.DerivedPosition + socket.Position; Vector3 derivedUp = socket.Orientation * bone.DerivedOrientation * Vector3.UnitZ; log.InfoFormat( " Absolute Position: {0}", derivedPos ); log.InfoFormat( " Absolute Up: {0}", derivedUp ); } string skelFile = baseFile + ".skeleton"; OgreSkeletonSerializer skelWriter = new OgreSkeletonSerializer(); skelWriter.ExportSkeleton( mesh.Skeleton, dstDir + skelFile ); #endif }
private static Mesh ReadMesh(Matrix4 transform, string srcDir, string meshFile) { Stream meshData = new FileStream(srcDir + meshFile, FileMode.Open); Mesh mesh = new Mesh(meshFile); if (meshFile.EndsWith(".mesh", StringComparison.CurrentCultureIgnoreCase)) { MeshSerializer meshReader = new MeshSerializer(); meshReader.ImportMesh(meshData, mesh); } else if (meshFile.EndsWith(".mesh.xml", StringComparison.CurrentCultureIgnoreCase)) { OgreXmlMeshReader meshReader = new OgreXmlMeshReader(meshData); meshReader.Import(mesh); } else if (meshFile.EndsWith(".dae", StringComparison.CurrentCultureIgnoreCase)) { string extension = Path.GetExtension(meshFile); string baseFile = Path.GetFileNameWithoutExtension(meshFile); string basename = meshFile.Substring(0, meshFile.Length - extension.Length); ColladaMeshReader meshReader = new ColladaMeshReader(meshData, baseFile); // import the .dae file meshReader.Import(transform, mesh, null, "idle", basename); // materialScript = meshReader.MaterialScript; } else { meshData.Close(); string extension = Path.GetExtension(meshFile); throw new AxiomException("Unsupported mesh format '{0}'", extension); } meshData.Close(); return mesh; }
/// <summary> /// Import into the mesh, using the skeleton provided, and /// assigning the animation data to a new animation. /// </summary> /// <param name="transform">the world transform to apply to this object</param> /// <param name="mesh">the mesh we will populate</param> /// <param name="skeleton">the skeleton to which we will add animations (or null if we are creating one)</param> /// <param name="animationName">the name that will be used for the animation</param> /// <param name="materialNamespace">namespace used for generation of material names</param> public void Import( Matrix4 transform, Mesh mesh, Skeleton skeleton, string animationName, string materialNamespace ) { ColladaMeshReader reader = null; XmlDocument document = new XmlDocument(); document.Load( m_Stream ); XmlElement rootElement = document.DocumentElement; // This is slightly weird. The client calls this method on this object, // but then we determine which version of collada we're actually looking // at, and create a new instances of a derived collada reader. As an // outcome, we have to copy fields from the factory-created instance // back to this instance. // TODO: Need a static factory method on the base class to create the // collada reader instance, then call that instance from the client; // that way we'll only have one instance in the first place. reader = GetColladaParser( rootElement ); reader.m_ColladaRootNode = rootElement; reader.m_Document = document; reader.m_MaterialBuilder = new MaterialScriptBuilder( materialNamespace ); ColladaMeshInfo meshInfo = new ColladaMeshInfo( mesh ); reader.ReadCollada( rootElement, meshInfo ); meshInfo.NoRiggingCulling = NoRiggingCulling; meshInfo.Process( transform, skeleton, m_BaseFile, animationName ); this.m_MaterialBuilder = reader.MaterialBuilder; }
public static Quaternion GetRotation(Matrix4 transform) { Matrix3 tmp = new Matrix3(transform.m00, transform.m01, transform.m02, transform.m10, transform.m11, transform.m12, transform.m20, transform.m21, transform.m22); float scale = (float)Math.Pow(tmp.Determinant, 1 / 3.0f); tmp = tmp * scale; Quaternion rv = Quaternion.Identity; rv.FromRotationMatrix(tmp); return rv; }
protected void TransformSkeleton(Matrix4 unscaledTransform, float scale) { Matrix4 invExportTransform = unscaledTransform.Inverse(); Dictionary<string, Matrix4> fullInverseBoneTransforms = new Dictionary<string, Matrix4>(); Skeleton newSkeleton = new Skeleton(skeleton.Name); // Construct new versions of the bones, and build // the inverse bind matrix that will be needed. for (ushort i = 0; i < skeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); Bone newBone = newSkeleton.CreateBone(bone.Name, bone.Handle); fullInverseBoneTransforms[bone.Name] = bone.BindDerivedInverseTransform * invExportTransform; } // Build the parenting relationship for the new skeleton for (ushort i = 0; i < skeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); Bone newBone = newSkeleton.GetBone(i); Bone parentBone = (Bone)bone.Parent; if (parentBone != null) { Bone newParentBone = newSkeleton.GetBone(parentBone.Handle); newParentBone.AddChild(newBone); } } // Set the orientation and position for the various bones for (ushort i = 0; i < newSkeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); string boneName = bone.Name; string parentName = (bone.Parent == null) ? null : bone.Parent.Name; Matrix4 transform = GetLocalBindMatrix(fullInverseBoneTransforms, boneName, parentName, true); Quaternion orientation = GetRotation(transform); Bone newBone = newSkeleton.GetBone(i); newBone.Orientation = orientation; // newBone.Scale = transform.Scale; newBone.Position = scale * transform.Translation; } newSkeleton.SetBindingPose(); for (int i = 0; i < skeleton.AnimationCount; ++i) { Animation anim = skeleton.GetAnimation(i); Animation newAnim = newSkeleton.CreateAnimation(anim.Name, anim.Length); TransformAnimation(unscaledTransform, scale, newAnim, anim, newSkeleton); } skeleton = newSkeleton; }
protected void TransformTrack(Matrix4 exportTransform, NodeAnimationTrack newTrack, NodeAnimationTrack track, Bone bone) { Matrix4 invExportTransform = exportTransform.Inverse(); Bone oldNode = (Bone)track.TargetNode; Bone newNode = (Bone)newTrack.TargetNode; for (int i = 0; i < track.KeyFrames.Count; ++i) { TransformKeyFrame keyFrame = track.GetTransformKeyFrame(i); TransformKeyFrame newKeyFrame = newTrack.CreateNodeKeyFrame(keyFrame.Time); Quaternion oldOrientation = oldNode.Orientation * keyFrame.Rotation; Vector3 oldTranslation = oldNode.Position + keyFrame.Translate; Matrix4 oldTransform = Multiverse.MathLib.MathUtil.GetTransform(oldOrientation, oldTranslation); Matrix4 newTransform = exportTransform * oldTransform * invExportTransform; Quaternion newOrientation = GetRotation(newTransform); Vector3 newTranslation = newTransform.Translation; newKeyFrame.Rotation = newNode.Orientation.Inverse() * newOrientation; newKeyFrame.Translate = newTranslation - newNode.Position; //if (oldNode.Name == "Lower_Torso_BIND_jjj") { // log.DebugFormat("New translation: {0}; New Position: {1}", newTranslation, newNode.Position); //} } }
public void Export(Skeleton skeleton, Matrix4 exportTransform) { this.exportTransform = exportTransform; float det = exportTransform.Determinant; this.exportScale = (float)Math.Pow(det, 1 / 3.0f); Export(skeleton); }
public void AddModelPathObject(bool logPathGeneration, PathObjectType type, string modelName, Vector3 modelPosition, Matrix4 modelTransform, List<CollisionShape> shapes, float terrainHeight) { PathGenerator pathGenerator = new PathGenerator(logPathGeneration, modelName, type, terrainHeight, modelTransform, shapes); // Perform traversal and creation of polygons, arcs // between polygons, and portals to the terrain pathGenerator.GeneratePolygonsArcsAndPortals(); List<PathPolygon> polygons = new List<PathPolygon>(); List<PathArc> portals = new List<PathArc>(); List<PathArc> arcs = new List<PathArc>(); foreach(GridPolygon r in pathGenerator.CVPolygons) polygons.Add(new PathPolygon(r.Index, PolygonKind.CV, r.CornerLocs)); foreach(GridPolygon r in pathGenerator.TerrainPolygons) polygons.Add(new PathPolygon(r.Index, PolygonKind.Terrain, r.CornerLocs)); foreach(PolygonArc portal in pathGenerator.TerrainPortals) portals.Add(new PathArc(portal.Kind, portal.Poly1Index, portal.Poly2Index, MakePathEdge(portal.Edge))); foreach(PolygonArc arc in pathGenerator.PolygonArcs) arcs.Add(new PathArc(arc.Kind, arc.Poly1Index, arc.Poly2Index, MakePathEdge(arc.Edge))); pathObjects.Add(new PathObject(pathGenerator.ModelName, type.name, pathGenerator.FirstTerrainIndex, new PathPolygon(0, PolygonKind.Bounding, pathGenerator.ModelCorners), polygons, portals, arcs)); }
/// <summary> /// /// </summary> /// <param name="matrix"></param> public void Transform(Matrix4 matrix) { // do nothing for a null box if(isNull) return; Vector3 min = new Vector3(); Vector3 max = new Vector3(); Vector3 temp = new Vector3(); bool isFirst = true; int i; for( i = 0; i < corners.Length; i++ ) { // Transform and check extents temp = matrix * corners[i]; if( isFirst || temp.x > max.x ) max.x = temp.x; if( isFirst || temp.y > max.y ) max.y = temp.y; if( isFirst || temp.z > max.z ) max.z = temp.z; if( isFirst || temp.x < min.x ) min.x = temp.x; if( isFirst || temp.y < min.y ) min.y = temp.y; if( isFirst || temp.z < min.z ) min.z = temp.z; isFirst = false; } SetExtents(min, max); }
/// <summary> /// /// </summary> /// <param name="matrices"></param> public void GetWorldTransforms(Matrix4[] matrices) { if(parent.numBoneMatrices == 0 || !parent.IsHardwareAnimationEnabled) { matrices[0] = parent.ParentFullTransform; } else { // Hardware skinning, pass all actually used matrices List<ushort> indexMap = subMesh.useSharedVertices ? subMesh.Parent.SharedBlendIndexToBoneIndexMap : subMesh.BlendIndexToBoneIndexMap; Debug.Assert(indexMap.Count <= this.Parent.numBoneMatrices); if (parent.IsSkeletonAnimated) { // Bones, use cached matrices built when Entity::UpdateRenderQueue was called Debug.Assert(parent.boneMatrices != null); for (int i = 0; i < indexMap.Count; i++) { matrices[i] = parent.boneMatrices[indexMap[i]]; } } else { // All animations disabled, use parent entity world transform only for (int i = 0; i < indexMap.Count; i++) { matrices[i] = parent.ParentFullTransform; } } } }
public void ProcessArgs( string[] args ) { for( int i = 0; i < args.Length; ++i ) { switch( args[ i ] ) { case "--transform": for( int j = 0; j < 16; ++j ) if( i + 1 < args.Length ) transform[ j ] = float.Parse( args[ ++i ] ); else Console.WriteLine( "Invalid transform" ); break; case "--build_skeleton": build_skeleton = true; break; case "--base_skeleton": // This is overloaded. It is used for adding multiple animations // into a single skeleton, but it is also used to specify the name // of the skeleton that will be referenced by the mesh file. skeleton_file = args[ ++i ]; break; case "--build_tangents": build_tangents = true; break; case "--out_skeleton": out_skeleton_file = args[ ++i ]; break; case "--optimize_mesh": case "--optimise_mesh": optimize_mesh = true; break; case "--animation": { AnimationEntry entry = new AnimationEntry(); entry.animation_name = args[ ++i ]; entry.animation_file = args[ ++i ]; animations.Add( entry ); break; } case "--manual_lod": { LodEntry entry = new LodEntry(); entry.distance = float.Parse( args[ ++i ] ); entry.meshFile = args[ ++i ]; manualLodEntries.Add( entry ); break; } case "--socket": { Matrix4 attachTransform = Matrix4.Identity; string name = args[ ++i ]; string parentBone = args[ ++i ]; for( int j = 0; j < 16; ++j ) if( i + 1 < args.Length ) attachTransform[ j ] = float.Parse( args[ ++i ] ); else Console.WriteLine( "Invalid transform" ); AttachmentPointNode ap = new AttachmentPointNode( name, parentBone, attachTransform ); attachPoints.Add( ap ); break; } case "--test_physics": { test_physics = true; return; } // LOD options case "--lod_levels": { lodlevels = int.Parse( args[ ++i ] ); break; } case "--lod_distance": { loddist = float.Parse( args[ ++i ] ); break; } case "--lod_percent": { lodpercent = float.Parse( args[ ++i ] ); break; } case "--lod_num_triangles": { // lodnumtris break; } #if NOT_USED case "--merge_animations": { // Deprecated string destFile = args[++i]; string rigFile = args[++i]; List<string> animFiles = new List<string>(); while (i + 1 < args.Length) animFiles.Add(args[++i]); MergeAnimations(srcDir, dstDir, destFile, rigFile, animFiles); return; } case "--merge_collada": { // Deprecated string destFile = args[++i]; string rigFile = args[++i]; string animFile = args[++i]; MergeColladaFiles(srcDir, dstDir, destFile, rigFile, animFile); return; } #endif case "--3ds": { // Convert from a right handed system where z is up to a right handed system where y is up. Matrix4 yupTrans = new Matrix4( 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 ); transform = transform * yupTrans; break; } case "--src_dir": srcDir = MaybeAddTrailingBackslash( args[ ++i ] ); break; case "--dst_dir": dstDir = MaybeAddTrailingBackslash( args[ ++i ] ); break; #if NOT_USED case "--test_sockets": TestSockets(); break; #endif case "--dont_extract_collision_volumes": extract_collision_volumes = false; break; case "--log_collision_volumes": CVExtractor.InitLog( true ); break; case "--args_file": ProcessArgumentFile( args[ ++i ] ); break; case "--log_file": log_file = args[ ++i ]; break; case "--throw": rethrow = true; break; case "--version": Console.WriteLine( string.Format( "ConversionTool version: {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() ) ); break; case "--no_rigging_culling": ColladaMeshReader.NoRiggingCulling = true; break; case "--": case "--usage": case "--help": Convert.Usage(); abort = true; break; default: last_arg = args[ i ]; break; } if( abort ) break; } }
/// <summary> /// Utility method to merge animations from other files into a single skeleton /// </summary> /// <param name="srcDir">the directory from which the new animations will be loaded</param> /// <param name="dstDir">the directory to which the modified skeleton will be saved</param> /// <param name="skelFile">the name of the file to which the modified skeleton will be written</param> /// <param name="transform">the transform to apply to the skeleton and animations</param> /// <param name="skeleton">the original skeleton</param> /// <param name="animations">the list of animations</param> private static void AddAnimations( string srcDir, string dstDir, string skelFile, Matrix4 transform, Skeleton skeleton, List<AnimationEntry> animations ) { // mesh loading stats int before, after; // get the tick count before loading the mesh before = Environment.TickCount; foreach( AnimationEntry entry in animations ) { Mesh mesh = new Mesh( "Mesh" ); Stream data = new FileStream( srcDir + entry.animation_file, FileMode.Open ); ColladaMeshReader meshReader = new ColladaMeshReader( data, null ); // import the .dae file meshReader.Import( transform, mesh, skeleton, entry.animation_name, null ); // close the stream (we don't need to leave it open here) data.Close(); } // get the tick count after loading the mesh after = Environment.TickCount; // record the time elapsed while loading the mesh log.InfoFormat( "Mesh: took {0}ms", (after - before) ); //// prepare the mesh for a shadow volume? //if (MeshManager.Instance.PrepareAllMeshesForShadowVolumes) { // if (edgeListsBuilt || autoBuildEdgeLists) { // PrepareForShadowVolume(); // } // if (!edgeListsBuilt && autoBuildEdgeLists) { // BuildEdgeList(); // } //} OgreSkeletonSerializer skelWriter = new OgreSkeletonSerializer(); skelWriter.ExportSkeleton( skeleton, dstDir + skelFile ); }
private static Skeleton ReadSkeleton( Matrix4 transform, string srcDir, string skelFile ) { Stream skelData = new FileStream( srcDir + skelFile, FileMode.Open ); Skeleton skeleton = new Skeleton( skelFile ); if( skelFile.EndsWith( ".skeleton" ) ) { OgreSkeletonSerializer skelReader = new OgreSkeletonSerializer(); skelReader.ImportSkeleton( skelData, skeleton ); } else if( skelFile.EndsWith( ".skeleton.xml" ) ) { OgreXmlSkeletonReader skelReader = new OgreXmlSkeletonReader( skelData ); skelReader.Import( skeleton ); } else { skelData.Close(); string extension = Path.GetExtension( skelFile ); throw new AxiomException( "Unsupported skeleton format '{0}'", extension ); } skelData.Close(); return skeleton; }
// mesh will be null if this fails static void ImportKMZFile( ref string materialScript, Matrix4 transform, string dstDir, string meshFile, FileStream kmzStream, Mesh mesh ) { string daeFile = ExtractKMZComponentFiles( dstDir, kmzStream ); if( ! String.IsNullOrEmpty( daeFile ) ) { string materialNamespace = Path.GetFileNameWithoutExtension( daeFile ); string animationNamespace = materialNamespace; FileStream daeStream = new FileStream( daeFile, FileMode.Open ); ColladaMeshReader meshReader = new ColladaMeshReader( daeStream, animationNamespace ); // Convert from a left handed system where z is up to a right handed system where y is up. Matrix4 yupTrans = new Matrix4( 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 ); Matrix4 yupTransform = transform * yupTrans; // import the .dae file meshReader.Import( yupTransform, mesh, null, "base", materialNamespace ); materialScript = meshReader.MaterialScript; } }
public static float GetScale(Matrix4 transform) { Matrix3 tmp = new Matrix3(transform.m00, transform.m01, transform.m02, transform.m10, transform.m11, transform.m12, transform.m20, transform.m21, transform.m22); return (float)Math.Pow(tmp.Determinant, 1 / 3.0f); }
public static Matrix4 ScaleMatrix(Matrix4 transform, float scale) { Matrix4 rv = transform; for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { rv[row, col] *= scale; } } return rv; }
/// <summary> /// Interpolates a single segment of the spline given a parametric value. /// </summary> /// <param name="index">The point index to treat as t=0. index + 1 is deemed to be t=1</param> /// <param name="t">Parametric value</param> /// <returns>An interpolated point along the spline.</returns> public Vector3 Interpolate(int index, float t) { Debug.Assert(index >= 0 && index < pointList.Count, "Spline point index overrun."); if((index + 1) == pointList.Count) { // cant interpolate past the end of the list, just return the last point return pointList[index]; } // quick special cases if(t == 0.0f) return pointList[index]; else if(t == 1.0f) return pointList[index + 1]; // Time for real interpolation // Construct a Vector4 of powers of 2 float t2, t3; // t^2 t2 = t * t; // t^3 t3 = t2 * t; Vector4 powers = new Vector4(t3, t2, t, 1); // Algorithm is result = powers * hermitePoly * Matrix4(point1, point2, tangent1, tangent2) Vector3 point1 = pointList[index]; Vector3 point2 = pointList[index + 1]; Vector3 tangent1 = tangentList[index]; Vector3 tangent2 = tangentList[index + 1]; Matrix4 point = new Matrix4(); // create the matrix 4 with the 2 point and tangent values point.m00 = point1.x; point.m01 = point1.y; point.m02 = point1.z; point.m03 = 1.0f; point.m10 = point2.x; point.m11 = point2.y; point.m12 = point2.z; point.m13 = 1.0f; point.m20 = tangent1.x; point.m21 = tangent1.y; point.m22 = tangent1.z; point.m23 = 1.0f; point.m30 = tangent2.x; point.m31 = tangent2.y; point.m32 = tangent2.z; point.m33 = 1.0f; // get the final result in a Vector4 Vector4 result = powers * hermitePoly * point; // return the final result return new Vector3(result.x, result.y, result.z); }
protected void TransformAnimation(Matrix4 exportTransform, Animation newAnim, Animation anim, Skeleton newSkeleton) { foreach (NodeAnimationTrack track in anim.NodeTracks.Values) { NodeAnimationTrack newTrack = newAnim.CreateNodeTrack(track.Handle); Bone targetBone = (Bone)track.TargetNode; newTrack.TargetNode = newSkeleton.GetBone(targetBone.Handle); TransformTrack(exportTransform, newTrack, track, targetBone); } }
/// <summary> /// Used to transform the overlay when scrolling, scaling etc. /// </summary> /// <param name="xform">Array of Matrix4s to populate with the world /// transforms of this overlay. /// </param> public void GetWorldTransforms(Matrix4[] xform) { if(isTransformOutOfDate) { UpdateTransforms(); } xform[0] = transform; }
protected void TransformAnimation(Matrix4 unscaledTransform, float scale, Animation newAnim, Animation anim, Skeleton newSkeleton) { // With the new idea I had for transforming these, I need the tracks // set up for the parent bones before I can handle the child bones. for (int i = 0; i < anim.Tracks.Count; ++i) { AnimationTrack track = anim.Tracks[i]; AnimationTrack newTrack = newAnim.CreateTrack(track.Handle); Bone targetBone = (Bone)track.TargetNode; newTrack.TargetNode = newSkeleton.GetBone(targetBone.Handle); } // This gets the ordered bone list, and transforms the tracks in // that order instead. List<Bone> orderedBoneList = GetOrderedBoneList(null, newSkeleton); foreach (Bone bone in orderedBoneList) TransformTrack(unscaledTransform, scale, newAnim, anim, bone); }
/// <summary> /// Internal lazy update method. /// </summary> protected void UpdateTransforms() { // Ordering: // 1. Scale // 2. Rotate // 3. Translate Matrix3 rot3x3 = Matrix3.Identity; Matrix3 scale3x3 = Matrix3.Zero; rot3x3.FromEulerAnglesXYZ(0, 0, MathUtil.DegreesToRadians(rotate)); scale3x3.m00 = scaleX; scale3x3.m11 = scaleY; scale3x3.m22 = 1.0f; transform = Matrix4.Identity; transform = rot3x3 * scale3x3; transform.Translation = new Vector3(scrollX, scrollY, 0); isTransformOutOfDate = false; }
protected void TransformTrack(Matrix4 unscaledTransform, float scale, Animation newAnim, Animation anim, Bone bone) { AnimationTrack track = GetBoneTrack(anim, bone.Handle); AnimationTrack newTrack = GetBoneTrack(newAnim, bone.Handle); Bone oldNode = (Bone)track.TargetNode; Bone newNode = (Bone)newTrack.TargetNode; Quaternion exportRotation = GetRotation(unscaledTransform); Vector3 exportTranslation = unscaledTransform.Translation; for (int i = 0; i < track.KeyFrames.Count; ++i) { KeyFrame keyFrame = track.KeyFrames[i]; Quaternion oldOrientation = Quaternion.Identity; Vector3 oldTranslation = Vector3.Zero; // Now build the composite transform for the old node GetCompositeTransform(ref oldOrientation, ref oldTranslation, oldNode, anim, i); Quaternion targetOrientation = exportRotation * oldOrientation; Vector3 targetTranslation = exportTranslation + scale * (exportRotation * oldTranslation); KeyFrame newKeyFrame = newTrack.CreateKeyFrame(keyFrame.Time); // we have a parent - where is it? Quaternion parentOrientation = Quaternion.Identity; Vector3 parentTranslation = Vector3.Zero; GetCompositeTransform(ref parentOrientation, ref parentTranslation, (Bone)newNode.Parent, newAnim, i); newKeyFrame.Rotation = newNode.Orientation.Inverse() * parentOrientation.Inverse() * targetOrientation; newKeyFrame.Translate = (-1 * newNode.Position) + (-1 * parentTranslation) + targetTranslation; } }
/// <summary> /// /// </summary> /// <param name="vector"></param> /// <param name="matrix"></param> /// <returns></returns> public static Vector4 Multiply(Vector4 vector, Matrix4 matrix) { return vector * matrix; }
public void GetWorldTransforms( Matrix4[] xform ) { parentNode.GetWorldTransforms(xform); }
/// <summary> /// /// </summary> /// <param name="matrices"></param> public void GetWorldTransforms(Matrix4[] matrices) { matrices[0] = parent.ParentFullTransform; }
/// <summary> /// Gets the world transform matrix / matrices for this renderable object. /// </summary> /// <remarks> /// If the object has any derived transforms, these are expected to be up to date as long as /// all the SceneNode structures have been updated before this is called. /// <p/> /// This method will populate xform with 1 matrix if it does not use vertex blending. If it /// does use vertex blending it will fill the passed in pointer with an array of matrices, /// the length being the value returned from getNumWorldTransforms. /// </remarks> public void GetWorldTransforms(Matrix4[] matrices) { }
private static void GenerateCurvedIllusionPlaneVertexData(HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float cameraPosition, float sphereRadius, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength) { Vector3 vec; Vector3 norm; float sphereDistance; unsafe { // lock the vertex buffer IntPtr data = vertexBuffer.Lock(BufferLocking.Discard); float* pData = (float*)data.ToPointer(); for (int y = 0; y < ySegments + 1; ++y) { for (int x = 0; x < xSegments + 1; ++x) { // centered on origin vec.x = (x * xSpace) - halfWidth; vec.y = (y * ySpace) - halfHeight; vec.z = 0.0f; // transform by orientation and distance vec = xform * vec; // assign to geometry *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // build bounds as we go if (firstTime) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor(vec); max.Ceil(vec); maxSquaredLength = MathUtil.Max(maxSquaredLength, vec.LengthSquared); } if (normals) { norm = Vector3.UnitZ; norm = orientation * norm; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } // generate texture coordinates, normalize position, modify by orientation to return +y up vec = orientation.Inverse() * vec; vec.Normalize(); // find distance to sphere sphereDistance = MathUtil.Sqrt(cameraPosition * cameraPosition * (vec.y * vec.y - 1.0f) + sphereRadius * sphereRadius) - cameraPosition * vec.y; vec.x *= sphereDistance; vec.z *= sphereDistance; // use x and y on sphere as texture coordinates, tiled float s = vec.x * (0.01f * uTiles); float t = vec.z * (0.01f * vTiles); for (int i = 0; i < numberOfTexCoordSets; i++) { *pData++ = s; *pData++ = (1 - t); } } // x } // y // unlock the buffer vertexBuffer.Unlock(); } // unsafe }
public static Quaternion GetRotation(Matrix4 transform) { Matrix3 tmp = new Matrix3(transform.m00, transform.m01, transform.m02, transform.m10, transform.m11, transform.m12, transform.m20, transform.m21, transform.m22); float det = tmp.Determinant; float scale = (float)(1 / Math.Pow(det, 1.0 / 3.0)); tmp = tmp * scale; Quaternion rv = Quaternion.Identity; rv.FromRotationMatrix(tmp); Debug.Assert(Math.Abs(1.0 - rv.Norm) < .001f, "Possible non-uniform scale factor on rotation matrix"); // rv.Normalize(); return rv; }
private static void GeneratePlaneVertexData(HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength) { Vector3 vec; unsafe { // lock the vertex buffer IntPtr data = vbuf.Lock(BufferLocking.Discard); float* pData = (float*)data.ToPointer(); for (int y = 0; y <= ySegments; y++) { for (int x = 0; x <= xSegments; x++) { // centered on origin vec.x = (x * xSpace) - halfWidth; vec.y = (y * ySpace) - halfHeight; vec.z = 0.0f; vec = transform * vec; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // Build bounds as we go if (firstTime) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor(vec); max.Ceil(vec); maxSquaredLength = MathUtil.Max(maxSquaredLength, vec.LengthSquared); } if (normals) { vec = Vector3.UnitZ; vec = rotation * vec; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } for (int i = 0; i < numTexCoordSets; i++) { *pData++ = x * xTexCoord; *pData++ = 1 - (y * yTexCoord); } // for texCoords } // for x } // for y // unlock the buffer vbuf.Unlock(); subMesh.useSharedVertices = true; } // unsafe }