Esempio n. 1
0
        private PmxRigidBody ReadPmxRigidBody()
        {
            var body = new PmxRigidBody();

            body.Name        = ReadString() ?? string.Empty;
            body.NameEnglish = ReadString() ?? string.Empty;

            body.BoneIndex  = _reader.ReadVarLenIntAsInt32(BoneElementSize);
            body.GroupIndex = _reader.ReadByte(); // TODO: Signed? Unsigned?

            var bits      = _reader.ReadUInt16();
            var passGroup = PmxBodyPassGroup.FromFlagBits(bits);

            body.PassGroup = passGroup;

            body.BoundingBoxKind = (BoundingBoxKind)_reader.ReadByte();
            body.BoundingBoxSize = _reader.ReadVector3();
            body.Position        = _reader.ReadVector3();
            body.RotationAngles  = _reader.ReadVector3();
            body.Mass            = _reader.ReadSingle();
            body.PositionDamping = _reader.ReadSingle();
            body.RotationDamping = _reader.ReadSingle();
            body.Restitution     = _reader.ReadSingle();
            body.Friction        = _reader.ReadSingle();
            body.KineticMode     = (KineticMode)_reader.ReadByte();

            return(body);
        }
Esempio n. 2
0
        private void WritePmxRigidBody([NotNull] PmxRigidBody body)
        {
            WriteString(body.Name);
            WriteString(body.NameEnglish);

            _writer.WriteInt32AsVarLenInt(body.BoneIndex, BoneElementSize);
            _writer.Write((byte)body.GroupIndex);

            _writer.Write(body.PassGroup.ToFlagBits());

            _writer.Write((byte)body.BoundingBoxKind);
            _writer.Write(body.BoundingBoxSize);
            _writer.Write(body.Position);
            _writer.Write(body.RotationAngles);
            _writer.Write(body.Mass);
            _writer.Write(body.PositionDamping);
            _writer.Write(body.RotationDamping);
            _writer.Write(body.Restitution);
            _writer.Write(body.Friction);
            _writer.Write((byte)body.KineticMode);
        }
Esempio n. 3
0
            private void AppendStaticBodies([NotNull, ItemNotNull] PmxBone[] bones, [NotNull, ItemNotNull] SwayCollider[] swayColliders, [NotNull, ItemNotNull] List <PmxRigidBody> bodies)
            {
                foreach (var collider in swayColliders)
                {
                    var mltdBoneName = collider.Path;

                    if (mltdBoneName.Contains(BoneLookup.BoneNamePart_BodyScale))
                    {
                        mltdBoneName = mltdBoneName.Replace(BoneLookup.BoneNamePart_BodyScale, string.Empty);
                    }

                    var pmxBoneName = _pmxCreator._boneLookup.GetPmxBoneName(mltdBoneName);

                    var body = new PmxRigidBody();
                    var correspondingBone = bones.Find(o => o.Name == pmxBoneName);

                    Debug.Assert(correspondingBone != null, nameof(correspondingBone) + " != null");

                    body.Name        = correspondingBone.Name;
                    body.NameEnglish = correspondingBone.NameEnglish;

                    body.BoneIndex = correspondingBone.BoneIndex;

                    body.KineticMode = KineticMode.Static;

                    body.Mass            = 1;
                    body.PositionDamping = 0.9f;
                    body.RotationDamping = 1.0f;
                    body.Friction        = 0.0f;
                    body.Restitution     = 0.0f;

                    var part = GetBodyCoordSystemPart(collider);

                    body.Part = part;

                    switch (part)
                    {
                    case CoordSystemPart.Torso:
                        body.GroupIndex = PassGroupIndex.Torso;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        body.PassGroup.Pass(PassGroupIndex.Arms);
                        body.PassGroup.Pass(PassGroupIndex.Legs);
                        body.PassGroup.Pass(PassGroupIndex.Head);
                        break;

                    case CoordSystemPart.LeftArm:
                    case CoordSystemPart.RightArm:
                        body.GroupIndex = PassGroupIndex.Arms;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        body.PassGroup.Pass(PassGroupIndex.Arms);
                        body.PassGroup.Pass(PassGroupIndex.Legs);
                        body.PassGroup.Pass(PassGroupIndex.Head);
                        break;

                    case CoordSystemPart.Legs:
                        body.GroupIndex = PassGroupIndex.Legs;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        body.PassGroup.Pass(PassGroupIndex.Arms);
                        body.PassGroup.Pass(PassGroupIndex.Legs);
                        body.PassGroup.Pass(PassGroupIndex.Head);
                        break;

                    case CoordSystemPart.Head:
                        body.GroupIndex = PassGroupIndex.Head;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        body.PassGroup.Pass(PassGroupIndex.Arms);
                        body.PassGroup.Pass(PassGroupIndex.Legs);
                        body.PassGroup.Pass(PassGroupIndex.Head);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    switch (collider.Type)
                    {
                    case ColliderType.Sphere: {
                        body.BoundingBoxKind = BoundingBoxKind.Sphere;
                        body.BoundingBoxSize = new Vector3(collider.Radius, 0, 0);
                        body.Position        = correspondingBone.InitialPosition;
                    }
                    break;

                    case ColliderType.Capsule: {
                        body.BoundingBoxKind = BoundingBoxKind.Capsule;
                        body.BoundingBoxSize = new Vector3(collider.Radius, collider.Distance, 0);
                        body.RotationAngles  = MapRotation(part, collider.Axis);

                        var offset = MapTranslation(collider.Offset.ToOpenTK(), part, collider.Axis);

                        if (_pmxCreator._conversionConfig.ScaleToPmxSize)
                        {
                            offset = offset * _pmxCreator._scalingConfig.ScaleUnityToPmx;
                        }

                        body.Position = correspondingBone.InitialPosition + offset;
                    }
                    break;

                    case ColliderType.Plane:
                    case ColliderType.Bridge:
                        // TODO: How to handle these?
                        continue;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    if (_pmxCreator._conversionConfig.ScaleToPmxSize)
                    {
                        body.BoundingBoxSize = body.BoundingBoxSize * _pmxCreator._scalingConfig.ScaleUnityToPmx;
                    }

                    bodies.Add(body);
                }
            }
Esempio n. 4
0
            private void AppendSwayBones([NotNull, ItemNotNull] PmxBone[] bones, [NotNull, ItemNotNull] SwayBone[] swayBones, [NotNull, ItemNotNull] List <PmxRigidBody> bodies)
            {
                // "Semi-root" sway bones
                foreach (var swayBone in swayBones)
                {
                    var part = GetBodyCoordSystemPart(swayBone);

                    switch (part)
                    {
                    case CoordSystemPart.Torso:
                    case CoordSystemPart.LeftArm:
                    case CoordSystemPart.RightArm:
                    case CoordSystemPart.Legs:
                    case CoordSystemPart.Head:
                        continue;

                    case CoordSystemPart.Breasts:
                    case CoordSystemPart.Accessories:
                        continue;

                    case CoordSystemPart.Skirt:
                    case CoordSystemPart.Hair:
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    var guessedParentPath = swayBone.Path.BreakUntilLast('/');
                    var parentBody        = swayBones.Find(sb => sb.Path == guessedParentPath);

                    if (parentBody != null)
                    {
                        // This is a child rigid body.
                        continue;
                    }

                    var mltdBoneName = swayBone.Path;

                    if (mltdBoneName.Contains(BoneLookup.BoneNamePart_BodyScale))
                    {
                        mltdBoneName = mltdBoneName.Replace(BoneLookup.BoneNamePart_BodyScale, string.Empty);
                    }

                    var pmxBoneName = _pmxCreator._boneLookup.GetPmxBoneName(mltdBoneName);

                    var correspondingBone = bones.Find(o => o.Name == pmxBoneName);

                    if (correspondingBone == null)
                    {
                        Trace.WriteLine($"Warning: Semi-root sway bone is missing. Skipping this bone. PMX name: {pmxBoneName}; MLTD name: {mltdBoneName}");
                        continue;
                    }

                    var body = new PmxRigidBody();

                    body.Part = part;

                    body.BoneIndex = correspondingBone.BoneIndex;

                    body.Name        = correspondingBone.Name;
                    body.NameEnglish = correspondingBone.NameEnglish;

                    body.KineticMode = KineticMode.Dynamic;

                    body.Mass = ComputeMass(swayBone.Radius);

                    body.PositionDamping = 0.9f;
                    body.RotationDamping = 1.0f;
                    body.Friction        = 0.0f;
                    body.Restitution     = 0.0f;

                    switch (part)
                    {
                    case CoordSystemPart.Head:
                        body.GroupIndex = PassGroupIndex.Head;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        body.PassGroup.Pass(PassGroupIndex.Arms);
                        body.PassGroup.Pass(PassGroupIndex.Legs);
                        body.PassGroup.Pass(PassGroupIndex.Head);
                        break;

                    case CoordSystemPart.Hair:
                        body.GroupIndex = PassGroupIndex.Hair;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Head);
                        body.PassGroup.Pass(PassGroupIndex.Hair);
                        break;

                    case CoordSystemPart.Skirt:
                        body.GroupIndex = PassGroupIndex.Skirt;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Skirt);
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        break;

                    case CoordSystemPart.Breasts:
                        body.GroupIndex = PassGroupIndex.Breasts;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Breasts);
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        break;

                    case CoordSystemPart.Accessories:
                        body.GroupIndex = PassGroupIndex.Accessories;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Accessories);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    switch (swayBone.Type)
                    {
                    case ColliderType.Sphere: {
                        body.BoundingBoxKind = BoundingBoxKind.Sphere;
                        body.BoundingBoxSize = new Vector3(swayBone.Radius, 0, 0);

                        var childBone = bones.Find(bo => bo.ParentIndex == correspondingBone.BoneIndex);

                        Debug.Assert(childBone != null, nameof(childBone) + " != null");

                        body.Position = (correspondingBone.InitialPosition + childBone.InitialPosition) / 2;
                    }
                    break;

                    case ColliderType.Capsule:
                    case ColliderType.Plane:
                    case ColliderType.Bridge:
                        throw new ArgumentOutOfRangeException(nameof(swayBone.Type), swayBone.Type, "Only sphere colliders are supported in SwayBone.");

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    if (_pmxCreator._conversionConfig.ScaleToPmxSize)
                    {
                        body.BoundingBoxSize = body.BoundingBoxSize * _pmxCreator._scalingConfig.ScaleUnityToPmx;
                    }

                    bodies.Add(body);
                }

                // Normal sway bones
                foreach (var swayBone in swayBones)
                {
                    var mltdBoneName = swayBone.Path;

                    if (mltdBoneName.Contains(BoneLookup.BoneNamePart_BodyScale))
                    {
                        mltdBoneName = mltdBoneName.Replace(BoneLookup.BoneNamePart_BodyScale, string.Empty);
                    }

                    var pmxBoneName = _pmxCreator._boneLookup.GetPmxBoneName(mltdBoneName);

                    var body = new PmxRigidBody();
                    var part = GetBodyCoordSystemPart(swayBone);

                    body.Part = part;

                    var correspondingBone = bones.Find(o => o.Name == pmxBoneName);

                    if (correspondingBone == null)
                    {
                        Trace.WriteLine($"Warning: Normal sway bone is missing. Skipping this bone. PMX name: {pmxBoneName}; MLTD name: {mltdBoneName}");
                        continue;
                    }

                    switch (part)
                    {
                    case CoordSystemPart.Skirt:
                    case CoordSystemPart.Hair: {
                        var cb = correspondingBone;
                        correspondingBone = bones.Find(b => b.ParentIndex == cb.BoneIndex);
                        Debug.Assert(correspondingBone != null, "Normal sway (skirt/hair): " + nameof(correspondingBone) + " != null");
                        break;
                    }

                    case CoordSystemPart.Accessories:
                    case CoordSystemPart.Breasts:
                        break;
                    }

                    body.BoneIndex = correspondingBone.BoneIndex;

                    body.Name        = correspondingBone.Name;
                    body.NameEnglish = correspondingBone.NameEnglish;

                    switch (part)
                    {
                    case CoordSystemPart.Skirt:
                    case CoordSystemPart.Hair:
                        body.KineticMode = KineticMode.Dynamic;
                        break;

                    case CoordSystemPart.Accessories:
                    case CoordSystemPart.Breasts:
                        body.KineticMode = KineticMode.DynamicWithBone;
                        break;
                    }

                    body.Mass = ComputeMass(swayBone.Radius);

                    body.PositionDamping = 0.9f;
                    body.RotationDamping = 1.0f;
                    body.Friction        = 0.0f;
                    body.Restitution     = 0.0f;

                    switch (part)
                    {
                    case CoordSystemPart.Head:
                        body.GroupIndex = PassGroupIndex.Head;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        body.PassGroup.Pass(PassGroupIndex.Arms);
                        body.PassGroup.Pass(PassGroupIndex.Legs);
                        body.PassGroup.Pass(PassGroupIndex.Head);
                        break;

                    case CoordSystemPart.Hair:
                        body.GroupIndex = PassGroupIndex.Hair;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Hair);
                        body.PassGroup.Pass(PassGroupIndex.Head);
                        break;

                    case CoordSystemPart.Skirt:
                        body.GroupIndex = PassGroupIndex.Skirt;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Skirt);
                        break;

                    case CoordSystemPart.Breasts:
                        body.GroupIndex = PassGroupIndex.Breasts;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Breasts);
                        body.PassGroup.Pass(PassGroupIndex.Torso);
                        break;

                    case CoordSystemPart.Accessories:
                        body.GroupIndex = PassGroupIndex.Accessories;
                        body.PassGroup.BlockAll();
                        body.PassGroup.Pass(PassGroupIndex.Accessories);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    switch (swayBone.Type)
                    {
                    case ColliderType.Sphere: {
                        body.BoundingBoxKind = BoundingBoxKind.Sphere;
                        body.BoundingBoxSize = new Vector3(swayBone.Radius, 0, 0);

                        var childBone = bones.Find(bo => bo.ParentIndex == correspondingBone.BoneIndex);

                        if (childBone != null)
                        {
                            body.Position = (correspondingBone.InitialPosition + childBone.InitialPosition) / 2;
                        }
                        else
                        {
                            var parentBone = bones.Find(bo => bo.BoneIndex == correspondingBone.ParentIndex);

                            Debug.Assert(parentBone != null, nameof(parentBone) + " != null");

                            var delta = correspondingBone.InitialPosition - parentBone.InitialPosition;

                            body.Position = correspondingBone.InitialPosition + delta / 2;
                        }
                    }
                    break;

                    case ColliderType.Capsule:
                    case ColliderType.Plane:
                    case ColliderType.Bridge:
                        throw new ArgumentOutOfRangeException(nameof(swayBone.Type), swayBone.Type, "Only sphere colliders are supported in SwayBone.");

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    if (_pmxCreator._conversionConfig.ScaleToPmxSize)
                    {
                        body.BoundingBoxSize = body.BoundingBoxSize * _pmxCreator._scalingConfig.ScaleUnityToPmx;
                    }

                    bodies.Add(body);
                }
            }
Esempio n. 5
0
        private PmxModel ReadPmxModel()
        {
            var model = new PmxModel();

            model.Name           = ReadString() ?? string.Empty;
            model.NameEnglish    = ReadString() ?? string.Empty;
            model.Comment        = ReadString() ?? string.Empty;
            model.CommentEnglish = ReadString() ?? string.Empty;

            ReadVertexInfo();
            ReadFaceInfo();
            ReadTextureInfo();
            ReadMaterialInfo();
            ReadBoneInfo();
            ReadMorphInfo();
            ReadNodeInfo();
            ReadRigidBodyInfo();
            ReadJointInfo();
            ReadSoftBodyInfo();

            return(model);

            void ReadVertexInfo()
            {
                var vertexCount = _reader.ReadInt32();
                var vertices    = new PmxVertex[vertexCount];

                for (var i = 0; i < vertexCount; ++i)
                {
                    vertices[i] = ReadPmxVertex();
                }

                model.Vertices = vertices;
            }

            void ReadFaceInfo()
            {
                var faceCount   = _reader.ReadInt32();
                var faceIndices = new int[faceCount];

                for (var i = 0; i < faceCount; ++i)
                {
                    faceIndices[i] = _reader.ReadVarLenIntAsInt32(VertexElementSize, true);
                }

                model.FaceTriangles = faceIndices;
            }

            void ReadTextureInfo()
            {
                var textureCount       = _reader.ReadInt32();
                var textureNameMap     = new Dictionary <int, string>();
                var textureIndexLookup = new Dictionary <string, int>();

                for (var i = 0; i < textureCount; ++i)
                {
                    var textureName = ReadString() ?? string.Empty;
                    textureNameMap[i] = textureName;
                    textureIndexLookup[textureName] = i;
                }

                textureNameMap[-1] = string.Empty;

                TextureNameMap     = textureNameMap;
                TextureIndexLookup = textureIndexLookup;
            }

            void ReadMaterialInfo()
            {
                var materialCount = _reader.ReadInt32();
                var materials     = new PmxMaterial[materialCount];

                for (var i = 0; i < materialCount; ++i)
                {
                    materials[i] = ReadPmxMaterial();
                }

                model.Materials = materials;
            }

            void ReadBoneInfo()
            {
                var boneCount = _reader.ReadInt32();
                var bones     = new PmxBone[boneCount];

                for (var i = 0; i < boneCount; ++i)
                {
                    bones[i]           = ReadPmxBone();
                    bones[i].BoneIndex = i;
                }

                model.Bones           = bones;
                model.BonesDictionary = bones.ToDictionary(bone => bone.Name);

                var rootBoneIndexList = new List <int>();

                for (var i = 0; i < bones.Length; ++i)
                {
                    var bone = bones[i];

                    if (bone.ParentIndex < 0)
                    {
                        rootBoneIndexList.Add(i);
                    }
                    else
                    {
                        bone.Parent = bones[bone.ParentIndex];
                    }

                    if (bone.AppendParentIndex >= 0)
                    {
                        bone.AppendParent = bones[bone.AppendParentIndex];
                    }

                    if (bone.ExternalParentIndex >= 0)
                    {
                        bone.ExternalParent = bones[bone.ExternalParentIndex];
                    }

                    if (bone.HasFlag(BoneFlags.IK))
                    {
                        var ik = bone.IK;

                        Debug.Assert(ik != null, nameof(ik) + " != null");

                        ik.TargetBone = bones[ik.TargetBoneIndex];

                        foreach (var link in ik.Links)
                        {
                            if (link.BoneIndex >= 0)
                            {
                                link.Bone = bones[link.BoneIndex];
                            }
                        }
                    }
                }

                model.RootBoneIndices = rootBoneIndexList.ToArray();

                foreach (var bone in bones)
                {
                    bone.SetToBindingPose();
                }
            }

            void ReadMorphInfo()
            {
                var morphCount = _reader.ReadInt32();
                var morphs     = new PmxMorph[morphCount];

                for (var i = 0; i < morphCount; ++i)
                {
                    morphs[i] = ReadPmxMorph();
                }

                model.Morphs = morphs;
            }

            void ReadNodeInfo()
            {
                var nodeCount = _reader.ReadInt32();
                var nodes     = new PmxNode[nodeCount];

                for (var i = 0; i < nodeCount; ++i)
                {
                    var node = ReadPmxNode();

                    nodes[i] = node;

                    if (node.IsSystemNode)
                    {
                        if (node.Name == "Root")
                        {
                            model.RootNodeIndex = i;
                        }
                        else if (node.Name == "表情")
                        {
                            model.FacialExpressionNodeIndex = i;
                        }
                    }
                }

                model.Nodes = nodes;
            }

            void ReadRigidBodyInfo()
            {
                var bodyCount = _reader.ReadInt32();
                var bodies    = new PmxRigidBody[bodyCount];

                for (var i = 0; i < bodyCount; ++i)
                {
                    bodies[i] = ReadPmxRigidBody();
                }

                model.RigidBodies = bodies;
            }

            void ReadJointInfo()
            {
                var jointCount = _reader.ReadInt32();
                var joints     = new PmxJoint[jointCount];

                for (var i = 0; i < jointCount; ++i)
                {
                    joints[i] = ReadPmxJoint();
                }

                model.Joints = joints;
            }

            void ReadSoftBodyInfo()
            {
                if (DetailedVersion < 2.1f)
                {
                    return;
                }

                var bodyCount = _reader.ReadInt32();
                var bodies    = new PmxSoftBody[bodyCount];

                for (var i = 0; i < bodyCount; ++i)
                {
                    bodies[i] = ReadPmxSoftBody();
                }

                model.SoftBodies = bodies;
            }
        }