public static Model3D GetSkeletonModel(AnimData animData, int frameNo) { if (null == animData) { return null; } GeometryModel3D model = new GeometryModel3D(); MeshGeometry3D mesh = new MeshGeometry3D(); Point3D[] parentPoints = new Point3D[64]; parentPoints[0] = new Point3D(0, 0, 0); for (int jointNum = 0; jointNum < animData.skeletonDef.GetLength(0); ++jointNum) { int parentIndex = animData.skeletonDef[jointNum]; // Binding position Point3D pos = animData.bindingPose[jointNum]; if (frameNo >= 0) { AnimMeshPose pose = animData.perFrameFKPoses[frameNo, jointNum]; pos = pose.Position; } parentPoints[parentIndex + 1] = pos; AddBone(mesh, parentPoints[parentIndex], pos); } model.Geometry = mesh; DiffuseMaterial dm = new DiffuseMaterial(); dm.Brush = new SolidColorBrush(Colors.DarkGreen); model.Material = dm; return model; }
public static AnimData DecodeCRTA(EngineVersion engineVersion, byte[] data, int startOffset, int length) { int endIndex = startOffset + length; AnimData animData = new AnimData(); animData.NumBones = DataUtil.getLEInt(data, startOffset); animData.Offset4Val = DataUtil.getLEInt(data, startOffset + 4); animData.Offset14Val = DataUtil.getLEInt(data, startOffset + 0x14); animData.Offset18Val = DataUtil.getLEInt(data, startOffset + 0x18); int offset8Val = startOffset + DataUtil.getLEInt(data, startOffset + 8); int bindingPoseOffset = startOffset + DataUtil.getLEInt(data, startOffset + 0x0C); animData.bindingPose = new Point3D[animData.NumBones]; for (int i = 0; i < animData.NumBones; ++i) { animData.bindingPose[i] = new Point3D( -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 0) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 2) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 4) / 64.0 ); } // Skeleton structure int offset10Val = startOffset + DataUtil.getLEInt(data, startOffset + 0x10); animData.skeletonDef = new int[animData.NumBones]; for (int i = 0; i < animData.NumBones; ++i) { animData.skeletonDef[i] = data[offset10Val + i]; } AnimMeshPose[] curPose = new AnimMeshPose[animData.NumBones]; AnimMeshPose pose = null; var bitReader = new BitstreamReader(data, offset8Val, length - (offset8Val - startOffset)); for (int boneNum = 0; boneNum < animData.NumBones; ++boneNum) { pose = new AnimMeshPose(); pose.BoneNum = boneNum; pose.FrameNum = 0; int posLen = bitReader.Read(4) + 1; pose.Position = new Point3D( bitReader.Read(posLen) / 64.0, bitReader.Read(posLen) / 64.0, bitReader.Read(posLen) / 64.0); int rotLen = bitReader.Read(4) + 1; double a = bitReader.Read(rotLen) / 4096.0; double b = bitReader.Read(rotLen) / 4096.0; double c = bitReader.Read(rotLen) / 4096.0; double d = bitReader.Read(rotLen) / 4096.0; pose.Rotation = new Quaternion(b, c, d, a); pose.Velocity = new Point3D(0, 0, 0); pose.AngularVelocity = new Quaternion(0, 0, 0, 0); // This may give us duplicate frame zero poses, but that's ok. animData.MeshPoses.Add(pose); curPose[boneNum] = new AnimMeshPose(pose); } int[] curAngVelFrame = new int[animData.NumBones]; int[] curVelFrame = new int[animData.NumBones]; animData.NumFrames = 1; int totalFrame = 0; pose = null; while (bitReader.HasData(16)) { int count = bitReader.Read(8); int flag = bitReader.Read(1); int boneNum = bitReader.Read(6); totalFrame += count; if (pose == null || pose.FrameNum != totalFrame || pose.BoneNum != boneNum) { if (pose != null) { animData.MeshPoses.Add(pose); } pose = new AnimMeshPose(); pose.FrameNum = totalFrame; pose.BoneNum = boneNum; pose.Position = curPose[boneNum].Position; pose.Rotation = curPose[boneNum].Rotation; pose.AngularVelocity = curPose[boneNum].AngularVelocity; pose.Velocity = curPose[boneNum].Velocity; } if (flag == 1) { // xyz int posLen = bitReader.Read(4) + 1; int x = bitReader.Read(posLen); int y = bitReader.Read(posLen); int z = bitReader.Read(posLen); Point3D vel = new Point3D(x, y, z); Point3D prevVel = pose.Velocity; double coeff = (totalFrame - curVelFrame[boneNum]) / 256.0; Point3D posDelta = new Point3D(prevVel.X * coeff, prevVel.Y * coeff, prevVel.Z * coeff); pose.Position = new Point3D(pose.Position.X + posDelta.X, pose.Position.Y + posDelta.Y, pose.Position.Z + posDelta.Z); pose.FrameNum = totalFrame; pose.Velocity = vel; curPose[boneNum].Position = pose.Position; curPose[boneNum].Velocity = pose.Velocity; curVelFrame[boneNum] = totalFrame; } else { // rot int rotLen = bitReader.Read(4) + 1; int a = bitReader.Read(rotLen); int b = bitReader.Read(rotLen); int c = bitReader.Read(rotLen); int d = bitReader.Read(rotLen); Quaternion angVel = new Quaternion(b, c, d, a); Quaternion prevAngVel = pose.AngularVelocity; double coeff = (totalFrame - curAngVelFrame[boneNum]) / 131072.0; Quaternion angDelta = new Quaternion(prevAngVel.X * coeff, prevAngVel.Y * coeff, prevAngVel.Z * coeff, prevAngVel.W * coeff); pose.Rotation = new Quaternion(pose.Rotation.X + angDelta.X, pose.Rotation.Y + angDelta.Y, pose.Rotation.Z + angDelta.Z, pose.Rotation.W + angDelta.W); pose.FrameNum = totalFrame; pose.AngularVelocity = angVel; curPose[boneNum].Rotation = pose.Rotation; curPose[boneNum].AngularVelocity = pose.AngularVelocity; curAngVelFrame[boneNum] = totalFrame; } } animData.MeshPoses.Add(pose); animData.NumFrames = totalFrame + 1; animData.BuildPerFramePoses(); animData.BuildPerFrameFKPoses(); return(animData); }
public static AnimData DecodeBGDA(EngineVersion engineVersion, byte[] data, int startOffset, int length) { int endIndex = startOffset + length; AnimData animData = new AnimData(); animData.NumBones = DataUtil.getLEInt(data, startOffset); animData.Offset4Val = DataUtil.getLEInt(data, startOffset + 4); animData.Offset14Val = DataUtil.getLEInt(data, startOffset + 0x14); animData.Offset18Val = DataUtil.getLEInt(data, startOffset + 0x18); int offset8Val = startOffset + DataUtil.getLEInt(data, startOffset + 8); int bindingPoseOffset = startOffset + DataUtil.getLEInt(data, startOffset + 0x0C); animData.bindingPose = new Point3D[animData.NumBones]; for (int i = 0; i < animData.NumBones; ++i) { animData.bindingPose[i] = new Point3D( -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 0) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 2) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 4) / 64.0 ); } // Skeleton structure int offset10Val = startOffset + DataUtil.getLEInt(data, startOffset + 0x10); animData.skeletonDef = new int[animData.NumBones]; for (int i = 0; i < animData.NumBones; ++i) { animData.skeletonDef[i] = data[offset10Val + i]; } AnimMeshPose[] curPose = new AnimMeshPose[animData.NumBones]; AnimMeshPose pose = null; for (int boneNum = 0; boneNum < animData.NumBones; ++boneNum) { pose = new AnimMeshPose(); pose.BoneNum = boneNum; pose.FrameNum = 0; int frameOff = offset8Val + boneNum * 0x0e; pose.Position = new Point3D( DataUtil.getLEShort(data, frameOff) / 64.0, DataUtil.getLEShort(data, frameOff + 2) / 64.0, DataUtil.getLEShort(data, frameOff + 4) / 64.0); double a = DataUtil.getLEShort(data, frameOff + 6) / 4096.0; double b = DataUtil.getLEShort(data, frameOff + 8) / 4096.0; double c = DataUtil.getLEShort(data, frameOff + 0x0A) / 4096.0; double d = DataUtil.getLEShort(data, frameOff + 0x0C) / 4096.0; pose.Rotation = new Quaternion(b, c, d, a); pose.Velocity = new Point3D(0, 0, 0); pose.AngularVelocity = new Quaternion(0, 0, 0, 0); // This may give us duplicate frame zero poses, but that's ok. animData.MeshPoses.Add(pose); curPose[boneNum] = new AnimMeshPose(pose); } int[] curAngVelFrame = new int[animData.NumBones]; int[] curVelFrame = new int[animData.NumBones]; animData.NumFrames = 1; int totalFrame = 0; int otherOff = offset8Val + animData.NumBones * 0x0e; pose = null; while (otherOff < endIndex) { int count = data[otherOff++]; byte byte2 = data[otherOff++]; int boneNum = byte2 & 0x3f; if (boneNum == 0x3f) { break; } totalFrame += count; if (pose == null || pose.FrameNum != totalFrame || pose.BoneNum != boneNum) { if (pose != null) { animData.MeshPoses.Add(pose); } pose = new AnimMeshPose(); pose.FrameNum = totalFrame; pose.BoneNum = boneNum; pose.Position = curPose[boneNum].Position; pose.Rotation = curPose[boneNum].Rotation; pose.AngularVelocity = curPose[boneNum].AngularVelocity; pose.Velocity = curPose[boneNum].Velocity; } // bit 7 specifies whether to read 4 (set) or 3 elements following // bit 6 specifies whether they are shorts or bytes (set). if ((byte2 & 0x80) == 0x80) { int a, b, c, d; if ((byte2 & 0x40) == 0x40) { a = (sbyte)data[otherOff++]; b = (sbyte)data[otherOff++]; c = (sbyte)data[otherOff++]; d = (sbyte)data[otherOff++]; } else { a = DataUtil.getLEShort(data, otherOff); b = DataUtil.getLEShort(data, otherOff + 2); c = DataUtil.getLEShort(data, otherOff + 4); d = DataUtil.getLEShort(data, otherOff + 6); otherOff += 8; } Quaternion angVel = new Quaternion(b, c, d, a); Quaternion prevAngVel = pose.AngularVelocity; double coeff = (totalFrame - curAngVelFrame[boneNum]) / 131072.0; Quaternion angDelta = new Quaternion(prevAngVel.X * coeff, prevAngVel.Y * coeff, prevAngVel.Z * coeff, prevAngVel.W * coeff); pose.Rotation = new Quaternion(pose.Rotation.X + angDelta.X, pose.Rotation.Y + angDelta.Y, pose.Rotation.Z + angDelta.Z, pose.Rotation.W + angDelta.W); pose.FrameNum = totalFrame; pose.AngularVelocity = angVel; curPose[boneNum].Rotation = pose.Rotation; curPose[boneNum].AngularVelocity = pose.AngularVelocity; curAngVelFrame[boneNum] = totalFrame; } else { int x, y, z; if ((byte2 & 0x40) == 0x40) { x = (sbyte)data[otherOff++]; y = (sbyte)data[otherOff++]; z = (sbyte)data[otherOff++]; } else { x = DataUtil.getLEShort(data, otherOff); y = DataUtil.getLEShort(data, otherOff + 2); z = DataUtil.getLEShort(data, otherOff + 4); otherOff += 6; } Point3D vel = new Point3D(x, y, z); Point3D prevVel = pose.Velocity; double coeff = (totalFrame - curVelFrame[boneNum]) / 512.0; Point3D posDelta = new Point3D(prevVel.X * coeff, prevVel.Y * coeff, prevVel.Z * coeff); pose.Position = new Point3D(pose.Position.X + posDelta.X, pose.Position.Y + posDelta.Y, pose.Position.Z + posDelta.Z); pose.FrameNum = totalFrame; pose.Velocity = vel; curPose[boneNum].Position = pose.Position; curPose[boneNum].Velocity = pose.Velocity; curVelFrame[boneNum] = totalFrame; } } animData.MeshPoses.Add(pose); animData.NumFrames = totalFrame + 1; animData.BuildPerFramePoses(); animData.BuildPerFrameFKPoses(); return(animData); }
public static AnimData DecodeCRTA(EngineVersion engineVersion, byte[] data, int startOffset, int length) { int endIndex = startOffset + length; AnimData animData = new AnimData(); animData.NumBones = DataUtil.getLEInt(data, startOffset); animData.Offset4Val = DataUtil.getLEInt(data, startOffset + 4); animData.Offset14Val = DataUtil.getLEInt(data, startOffset + 0x14); animData.Offset18Val = DataUtil.getLEInt(data, startOffset + 0x18); int offset8Val = startOffset + DataUtil.getLEInt(data, startOffset + 8); int bindingPoseOffset = startOffset + DataUtil.getLEInt(data, startOffset + 0x0C); animData.bindingPose = new Point3D[animData.NumBones]; for (int i = 0; i < animData.NumBones; ++i) { animData.bindingPose[i] = new Point3D( -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 0) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 2) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 4) / 64.0 ); } // Skeleton structure int offset10Val = startOffset + DataUtil.getLEInt(data, startOffset + 0x10); animData.skeletonDef = new int[animData.NumBones]; for (int i = 0; i < animData.NumBones; ++i) { animData.skeletonDef[i] = data[offset10Val + i]; } AnimMeshPose[] curPose = new AnimMeshPose[animData.NumBones]; AnimMeshPose pose = null; var bitReader = new BitstreamReader(data, offset8Val, length - (offset8Val - startOffset)); for (int boneNum = 0; boneNum < animData.NumBones; ++boneNum) { pose = new AnimMeshPose(); pose.BoneNum = boneNum; pose.FrameNum = 0; int posLen = bitReader.Read(4) + 1; pose.Position = new Point3D( bitReader.Read(posLen) / 64.0, bitReader.Read(posLen) / 64.0, bitReader.Read(posLen) / 64.0); int rotLen = bitReader.Read(4) + 1; double a = bitReader.Read(rotLen) / 4096.0; double b = bitReader.Read(rotLen) / 4096.0; double c = bitReader.Read(rotLen) / 4096.0; double d = bitReader.Read(rotLen) / 4096.0; pose.Rotation = new Quaternion(b, c, d, a); pose.Velocity = new Point3D(0, 0, 0); pose.AngularVelocity = new Quaternion(0, 0, 0, 0); // This may give us duplicate frame zero poses, but that's ok. animData.MeshPoses.Add(pose); curPose[boneNum] = new AnimMeshPose(pose); } int[] curAngVelFrame = new int[animData.NumBones]; int[] curVelFrame = new int[animData.NumBones]; animData.NumFrames = 1; int totalFrame = 0; pose = null; while (bitReader.HasData(16)) { int count = bitReader.Read(8); int flag = bitReader.Read(1); int boneNum = bitReader.Read(6); totalFrame += count; if (pose == null || pose.FrameNum != totalFrame || pose.BoneNum != boneNum) { if (pose != null) { animData.MeshPoses.Add(pose); } pose = new AnimMeshPose(); pose.FrameNum = totalFrame; pose.BoneNum = boneNum; pose.Position = curPose[boneNum].Position; pose.Rotation = curPose[boneNum].Rotation; pose.AngularVelocity = curPose[boneNum].AngularVelocity; pose.Velocity = curPose[boneNum].Velocity; } if (flag == 1) { // xyz int posLen = bitReader.Read(4) + 1; int x = bitReader.Read(posLen); int y = bitReader.Read(posLen); int z = bitReader.Read(posLen); Point3D vel = new Point3D(x, y, z); Point3D prevVel = pose.Velocity; double coeff = (totalFrame - curVelFrame[boneNum]) / 256.0; Point3D posDelta = new Point3D(prevVel.X * coeff, prevVel.Y * coeff, prevVel.Z * coeff); pose.Position = new Point3D(pose.Position.X + posDelta.X, pose.Position.Y + posDelta.Y, pose.Position.Z + posDelta.Z); pose.FrameNum = totalFrame; pose.Velocity = vel; curPose[boneNum].Position = pose.Position; curPose[boneNum].Velocity = pose.Velocity; curVelFrame[boneNum] = totalFrame; } else { // rot int rotLen = bitReader.Read(4) + 1; int a = bitReader.Read(rotLen); int b = bitReader.Read(rotLen); int c = bitReader.Read(rotLen); int d = bitReader.Read(rotLen); Quaternion angVel = new Quaternion(b, c, d, a); Quaternion prevAngVel = pose.AngularVelocity; double coeff = (totalFrame - curAngVelFrame[boneNum]) / 131072.0; Quaternion angDelta = new Quaternion(prevAngVel.X * coeff, prevAngVel.Y * coeff, prevAngVel.Z * coeff, prevAngVel.W * coeff); pose.Rotation = new Quaternion(pose.Rotation.X + angDelta.X, pose.Rotation.Y + angDelta.Y, pose.Rotation.Z + angDelta.Z, pose.Rotation.W + angDelta.W); pose.FrameNum = totalFrame; pose.AngularVelocity = angVel; curPose[boneNum].Rotation = pose.Rotation; curPose[boneNum].AngularVelocity = pose.AngularVelocity; curAngVelFrame[boneNum] = totalFrame; } } animData.MeshPoses.Add(pose); animData.NumFrames = totalFrame + 1; animData.BuildPerFramePoses(); animData.BuildPerFrameFKPoses(); return animData; }
public static AnimData DecodeBGDA(EngineVersion engineVersion, byte[] data, int startOffset, int length) { int endIndex = startOffset + length; AnimData animData = new AnimData(); animData.NumBones = DataUtil.getLEInt(data, startOffset); animData.Offset4Val = DataUtil.getLEInt(data, startOffset + 4); animData.Offset14Val = DataUtil.getLEInt(data, startOffset + 0x14); animData.Offset18Val = DataUtil.getLEInt(data, startOffset + 0x18); int offset8Val = startOffset + DataUtil.getLEInt(data, startOffset + 8); int bindingPoseOffset = startOffset + DataUtil.getLEInt(data, startOffset + 0x0C); animData.bindingPose = new Point3D[animData.NumBones]; for (int i = 0; i < animData.NumBones; ++i) { animData.bindingPose[i] = new Point3D( -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 0) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 2) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 4) / 64.0 ); } // Skeleton structure int offset10Val = startOffset + DataUtil.getLEInt(data, startOffset + 0x10); animData.skeletonDef = new int[animData.NumBones]; for (int i = 0; i < animData.NumBones; ++i) { animData.skeletonDef[i] = data[offset10Val + i]; } AnimMeshPose[] curPose = new AnimMeshPose[animData.NumBones]; AnimMeshPose pose = null; for (int boneNum = 0; boneNum < animData.NumBones; ++boneNum) { pose = new AnimMeshPose(); pose.BoneNum = boneNum; pose.FrameNum = 0; int frameOff = offset8Val + boneNum * 0x0e; pose.Position = new Point3D( DataUtil.getLEShort(data, frameOff) / 64.0, DataUtil.getLEShort(data, frameOff + 2) / 64.0, DataUtil.getLEShort(data, frameOff + 4) / 64.0); double a = DataUtil.getLEShort(data, frameOff + 6) / 4096.0; double b = DataUtil.getLEShort(data, frameOff + 8) / 4096.0; double c = DataUtil.getLEShort(data, frameOff + 0x0A) / 4096.0; double d = DataUtil.getLEShort(data, frameOff + 0x0C) / 4096.0; pose.Rotation = new Quaternion(b, c, d, a); pose.Velocity = new Point3D(0, 0, 0); pose.AngularVelocity = new Quaternion(0, 0, 0, 0); // This may give us duplicate frame zero poses, but that's ok. animData.MeshPoses.Add(pose); curPose[boneNum] = new AnimMeshPose(pose); } int[] curAngVelFrame = new int[animData.NumBones]; int[] curVelFrame = new int[animData.NumBones]; animData.NumFrames = 1; int totalFrame = 0; int otherOff = offset8Val + animData.NumBones * 0x0e; pose = null; while (otherOff < endIndex) { int count = data[otherOff++]; byte byte2 = data[otherOff++]; int boneNum = byte2 & 0x3f; if (boneNum == 0x3f) break; totalFrame += count; if (pose == null || pose.FrameNum != totalFrame || pose.BoneNum != boneNum) { if (pose != null) { animData.MeshPoses.Add(pose); } pose = new AnimMeshPose(); pose.FrameNum = totalFrame; pose.BoneNum = boneNum; pose.Position = curPose[boneNum].Position; pose.Rotation = curPose[boneNum].Rotation; pose.AngularVelocity = curPose[boneNum].AngularVelocity; pose.Velocity = curPose[boneNum].Velocity; } // bit 7 specifies whether to read 4 (set) or 3 elements following // bit 6 specifies whether they are shorts or bytes (set). if ((byte2 & 0x80) == 0x80) { int a, b, c, d; if ((byte2 & 0x40) == 0x40) { a = (sbyte)data[otherOff++]; b = (sbyte)data[otherOff++]; c = (sbyte)data[otherOff++]; d = (sbyte)data[otherOff++]; } else { a = DataUtil.getLEShort(data, otherOff); b = DataUtil.getLEShort(data, otherOff+2); c = DataUtil.getLEShort(data, otherOff+4); d = DataUtil.getLEShort(data, otherOff+6); otherOff += 8; } Quaternion angVel = new Quaternion(b, c, d, a); Quaternion prevAngVel = pose.AngularVelocity; double coeff = (totalFrame - curAngVelFrame[boneNum]) / 131072.0; Quaternion angDelta = new Quaternion(prevAngVel.X * coeff, prevAngVel.Y * coeff, prevAngVel.Z * coeff, prevAngVel.W * coeff); pose.Rotation = new Quaternion(pose.Rotation.X + angDelta.X, pose.Rotation.Y + angDelta.Y, pose.Rotation.Z + angDelta.Z, pose.Rotation.W + angDelta.W); pose.FrameNum = totalFrame; pose.AngularVelocity = angVel; curPose[boneNum].Rotation = pose.Rotation; curPose[boneNum].AngularVelocity = pose.AngularVelocity; curAngVelFrame[boneNum] = totalFrame; } else { int x, y, z; if ((byte2 & 0x40) == 0x40) { x = (sbyte)data[otherOff++]; y = (sbyte)data[otherOff++]; z = (sbyte)data[otherOff++]; } else { x = DataUtil.getLEShort(data, otherOff); y = DataUtil.getLEShort(data, otherOff + 2); z = DataUtil.getLEShort(data, otherOff + 4); otherOff += 6; } Point3D vel = new Point3D(x, y, z); Point3D prevVel = pose.Velocity; double coeff = (totalFrame - curVelFrame[boneNum]) / 512.0; Point3D posDelta = new Point3D(prevVel.X * coeff, prevVel.Y * coeff, prevVel.Z * coeff); pose.Position = new Point3D(pose.Position.X + posDelta.X, pose.Position.Y + posDelta.Y, pose.Position.Z + posDelta.Z); pose.FrameNum = totalFrame; pose.Velocity = vel; curPose[boneNum].Position = pose.Position; curPose[boneNum].Velocity = pose.Velocity; curVelFrame[boneNum] = totalFrame; } } animData.MeshPoses.Add(pose); animData.NumFrames = totalFrame+1; animData.BuildPerFramePoses(); animData.BuildPerFrameFKPoses(); return animData; }
public static Model3D CreateModel3D(List<Mesh> meshGroups, BitmapSource texture, AnimData pose, int frame) { GeometryModel3D model = new GeometryModel3D(); var mesh3D = new MeshGeometry3D(); int numVertices = 0; foreach (var meshGroup in meshGroups) { numVertices += meshGroup.Positions.Count; } var triangleIndices = new Int32Collection(); var positions = new Point3DCollection(numVertices); var normals = new Vector3DCollection(numVertices); var uvCoords = new PointCollection(numVertices); int vstart = 0; foreach (var meshGroup in meshGroups) { Boolean hasVertexWeights = meshGroup.vertexWeights.Count > 0; int vwNum = 0; VertexWeight vw = new VertexWeight(); if (meshGroup.vertexWeights.Count > 0) { vw = meshGroup.vertexWeights[vwNum]; } int vnum = 0; foreach (var vertex in meshGroup.Positions) { var point = vertex; if (frame >= 0 && pose != null) { if (vw.endVertex < vnum) { ++vwNum; vw = meshGroup.vertexWeights[vwNum]; if (vnum < vw.startVertex || vnum > vw.endVertex) { Debug.Fail("Vertex " + vnum + " out of range of bone weights " + vw.startVertex + " -> " + vw.endVertex); } } int bone1No = vw.bone1; Point3D bindingPos1 = pose.bindingPose[bone1No]; AnimMeshPose bone1Pose = pose.perFrameFKPoses[frame, bone1No]; var joint1Pos = bone1Pose.Position; if (vw.bone2 == 0xFF) { if (bone1No == 1) { bone1No = 1; } Matrix3D m = Matrix3D.Identity; m.Translate(new Vector3D(-bindingPos1.X, -bindingPos1.Y, -bindingPos1.Z)); // Inverse binding matrix m.Rotate(bone1Pose.Rotation); m.Translate(new Vector3D(bone1Pose.Position.X, bone1Pose.Position.Y, bone1Pose.Position.Z)); point = m.Transform(point); } else { // multi-bone int bone2No = vw.bone2; Point3D bindingPos2 = pose.bindingPose[bone2No]; AnimMeshPose bone2Pose = pose.perFrameFKPoses[frame, bone2No]; double boneSum = vw.boneWeight1 + vw.boneWeight2; double bone1Coeff = vw.boneWeight1 / boneSum; double bone2Coeff = vw.boneWeight2 / boneSum; Matrix3D m = Matrix3D.Identity; m.Translate(new Vector3D(-bindingPos1.X, -bindingPos1.Y, -bindingPos1.Z)); // Inverse binding matrix m.Rotate(bone1Pose.Rotation); m.Translate(new Vector3D(bone1Pose.Position.X, bone1Pose.Position.Y, bone1Pose.Position.Z)); var point1 = m.Transform(point); // Now rotate Matrix3D m2 = Matrix3D.Identity; m2.Translate(new Vector3D(-bindingPos2.X, -bindingPos2.Y, -bindingPos2.Z)); // Inverse binding matrix m2.Rotate(bone2Pose.Rotation); m2.Translate(new Vector3D(bone2Pose.Position.X, bone2Pose.Position.Y, bone2Pose.Position.Z)); var point2 = m2.Transform(point); point = new Point3D(point1.X * bone1Coeff + point2.X * bone2Coeff, point1.Y * bone1Coeff + point2.Y * bone2Coeff, point1.Z * bone1Coeff + point2.Z * bone2Coeff); } } positions.Add(point); ++vnum; } foreach (var normal in meshGroup.Normals) { normals.Add(normal); } foreach (var ti in meshGroup.TriangleIndices) { triangleIndices.Add(ti+vstart); } foreach (var uv in meshGroup.TextureCoordinates) { uvCoords.Add(uv); } vstart += meshGroup.Positions.Count; } mesh3D.TriangleIndices = triangleIndices; mesh3D.Positions = positions; mesh3D.TextureCoordinates = uvCoords; mesh3D.Normals = normals; model.Geometry = mesh3D; var dm = new DiffuseMaterial(); if (texture != null && texture.Width > 0 && texture.Height > 0) { var ib = new ImageBrush(texture); ib.ViewportUnits = BrushMappingMode.Absolute; // May be needed at a later point //ib.TileMode = TileMode.Tile; dm.Brush = ib; } else { var dg = new DrawingGroup(); // Background dg.Children.Add(new GeometryDrawing() { Brush = new SolidColorBrush(Colors.Black), Geometry = new RectangleGeometry(new Rect(0, 0, 2, 2)) }); // Tiles dg.Children.Add(new GeometryDrawing() { Brush = new SolidColorBrush(Colors.Violet), Geometry = new RectangleGeometry(new Rect(0, 0, 1, 1)) }); dg.Children.Add(new GeometryDrawing() { Brush = new SolidColorBrush(Colors.Violet), Geometry = new RectangleGeometry(new Rect(1, 1, 1, 1)) }); dm.Brush = new DrawingBrush(dg){ TileMode = TileMode.Tile, Transform = new ScaleTransform(0.1,0.1)}; } model.Material = dm; return model; }
public static AnimData DecodeCRTA(EngineVersion engineVersion, byte[] data, int startOffset, int length) { var endIndex = startOffset + length; var animData = new AnimData { NumBones = DataUtil.getLEInt(data, startOffset), Offset4Val = DataUtil.getLEInt(data, startOffset + 4), // max frame Offset14Val = DataUtil.getLEInt(data, startOffset + 0x14), Offset18Val = DataUtil.getLEInt(data, startOffset + 0x18) }; var offset8Val = DataUtil.getLEInt(data, startOffset + 8); var bindingPoseOffset = startOffset + DataUtil.getLEInt(data, startOffset + 0x0C); animData.bindingPose = new Point3D[animData.NumBones]; for (var i = 0; i < animData.NumBones; ++i) { animData.bindingPose[i] = new Point3D( -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 0) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 2) / 64.0, -DataUtil.getLEShort(data, bindingPoseOffset + i * 8 + 4) / 64.0 ); } // Skeleton structure var offset10Val = startOffset + DataUtil.getLEInt(data, startOffset + 0x10); animData.skeletonDef = new int[animData.NumBones]; for (var i = 0; i < animData.NumBones; ++i) { animData.skeletonDef[i] = data[offset10Val + i]; } var curPose = new AnimMeshPose[animData.NumBones]; AnimMeshPose pose = null; var bitReader = new BitstreamReader(data, startOffset + offset8Val, length - offset8Val); for (var boneNum = 0; boneNum < animData.NumBones; ++boneNum) { pose = new AnimMeshPose { BoneNum = boneNum, FrameNum = 0 }; var posLen = bitReader.Read(4) + 1; pose.Position = new Point3D( bitReader.ReadSigned(posLen) / 64.0, bitReader.ReadSigned(posLen) / 64.0, bitReader.ReadSigned(posLen) / 64.0); var rotLen = bitReader.Read(4) + 1; var a = bitReader.ReadSigned(rotLen) / 4096.0; var b = bitReader.ReadSigned(rotLen) / 4096.0; var c = bitReader.ReadSigned(rotLen) / 4096.0; var d = bitReader.ReadSigned(rotLen) / 4096.0; pose.Rotation = new Quaternion(b, c, d, a); pose.Velocity = new Point3D(0, 0, 0); pose.AngularVelocity = new Quaternion(0, 0, 0, 0); // This may give us duplicate frame zero poses, but that's ok. animData.MeshPoses.Add(pose); curPose[boneNum] = new AnimMeshPose(pose); } var curAngVelFrame = new int[animData.NumBones]; var curVelFrame = new int[animData.NumBones]; animData.NumFrames = 1; var totalFrame = 0; pose = null; while (bitReader.HasData(22) && totalFrame < animData.Offset4Val) { int count = bitReader.Read(8); if (count == 0xFF) { break; } int flag = bitReader.Read(1); int boneNum = bitReader.Read(6); if (boneNum >= animData.NumBones) { break; } totalFrame += count; if (pose == null || pose.FrameNum != totalFrame || pose.BoneNum != boneNum) { if (pose != null) { animData.MeshPoses.Add(pose); } pose = new AnimMeshPose { FrameNum = totalFrame, BoneNum = boneNum, Position = curPose[boneNum].Position, Rotation = curPose[boneNum].Rotation, AngularVelocity = curPose[boneNum].AngularVelocity, Velocity = curPose[boneNum].Velocity }; } if (flag == 1) { // xyz var posLen = bitReader.Read(4) + 1; var x = bitReader.ReadSigned(posLen); var y = bitReader.ReadSigned(posLen); var z = bitReader.ReadSigned(posLen); var vel = new Point3D(x, y, z); var prevVel = pose.Velocity; var coeff = (totalFrame - curVelFrame[boneNum]) / 256.0; var posDelta = new Point3D(prevVel.X * coeff, prevVel.Y * coeff, prevVel.Z * coeff); pose.Position = new Point3D(pose.Position.X + posDelta.X, pose.Position.Y + posDelta.Y, pose.Position.Z + posDelta.Z); pose.FrameNum = totalFrame; pose.Velocity = vel; curPose[boneNum].Position = pose.Position; curPose[boneNum].Velocity = pose.Velocity; curVelFrame[boneNum] = totalFrame; } else { // rot var rotLen = bitReader.Read(4) + 1; var a = bitReader.ReadSigned(rotLen); var b = bitReader.ReadSigned(rotLen); var c = bitReader.ReadSigned(rotLen); var d = bitReader.ReadSigned(rotLen); var angVel = new Quaternion(b, c, d, a); var prevAngVel = pose.AngularVelocity; var coeff = (totalFrame - curAngVelFrame[boneNum]) / 131072.0; var angDelta = new Quaternion(prevAngVel.X * coeff, prevAngVel.Y * coeff, prevAngVel.Z * coeff, prevAngVel.W * coeff); pose.Rotation = new Quaternion(pose.Rotation.X + angDelta.X, pose.Rotation.Y + angDelta.Y, pose.Rotation.Z + angDelta.Z, pose.Rotation.W + angDelta.W); pose.FrameNum = totalFrame; pose.AngularVelocity = angVel; curPose[boneNum].Rotation = pose.Rotation; curPose[boneNum].AngularVelocity = pose.AngularVelocity; curAngVelFrame[boneNum] = totalFrame; } } animData.MeshPoses.Add(pose); animData.NumFrames = animData.Offset4Val + 1; // totalFrame + 1; animData.BuildPerFramePoses(); animData.BuildPerFrameFKPoses(); return(animData); }
public static Model3D CreateModel3D(List <Mesh> meshGroups, BitmapSource texture, AnimData pose, int frame) { GeometryModel3D model = new GeometryModel3D(); var mesh3D = new MeshGeometry3D(); int numVertices = 0; foreach (var meshGroup in meshGroups) { numVertices += meshGroup.Positions.Count; } var triangleIndices = new Int32Collection(); var positions = new Point3DCollection(numVertices); var normals = new Vector3DCollection(numVertices); var uvCoords = new PointCollection(numVertices); int vstart = 0; foreach (var meshGroup in meshGroups) { Boolean hasVertexWeights = meshGroup.vertexWeights.Count > 0; int vwNum = 0; VertexWeight vw = new VertexWeight(); if (meshGroup.vertexWeights.Count > 0) { vw = meshGroup.vertexWeights[vwNum]; } int vnum = 0; foreach (var vertex in meshGroup.Positions) { var point = vertex; if (frame >= 0 && pose != null) { if (vw.endVertex < vnum) { ++vwNum; vw = meshGroup.vertexWeights[vwNum]; if (vnum < vw.startVertex || vnum > vw.endVertex) { Debug.Fail("Vertex " + vnum + " out of range of bone weights " + vw.startVertex + " -> " + vw.endVertex); } } int bone1No = vw.bone1; Point3D bindingPos1 = pose.bindingPose[bone1No]; AnimMeshPose bone1Pose = pose.perFrameFKPoses[frame, bone1No]; var joint1Pos = bone1Pose.Position; if (vw.bone2 == 0xFF) { if (bone1No == 1) { bone1No = 1; } Matrix3D m = Matrix3D.Identity; m.Translate(new Vector3D(-bindingPos1.X, -bindingPos1.Y, -bindingPos1.Z)); // Inverse binding matrix m.Rotate(bone1Pose.Rotation); m.Translate(new Vector3D(bone1Pose.Position.X, bone1Pose.Position.Y, bone1Pose.Position.Z)); point = m.Transform(point); } else { // multi-bone int bone2No = vw.bone2; Point3D bindingPos2 = pose.bindingPose[bone2No]; AnimMeshPose bone2Pose = pose.perFrameFKPoses[frame, bone2No]; double boneSum = vw.boneWeight1 + vw.boneWeight2; double bone1Coeff = vw.boneWeight1 / boneSum; double bone2Coeff = vw.boneWeight2 / boneSum; Matrix3D m = Matrix3D.Identity; m.Translate(new Vector3D(-bindingPos1.X, -bindingPos1.Y, -bindingPos1.Z)); // Inverse binding matrix m.Rotate(bone1Pose.Rotation); m.Translate(new Vector3D(bone1Pose.Position.X, bone1Pose.Position.Y, bone1Pose.Position.Z)); var point1 = m.Transform(point); // Now rotate Matrix3D m2 = Matrix3D.Identity; m2.Translate(new Vector3D(-bindingPos2.X, -bindingPos2.Y, -bindingPos2.Z)); // Inverse binding matrix m2.Rotate(bone2Pose.Rotation); m2.Translate(new Vector3D(bone2Pose.Position.X, bone2Pose.Position.Y, bone2Pose.Position.Z)); var point2 = m2.Transform(point); point = new Point3D(point1.X * bone1Coeff + point2.X * bone2Coeff, point1.Y * bone1Coeff + point2.Y * bone2Coeff, point1.Z * bone1Coeff + point2.Z * bone2Coeff); } } positions.Add(point); ++vnum; } foreach (var normal in meshGroup.Normals) { normals.Add(normal); } foreach (var ti in meshGroup.TriangleIndices) { triangleIndices.Add(ti + vstart); } foreach (var uv in meshGroup.TextureCoordinates) { uvCoords.Add(uv); } vstart += meshGroup.Positions.Count; } mesh3D.TriangleIndices = triangleIndices; mesh3D.Positions = positions; mesh3D.TextureCoordinates = uvCoords; mesh3D.Normals = normals; model.Geometry = mesh3D; var dm = new DiffuseMaterial(); if (texture != null && texture.Width > 0 && texture.Height > 0) { var ib = new ImageBrush(texture); ib.ViewportUnits = BrushMappingMode.Absolute; // May be needed at a later point //ib.TileMode = TileMode.Tile; dm.Brush = ib; } else { var dg = new DrawingGroup(); // Background dg.Children.Add(new GeometryDrawing() { Brush = new SolidColorBrush(Colors.Black), Geometry = new RectangleGeometry(new Rect(0, 0, 2, 2)) }); // Tiles dg.Children.Add(new GeometryDrawing() { Brush = new SolidColorBrush(Colors.Violet), Geometry = new RectangleGeometry(new Rect(0, 0, 1, 1)) }); dg.Children.Add(new GeometryDrawing() { Brush = new SolidColorBrush(Colors.Violet), Geometry = new RectangleGeometry(new Rect(1, 1, 1, 1)) }); dm.Brush = new DrawingBrush(dg) { TileMode = TileMode.Tile, Transform = new ScaleTransform(0.1, 0.1) }; } model.Material = dm; return(model); }