private static void ConfigureVertexAttributes(Mesh mesh, UltimateMesh renderMesh, RSkeleton skeleton, MeshObject meshObject, BufferObject vertexBuffer0, BufferObject vertexBuffer1) { var riggingAccessor = new SsbhRiggingAccessor(mesh); var influences = riggingAccessor.ReadRiggingBuffer(meshObject.Name, (int)meshObject.SubIndex); var indexByBoneName = GetIndexByBoneName(skeleton); // TODO: Optimize reading/configuring rigging buffer? GetRiggingData(meshObject.VertexCount, influences, indexByBoneName, out IVec4[] boneIndices, out Vector4[] boneWeights);
public RModel GetRenderModel(RSkeleton skeleton) => MeshToRenderable.GetRenderModel(mesh, skeleton);
private void GetNodesForRendering(ref NumsbhNode meshNode, ref NuhlpbNode hlpbNode, ref RSkeleton skeleton, ref Matl material, ref XmbNode modelXmb, ref XmbNode lodXmb, Dictionary <string, RTexture> textureByName) { // TODO: There's probably a cleaner way of doing this. foreach (FileNode fileNode in Parent.Nodes) { if (fileNode is NuhlpbNode node) { hlpbNode = node; } else if (fileNode is NutexNode nutexNode) { var texture = (RTexture)nutexNode.GetRenderableNode(); textureByName[nutexNode.TexName.ToLower()] = texture; } else if (fileNode.Text.Equals(model.MeshString)) { meshNode = (NumsbhNode)fileNode; } else if (fileNode.Text.Equals(model.SkeletonFileName)) { skeleton = (RSkeleton)((SkelNode)fileNode).GetRenderableNode(); } else if (fileNode.Text.Equals(model.MaterialFileNames[0].MaterialFileName)) { material = ((MatlNode)fileNode).Material; } else if (fileNode.Text.Equals("model.xmb")) { modelXmb = (XmbNode)fileNode; } else if (fileNode.Text.Equals("lod.xmb")) { lodXmb = (XmbNode)fileNode; } } }
public static void ExportIOAnimationAsANIM(string fname, IOAnimation animation, RSkeleton Skeleton, bool ordinal = false) { IO_MayaANIM anim = new IO_MayaANIM(); anim.header.endTime = animation.FrameCount + 1; // get bone order List <RBone> BonesInOrder = getBoneTreeOrder(Skeleton); if (ordinal) { BonesInOrder = BonesInOrder.OrderBy(f => f.Name, StringComparer.Ordinal).ToList(); } foreach (RBone b in BonesInOrder) { AnimBone animBone = new AnimBone() { name = b.Name }; anim.Bones.Add(animBone); // Add Tracks if (animation.TryGetNodeByName(b.Name, out IOAnimNode ioAnimNode)) { AddAnimData(animBone, ioAnimNode, IOTrackType.POSX, ControlType.translate, TrackType.translateX); AddAnimData(animBone, ioAnimNode, IOTrackType.POSY, ControlType.translate, TrackType.translateY); AddAnimData(animBone, ioAnimNode, IOTrackType.POSZ, ControlType.translate, TrackType.translateZ); // rotation if (animation.RotationType == IORotationType.Euler) { // directly AddAnimData(animBone, ioAnimNode, IOTrackType.ROTX, ControlType.rotate, TrackType.rotateX); AddAnimData(animBone, ioAnimNode, IOTrackType.ROTY, ControlType.rotate, TrackType.rotateY); AddAnimData(animBone, ioAnimNode, IOTrackType.ROTZ, ControlType.rotate, TrackType.rotateZ); } else if (animation.RotationType == IORotationType.Quaternion) { // convert to euler AnimData rx = new AnimData(); rx.controlType = ControlType.rotate; rx.type = TrackType.rotateX; AnimData ry = new AnimData(); ry.controlType = ControlType.rotate; ry.type = TrackType.rotateY; AnimData rz = new AnimData(); rz.controlType = ControlType.rotate; rz.type = TrackType.rotateZ; rx.output = OutputType.angular; ry.output = OutputType.angular; rz.output = OutputType.angular; List <float> KeyFrames = new List <float>(); foreach (IOAnimKey key in ioAnimNode.GetKeysForTrack(IOTrackType.ROTX)) { KeyFrames.Add(key.Frame); } for (int i = 0; i < KeyFrames.Count; i++) { Vector3 EulerAngles = Tools.CrossMath.ToEulerAnglesXyz(ioAnimNode.GetQuaternionRotation(KeyFrames[i], b.Rotation)); rx.keys.Add(new AnimKey() { input = KeyFrames[i] + 1, output = EulerAngles.X, }); ry.keys.Add(new AnimKey() { input = KeyFrames[i] + 1, output = EulerAngles.Y, }); rz.keys.Add(new AnimKey() { input = KeyFrames[i] + 1, output = EulerAngles.Z, }); } if (rx.keys.Count > 0) { animBone.atts.Add(rx); animBone.atts.Add(ry); animBone.atts.Add(rz); } } // scale AddAnimData(animBone, ioAnimNode, IOTrackType.SCAX, ControlType.scale, TrackType.scaleX); AddAnimData(animBone, ioAnimNode, IOTrackType.SCAY, ControlType.scale, TrackType.scaleY); AddAnimData(animBone, ioAnimNode, IOTrackType.SCAZ, ControlType.scale, TrackType.scaleZ); } } anim.Save(fname); }
public static void ExportIOAnimationAsSMD(string FileName, IOAnimation Animation, RSkeleton Skeleton) { if (Skeleton == null) { return; } StringBuilder o = new StringBuilder(); o.AppendLine("version 1"); //skeleton { o.AppendLine("nodes"); foreach (RBone bone in Skeleton.Bones) { o.AppendLine($"{bone.ID} \"{bone.Name}\" {bone.ParentID}"); } o.AppendLine("end"); } //animation o.AppendLine("skeleton"); { for (int i = 0; i < Animation.FrameCount; i++) { o.AppendLine($"time {i}"); foreach (RBone bone in Skeleton.Bones) { Vector3 Position = bone.Position; Vector3 Rotation = bone.EulerRotation; if (Animation.TryGetNodeByName(bone.Name, out IOAnimNode Node)) { Position = Node.GetPosition(i, Position); Rotation = Tools.CrossMath.ToEulerAngles(Node.GetQuaternionRotation(i, bone.Rotation).Inverted()); } o.AppendLine($"{bone.ID} {Position.X} {Position.Y} {Position.Z} {Rotation.X} {Rotation.Y} {Rotation.Z}"); } } } o.AppendLine("end"); File.WriteAllText(FileName, o.ToString()); }
private void GetNodesForRendering(ref NumsbhNode meshNode, ref NuhlpbNode hlpbNode, ref RSkeleton skeleton, ref Matl material, Dictionary <string, SFGraphics.GLObjects.Textures.Texture> textureByName) { foreach (FileNode fileNode in Parent.Nodes) { if (fileNode is NuhlpbNode node) { hlpbNode = node; } else if (fileNode is NutexNode nutexNode) { var texture = (RTexture)nutexNode.GetRenderableNode(); textureByName[nutexNode.TexName.ToLower()] = texture.RenderTexture; } else if (fileNode.Text.Equals(model.MeshString)) { meshNode = (NumsbhNode)fileNode; } else if (fileNode.Text.Equals(model.SkeletonFileName)) { skeleton = (RSkeleton)((SkelNode)fileNode).GetRenderableNode(); } else if (fileNode.Text.Equals(model.MaterialFileNames[0].MaterialFileName)) { material = ((MatlNode)fileNode).Material; } } }