public SkeletonBone(SkeletonBone other) { Name = other.Name; Parent = other.Parent; Scale = other.Scale; Rotation = other.Rotation; Translation = other.Translation; BoundingSphereDiameter = other.BoundingSphereDiameter; BoundingBoxMin = other.BoundingBoxMin; BoundingBoxMax = other.BoundingBoxMax; }
public SkeletonBone() { Name = "Joint"; Parent = null; Scale = Vector3.One; Rotation = Quaternion.Identity; Translation = Vector3.Zero; BoundingSphereDiameter = 0f; BoundingBoxMin = Vector3.Zero; BoundingBoxMax = Vector3.Zero; }
private void DrawMesh(Mesh mesh, Camera camera, Matrix4 additionalMatrix) { if (mesh == null) { return; } Matrix4 viewMatrix = camera.ViewMatrix; Matrix4 projMatrix = camera.ProjectionMatrix; foreach (var batch in mesh.SubMeshes) { // Bind the shader if (batch.Material != null) { if (batch.Material.Shader != null) { batch.Material.Shader.Bind(); } } // ToDo: Get the model's position in the world from the entity it belongs to and create a model matrix from that. Matrix4 modelMatrix = additionalMatrix; // Before we draw it, we're going to do something incredibly stupid, and try to add bone support. Matrix4[] boneTransforms = new Matrix4[mesh.Skeleton.Count]; for (int i = 0; i < mesh.Skeleton.Count; i++) { SkeletonBone bone = mesh.Skeleton[i]; Matrix4 cumulativeTransform = Matrix4.Identity; while (bone != null) { cumulativeTransform = cumulativeTransform * Matrix4.CreateScale(bone.Scale) * Matrix4.CreateFromQuaternion(bone.Rotation) * Matrix4.CreateTranslation(bone.Translation); bone = bone.Parent; } boneTransforms[i] = cumulativeTransform; } // Each boneCopy is now in it's final position, so we can apply that to the vertexes based on their bone weighting. // However, vertex positions have already been uploaded once, so we're uh... going to hack it and re-upload them. Vector3[] origVerts = batch.Vertices; Vector3[] vertices = new Vector3[origVerts.Length]; Array.Copy(origVerts, vertices, origVerts.Length); for (int v = 0; v < vertices.Length; v++) { BoneWeight weights = batch.BoneWeights[v]; Matrix4 finalMatrix = Matrix4.Zero; for (int w = 0; w < weights.BoneIndexes.Length; w++) { Matrix4 boneInfluence = boneTransforms[weights.BoneIndexes[w]]; float weight = weights.BoneWeights[w]; finalMatrix = (boneInfluence * weight) + finalMatrix; } vertices[v] = Vector3.TransformPosition(vertices[v], finalMatrix); } // Now re-assign our Vertices to the mesh so they get uploaded to the GPU... batch.Vertices = vertices; // Bind the VAOs currently associated with this Mesh batch.Bind(); // Bind our Textures GL.ActiveTexture(TextureUnit.Texture0); if (batch.Material.Textures[0] != null) { batch.Material.Textures[0].Bind(); } // Upload uniforms to the GPU GL.UniformMatrix4(batch.Material.Shader.UniformModelMtx, false, ref modelMatrix); GL.UniformMatrix4(batch.Material.Shader.UniformViewMtx, false, ref viewMatrix); GL.UniformMatrix4(batch.Material.Shader.UniformProjMtx, false, ref projMatrix); // Set our Blend, Cull, Depth and Dither states. Alpha Compare is // done in the pixel shader due to Nintendo having advanced AC options. GX2OpenGL.SetBlendState(batch.Material.BlendMode); GX2OpenGL.SetCullState(batch.Material.CullMode); GX2OpenGL.SetDepthState(batch.Material.ZMode); GX2OpenGL.SetDitherState(batch.Material.Dither); // Draw our Mesh. GL.DrawElements(batch.PrimitveType, batch.Indexes.Length, DrawElementsType.UnsignedInt, 0); // Unbind the VAOs so that our VAO doesn't leak into the next drawcall. batch.Unbind(); // And finally restore our 'source' vertex positions batch.Vertices = origVerts; } }
private static List<SkeletonBone> LoadJNT1SectionFromStream(EndianBinaryReader reader, long chunkStart) { List<SkeletonBone> skeletonBones = new List<SkeletonBone>(); ushort numJoints = reader.ReadUInt16(); ushort padding = reader.ReadUInt16(); uint jointDataOffset = reader.ReadUInt32(); // Relative to JNT1 Header Start uint jointRemapOffset = reader.ReadUInt32(); uint stringTableOffset = reader.ReadUInt32(); // Grab the joint names from file reader.BaseStream.Position = chunkStart + stringTableOffset; StringTable jointNames = StringTable.FromStream(reader); // This is always 0 to (numJoints-1) - unsure if it's a joint // remap (likely) or a string-table remap (less likely). It's unknown // if any models don't follow this 0 to (n-1) pattern. ushort[] jointRemaps = new ushort[numJoints]; reader.BaseStream.Position = chunkStart + jointRemapOffset; for (int j = 0; j < numJoints; j++) jointRemaps[j] = reader.ReadUInt16(); // Grab the actual joints reader.BaseStream.Position = chunkStart + jointDataOffset; for (int j = 0; j < numJoints; j++) { SkeletonBone bone = new SkeletonBone(); bone.Name = jointNames[j]; ushort unknown1 = reader.ReadUInt16(); // Values of 0, 2 or 1. yaz0r calls it Matrix Type (referring to 'MatrixTable' which is an index into DRW1 - Draw type? // If value is 1 or 2 then Bounding Box / Radius is Vector3.Zero / 0f // And seems to be 0 if a joint has direct non-joint children (Maybe 0 is a 'bone with children' and the BBMin/Max contain // the bounds of children? ushort unknown2 = reader.ReadUInt16(); // No one seems to know what it is, often 0xFF or 0 or 1. May be two individual bytes with a pad afterwards. for (int f = 0; f < 3; f++) bone.Scale[f] = reader.ReadSingle(); Vector3 eulerAngles = new Vector3(); for (int f = 0; f < 3; f++) eulerAngles[f] = (reader.ReadInt16() * (180 / 32786f)); Quaternion xAxis = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), eulerAngles.X * MathE.Deg2Rad); Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), eulerAngles.Y * MathE.Deg2Rad); Quaternion zAxis = Quaternion.FromAxisAngle(new Vector3(0, 0, 1), eulerAngles.Z * MathE.Deg2Rad); // Swizzling to the ZYX order seems to be the right one. Quaternion finalRot = zAxis * yAxis * xAxis; bone.Rotation = finalRot; Trace.Assert(reader.ReadUInt16() == 0xFFFF); // Padding for (int f = 0; f < 3; f++) bone.Translation[f] = reader.ReadSingle(); bone.BoundingSphereDiameter = reader.ReadSingle(); for (int f = 0; f < 3; f++) bone.BoundingBoxMin[f] = reader.ReadSingle(); for (int f = 0; f < 3; f++) bone.BoundingBoxMax[f] = reader.ReadSingle(); skeletonBones.Add(bone); } return skeletonBones; }