public static void Update(ModelViewHierarchyUpdater hierarchy, RenderModel renderModel, int slot) { var boneMatrices = staticBoneMatrices; var meshes = renderModel.RenderMeshesList[slot]; { if (meshes == null) { return; } foreach (var renderMesh in meshes) { var mesh = renderMesh.Mesh; var skinning = mesh.Skinning; if (skinning == null) { // For unskinned meshes, use the original bounding box var boundingBoxExt = (BoundingBoxExt)mesh.BoundingBox; boundingBoxExt.Transform(renderMesh.WorldMatrix); renderMesh.BoundingBox = boundingBoxExt; continue; } var bones = skinning.Bones; // Make sure there is enough spaces in boneMatrices if (boneMatrices == null || bones.Length > boneMatrices.Length) { staticBoneMatrices = boneMatrices = new Matrix[bones.Length]; } var bindPoseBoundingBox = new BoundingBoxExt(renderMesh.Mesh.BoundingBox); renderMesh.BoundingBox = BoundingBoxExt.Empty; for (int index = 0; index < bones.Length; index++) { var nodeIndex = bones[index].NodeIndex; // Compute bone matrix Matrix.Multiply(ref bones[index].LinkToMeshMatrix, ref hierarchy.NodeTransformations[nodeIndex].WorldMatrix, out boneMatrices[index]); // Calculate and extend bounding box for each bone // TODO: Move runtime bounding box into ModelViewHierarchyUpdater? // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) var boundingBoxExt = bindPoseBoundingBox; boundingBoxExt.Transform(boneMatrices[index]); BoundingBoxExt.Merge(ref renderMesh.BoundingBox, ref boundingBoxExt, out renderMesh.BoundingBox); } // Upload bones renderMesh.Parameters.Set(TransformationSkinningKeys.BlendMatrixArray, boneMatrices, 0, bones.Length); } } }
public static void Update(ModelViewHierarchyUpdater hierarchy, RenderModel renderModel, int slot) { var boneMatrices = staticBoneMatrices; var meshes = renderModel.RenderMeshesList[slot]; { if (meshes == null) { return; } foreach (var renderMesh in meshes) { var mesh = renderMesh.Mesh; var skinning = mesh.Skinning; if (skinning == null) { // For unskinned meshes, use the original bounding box var boundingBoxExt = (BoundingBoxExt)mesh.BoundingBox; boundingBoxExt.Transform(renderMesh.WorldMatrix); renderMesh.BoundingBox = boundingBoxExt; continue; } var bones = skinning.Bones; // Make sure there is enough spaces in boneMatrices if (boneMatrices == null || bones.Length > boneMatrices.Length) staticBoneMatrices = boneMatrices = new Matrix[bones.Length]; var bindPoseBoundingBox = new BoundingBoxExt(renderMesh.Mesh.BoundingBox); renderMesh.BoundingBox = BoundingBoxExt.Empty; for (int index = 0; index < bones.Length; index++) { var nodeIndex = bones[index].NodeIndex; // Compute bone matrix Matrix.Multiply(ref bones[index].LinkToMeshMatrix, ref hierarchy.NodeTransformations[nodeIndex].WorldMatrix, out boneMatrices[index]); // Calculate and extend bounding box for each bone // TODO: Move runtime bounding box into ModelViewHierarchyUpdater? // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) var boundingBoxExt = bindPoseBoundingBox; boundingBoxExt.Transform(boneMatrices[index]); BoundingBoxExt.Merge(ref renderMesh.BoundingBox, ref boundingBoxExt, out renderMesh.BoundingBox); } // Upload bones renderMesh.Parameters.Set(TransformationSkinningKeys.BlendMatrixArray, boneMatrices, 0, bones.Length); } } }
/// <inheritdoc/> public override void ComputeMatrix(bool recursive, out Matrix matrix) { // If model is not in the parent, we might want to force recursive update (since parentModelComponent might not be updated yet) if (forceRecursive || recursive) { parentModelComponent.Entity.Transform.UpdateWorldMatrix(); } // Updated? (rare slow path) if (parentModelComponent.ModelViewHierarchy != modelViewHierarchy) { modelViewHierarchy = parentModelComponent.ModelViewHierarchy; if (modelViewHierarchy == null) { goto failed; } // Find our node index nodeIndex = int.MaxValue; for (int index = 0; index < modelViewHierarchy.Nodes.Length; index++) { var node = modelViewHierarchy.Nodes[index]; if (node.Name == nodeName) { nodeIndex = index; } } } var nodes = modelViewHierarchy.Nodes; var nodeTransformations = modelViewHierarchy.NodeTransformations; if (nodeIndex >= nodes.Length) { goto failed; } // Hopefully, if ref locals gets merged in roslyn, this code can be refactored // Compute matrix = nodeTransformations[nodeIndex].WorldMatrix; return; failed: // Fallback to TransformComponent matrix = parentModelComponent.Entity.Transform.WorldMatrix; return; }
public unsafe void Update(ModelViewHierarchyUpdater hierarchy, AnimationClipResult result) { // Check if we need to regenerate "update channels" (i.e. how to copy data from result to hierarchy) if (updateChannels == null || // First time?... currentSourceChannels != result.Channels || // ... or changed? currentSourceChannels.Count != currentSourceChannelCount) // .. or modified? (could only append channel) { RegenerateUpdateChannels(hierarchy, result.Channels); currentSourceChannels = result.Channels; currentSourceChannelCount = currentSourceChannels.Count; } // Copy results to node hierarchy fixed(byte *structures = result.Data) { foreach (var updateChannel in updateChannels) { var structureData = (float *)(structures + updateChannel.Offset); var factor = *structureData++; if (factor == 0.0f) { continue; } switch (updateChannel.Type) { case ChannelType.Translation: Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Translation); break; case ChannelType.Rotation: Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Rotation); break; case ChannelType.Scaling: Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Scaling); break; default: throw new ArgumentOutOfRangeException(); } } } }
private void RegenerateUpdateChannels(ModelViewHierarchyUpdater hierarchy, List <AnimationBlender.Channel> channels) { var newUpdateChannels = new List <UpdateChannel>(); // TODO: Temporary implementation due to lack of time before first release. foreach (var channel in channels) { string nodeName = channel.NodeName; if (nodeName == null) { continue; } var updateChannel = new UpdateChannel(); updateChannel.Index = -1; var hierarchyNodes = hierarchy.Nodes; for (int i = 0; i < hierarchyNodes.Length; ++i) { var node = hierarchyNodes[i]; if (node.Name == nodeName) { updateChannel.Index = i; break; } } if (updateChannel.Index == -1) { // TODO: Warning? //throw new InvalidOperationException(string.Format("Could not find matching node in animation for {0}", nodeName)); continue; } updateChannel.Offset = channel.Offset; updateChannel.Type = channel.Type; newUpdateChannels.Add(updateChannel); } updateChannels = newUpdateChannels.ToArray(); }
public static void Update(ModelViewHierarchyUpdater hierarchy, RenderModel renderModel, int slot) { var boneMatrices = staticBoneMatrices; var meshes = renderModel.RenderMeshesList[slot]; { if (meshes == null) { return; } foreach (var renderMesh in meshes) { var mesh = renderMesh.Mesh; var skinning = mesh.Skinning; if (skinning == null) { continue; } var bones = skinning.Bones; // Make sure there is enough spaces in boneMatrices if (boneMatrices == null || bones.Length > boneMatrices.Length) { staticBoneMatrices = boneMatrices = new Matrix[bones.Length]; } for (int index = 0; index < bones.Length; index++) { var nodeIndex = bones[index].NodeIndex; // Compute bone matrix Matrix.Multiply(ref bones[index].LinkToMeshMatrix, ref hierarchy.NodeTransformations[nodeIndex].WorldMatrix, out boneMatrices[index]); } // Upload bones renderMesh.Parameters.Set(TransformationSkinningKeys.BlendMatrixArray, boneMatrices, 0, bones.Length); } } }
private void RegenerateUpdateChannels(ModelViewHierarchyUpdater hierarchy, List<AnimationBlender.Channel> channels) { var newUpdateChannels = new List<UpdateChannel>(); // TODO: Temporary implementation due to lack of time before first release. foreach (var channel in channels) { string nodeName = channel.NodeName; if (nodeName == null) continue; var updateChannel = new UpdateChannel(); updateChannel.Index = -1; var hierarchyNodes = hierarchy.Nodes; for (int i = 0; i < hierarchyNodes.Length; ++i) { var node = hierarchyNodes[i]; if (node.Name == nodeName) { updateChannel.Index = i; break; } } if (updateChannel.Index == -1) { // TODO: Warning? //throw new InvalidOperationException(string.Format("Could not find matching node in animation for {0}", nodeName)); continue; } updateChannel.Offset = channel.Offset; updateChannel.Type = channel.Type; newUpdateChannels.Add(updateChannel); } updateChannels = newUpdateChannels.ToArray(); }
public unsafe void Update(ModelViewHierarchyUpdater hierarchy, AnimationClipResult result) { // Check if we need to regenerate "update channels" (i.e. how to copy data from result to hierarchy) if (updateChannels == null // First time?... || currentSourceChannels != result.Channels // ... or changed? || currentSourceChannels.Count != currentSourceChannelCount) // .. or modified? (could only append channel) { RegenerateUpdateChannels(hierarchy, result.Channels); currentSourceChannels = result.Channels; currentSourceChannelCount = currentSourceChannels.Count; } // Copy results to node hierarchy fixed (byte* structures = result.Data) { foreach (var updateChannel in updateChannels) { var structureData = (float*)(structures + updateChannel.Offset); var factor = *structureData++; if (factor == 0.0f) continue; switch (updateChannel.Type) { case ChannelType.Translation: Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Translation); break; case ChannelType.Rotation: Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Rotation); break; case ChannelType.Scaling: Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Scaling); break; default: throw new ArgumentOutOfRangeException(); } } } }
public static void Update(ModelViewHierarchyUpdater hierarchy, RenderModel renderModel, int slot) { var boneMatrices = staticBoneMatrices; var meshes = renderModel.RenderMeshesList[slot]; { if (meshes == null) { return; } foreach (var renderMesh in meshes) { var mesh = renderMesh.Mesh; var skinning = mesh.Skinning; if (skinning == null) continue; var bones = skinning.Bones; // Make sure there is enough spaces in boneMatrices if (boneMatrices == null || bones.Length > boneMatrices.Length) staticBoneMatrices = boneMatrices = new Matrix[bones.Length]; for (int index = 0; index < bones.Length; index++) { var nodeIndex = bones[index].NodeIndex; // Compute bone matrix Matrix.Multiply(ref bones[index].LinkToMeshMatrix, ref hierarchy.NodeTransformations[nodeIndex].WorldMatrix, out boneMatrices[index]); } // Upload bones renderMesh.Parameters.Set(TransformationSkinningKeys.BlendMatrixArray, boneMatrices, 0, bones.Length); } } }
private void ModelUpdated() { if (model != null) { if (modelViewHierarchy != null) { // Reuse previous ModelViewHierarchy modelViewHierarchy.Initialize(model); } else { modelViewHierarchy = new ModelViewHierarchyUpdater(model); } } }