Exemplo n.º 1
0
        public static GameObject BuildHierarchy(PmxBone bone, IEnumerable <PmxBone> coll, List <Transform> appendList, GameObject sprite)
        {
            GameObject root = GameObject.Instantiate <GameObject>(sprite);

            appendList.Add(root.transform);
            bone.UnityObject = root;

            BoneSpriteBehaviour comp = root.GetComponent <BoneSpriteBehaviour>();

            if (!bone.HasFlag(PmxBone.BoneFlags.Visible))
            {
                comp.Icon = BoneSpriteBehaviour.IconType.Invisible;
            }
            else if (bone.HasFlag(PmxBone.BoneFlags.FixedAxis))
            {
                comp.Icon = BoneSpriteBehaviour.IconType.Twist;
            }
            else if (bone.HasFlag(PmxBone.BoneFlags.Translation))
            {
                comp.Icon = BoneSpriteBehaviour.IconType.Translation;
            }

            root.layer = LayerMask.NameToLayer("UISprites");
            root.name  = bone.Name;
            PmxBone[] children = bone.Children(coll);
            for (int i = 0; i < children.Length; ++i)
            {
                GameObject child = BuildHierarchy(children[i], coll, appendList, sprite);
                child.transform.SetParent(root.transform, true);
                child.transform.position = children[i].Position - bone.Position;
            }
            return(root);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Reads a bone structure from teh file and advances the stream position to the next item.
        /// </summary>
        /// <param name="encoding">The text encoding to use when reading strings.</param>
        /// <returns>The next bone in the PMX file.</returns>
        public static PmxBone ReadPmxBone(this BinaryReader reader, System.Text.Encoding encoding)
        {
            PmxBone bone = new PmxBone(reader.ReadPmxString(encoding), reader.ReadPmxString(encoding));

            bone.Position = reader.ReadVector3();
            bone.Parent   = reader.ReadIndex(PmxTypes.IndexType.Bone);
            bone.Layer    = reader.ReadInt32();
            bone.Flags    = (PmxBone.BoneFlags)reader.ReadInt16();

            // Tail
            if (bone.HasFlag(PmxBone.BoneFlags.TailIsIndex))
            {
                bone.TailIndex = reader.ReadIndex(PmxTypes.IndexType.Bone);
            }
            else
            {
                bone.TailPosition = reader.ReadVector3();
            }

            // Inherit
            if (bone.HasFlag(PmxBone.BoneFlags.InheritRotation | PmxBone.BoneFlags.InheritTranslation))
            {
                bone.InheritFromIndex = reader.ReadIndex(PmxTypes.IndexType.Bone);
                bone.InheritWeight    = reader.ReadSingle();
            }

            // Fixed axis
            if (bone.HasFlag(PmxBone.BoneFlags.FixedAxis))
            {
                bone.FixedAxis = reader.ReadVector3();
            }

            // Local transformation
            if (bone.HasFlag(PmxBone.BoneFlags.LocalTransform))
            {
                bone.LocalX = reader.ReadVector3();
                bone.LocalZ = reader.ReadVector3();
            }

            // Outside parent
            if (bone.HasFlag(PmxBone.BoneFlags.ExternalDeform))
            {
                bone.ExternalParentIndex = reader.ReadIndex(PmxTypes.IndexType.Bone);
            }

            // IK
            if (bone.HasFlag(PmxBone.BoneFlags.IK))
            {
                bone.IK             = new PmxIK();
                bone.IK.TargetIndex = reader.ReadIndex(PmxTypes.IndexType.Bone);
                bone.IK.Loop        = reader.ReadInt32();
                bone.IK.Limit       = reader.ReadSingle();
                int linkCount = reader.ReadInt32();
                bone.IK.Links = new List <PmxIKLink>();
                for (int j = 0; j < linkCount; ++j)
                {
                    PmxIKLink link = new PmxIKLink();
                    link.Index    = reader.ReadIndex(PmxTypes.IndexType.Bone);
                    link.HasLimit = reader.ReadByte() != 0;
                    if (link.HasLimit)
                    {
                        link.EulerLimitMin = reader.ReadVector3();
                        link.EulerLimitMax = reader.ReadVector3();
                    }
                    else
                    {
                        link.EulerLimitMin = new Vector3();
                        link.EulerLimitMax = new Vector3();
                    }
                    bone.IK.Links.Add(link);
                }
            }
            return(bone);
        }
Exemplo n.º 3
0
        // Unity
        /// <summary>
        /// Convert the PMX model into Unity meshes with correct materials.
        /// </summary>
        /// <returns>A parent GameObject that holds the sub-meshes in its children.</returns>
        public GameObject GetGameObject()
        {
            bool cancel = false;

            GameObject root        = new GameObject(Name);
            GameObject modelParent = new GameObject("Model");
            GameObject boneParent  = new GameObject("Skeleton");

            Material   baseOpaque       = Resources.Load <Material>("Materials/DefaultMaterial");
            Material   baseTransparent  = Resources.Load <Material>("Materials/DefaultMaterialTransparent");
            Material   baseFade         = Resources.Load <Material>("Materials/DefaultMaterialFade");
            Material   baseCutout       = Resources.Load <Material>("Materials/DefaultMaterialCutout");
            GameObject boneSpritePrefab = Resources.Load <GameObject>("Prefabs/BoneSprite");

            List <Transform> boneObjectList = new List <Transform>();

            // Skeleton... recursion is recursion.
            foreach (PmxBone rootBone in PmxBone.RootBones(Bones))
            {
                GameObject rootBoneObject = BoneHierarchy.BuildHierarchy(rootBone, Bones, boneObjectList, boneSpritePrefab);
                boneObjectList.Add(rootBoneObject.transform);
                rootBoneObject.transform.SetParent(boneParent.transform);
                rootBoneObject.transform.position = rootBone.Position;
            }

            // Model
            for (int i = 0; i < Materials.Count; ++i)
            {
                PmxMaterial mat = Materials[i];
                GameObject  o   = new GameObject(string.Format("{0} ({1})", Name, mat.NameJapanese));

                // MESH

                List <PmxVertex>  vert      = new List <PmxVertex>();           // List of vertices that make up the sub-model
                List <int>        tri       = new List <int>();                 // Every index corresponds to an index in vert
                List <BoneWeight> weights   = new List <BoneWeight>();
                List <Matrix4x4>  bindposes = new List <Matrix4x4>();
                foreach (PmxTriangle t in mat.Triangles(Triangles))
                {
                    vert.Add(Vertices[t.Vertex1]);
                    tri.Add(vert.Count - 1);
                    vert.Add(Vertices[t.Vertex2]);
                    tri.Add(vert.Count - 1);
                    vert.Add(Vertices[t.Vertex3]);
                    tri.Add(vert.Count - 1);
                    weights.Add(Vertices[t.Vertex1].DeformData.GetUnityWeight());
                    bindposes.Add(boneObjectList[weights[weights.Count - 1].boneIndex0].worldToLocalMatrix);
                    weights.Add(Vertices[t.Vertex2].DeformData.GetUnityWeight());
                    bindposes.Add(boneObjectList[weights[weights.Count - 1].boneIndex0].worldToLocalMatrix);
                    weights.Add(Vertices[t.Vertex3].DeformData.GetUnityWeight());
                    bindposes.Add(boneObjectList[weights[weights.Count - 1].boneIndex0].worldToLocalMatrix);
                }

                Mesh mesh = new Mesh();
                mesh.name        = mat.NameJapanese;
                mesh.vertices    = PmxVertex.GetPositions(vert).ToArray();
                mesh.normals     = PmxVertex.GetNormals(vert).ToArray();
                mesh.uv          = PmxVertex.GetUVs(vert).ToArray();
                mesh.triangles   = tri.ToArray();
                mesh.boneWeights = weights.ToArray();
                mesh.bindposes   = bindposes.ToArray();
                o.AddComponent <MeshFilter>().sharedMesh = mesh;
                SkinnedMeshRenderer renderer = o.AddComponent <SkinnedMeshRenderer>();
                renderer.sharedMesh          = mesh;
                renderer.updateWhenOffscreen = true;
                renderer.bones = boneObjectList.ToArray();

                // SKELETON


                // MATERIAL

                // Texture
                Texture2D tex = null;
                if (!string.IsNullOrEmpty(mat.DiffuseTexturePath))
                {
                    string path = Path.Combine(Path.GetDirectoryName(FilePath), mat.DiffuseTexturePath);
                    if (File.Exists(path))
                    {
                        tex = PmxMaterial.LoadTexture(path);
                    }
                }

                // Execute early rendering mode directives
                RenderModeDirective.RenderMode mode = RenderModeDirective.RenderMode.Opaque;
                foreach (RenderModeDirective dir in mat.Directives.OfType <RenderModeDirective>())
                {
                    mode = dir.Mode;
                    if (dir.AutoDetect)
                    {
                        if (!PmxMaterial.IsTransparent(mat, tex, dir.Threshold))
                        {
                            mode = RenderModeDirective.RenderMode.Opaque;
                        }
                    }
                }

                // Set up material

                Material material;
                switch (mode)
                {
                case RenderModeDirective.RenderMode.Cutout:
                    material = Material.Instantiate <Material>(baseCutout);
                    break;

                case RenderModeDirective.RenderMode.Fade:
                    material = Material.Instantiate <Material>(baseFade);
                    break;

                case RenderModeDirective.RenderMode.Transparent:
                    material = Material.Instantiate <Material>(baseTransparent);
                    break;

                default:
                    material = Material.Instantiate <Material>(baseOpaque);
                    break;
                }

                material.name  = mat.NameJapanese;
                material.color = mat.DiffuseColor;
                if (tex != null)
                {
                    material.mainTexture = tex;
                }

                // Execute directives
                foreach (MaterialDirective dir in mat.Directives)
                {
                    dir.Execute(material);
                }

                // Set up GameObject and components
                renderer.sharedMaterial    = material;
                renderer.shadowCastingMode = mat.HasFlag(PmxMaterial.MaterialFlags.CastShadow | PmxMaterial.MaterialFlags.GroundShadow) ? ShadowCastingMode.On : ShadowCastingMode.Off;
                //renderer.receiveShadows = mat.HasFlag(PmxMaterial.MaterialFlags.ReceiveShadow);

                // Execute renderer directives
                foreach (MaterialDirective dir in mat.Directives)
                {
                    dir.Execute(renderer);
                }

                o.transform.SetParent(modelParent.transform);
                if (cancel)
                {
                    break;
                }
            }

            modelParent.transform.SetParent(root.transform);
            boneParent.transform.SetParent(root.transform);

            // Release loaded prefabs - source of memory leak? unneeded?
            //GameObject.Destroy(baseOpaque);
            //GameObject.Destroy(baseTransparent);
            //GameObject.Destroy(baseFade);
            //GameObject.Destroy(baseCutout);
            //GameObject.Destroy(boneSpritePrefab);

            if (cancel)
            {
                GameObject.Destroy(root);
                return(null);
            }
            return(root);
        }
Exemplo n.º 4
0
        // Loading
#pragma warning disable 0162
        /// <summary>
        /// Read and process the file.
        /// </summary>
        /// <param name="r">The binary reader pointing at the PMX file.</param>
        private void LoadPmx(BinaryReader r)
        {
            #region Header
            // Signature (4)
            byte[] sig = r.ReadBytes(PmxConstants.SignatureLength);
            if (!sig.ValidatePmxSignature())
            {
                throw new PmxSignatureException(sig);
            }

            // Version (4)
            float parsedVersion = r.ReadSingle();
            if (parsedVersion == 2.0f)
            {
                Version = PmxVersion.Pmx20;
            }
            else if (parsedVersion == 2.1f)
            {
                Version = PmxVersion.Pmx21;
            }

            // Globals (9)
            r.ReadByte();                           // This is always 8 in PMX 2.0, safe to ignore
            TextEncoding            = r.ReadByte() == 0 ? Encoding.Unicode : Encoding.UTF8;
            AdditionalUVCount       = r.ReadByte(); // 0 to 4
            PmxTypes.VertexIndex    = r.ReadByte(); // Vertex index types are byte (1), ushort (2) or int (4)
            PmxTypes.TextureIndex   = r.ReadByte(); // All other index types are sbyte (1), short (2) or int (4)
            PmxTypes.MaterialIndex  = r.ReadByte();
            PmxTypes.BoneIndex      = r.ReadByte();
            PmxTypes.MorphIndex     = r.ReadByte();
            PmxTypes.RigidbodyIndex = r.ReadByte();

            // Model information
            NameJapanese = r.ReadPmxString(TextEncoding);
            NameEnglish  = r.ReadPmxString(TextEncoding);
            InfoJapanese = r.ReadPmxString(TextEncoding);
            InfoEnglish  = r.ReadPmxString(TextEncoding);
            #endregion
            #region Vertex data
            Vertices = new List <PmxVertex>(r.ReadInt32());
            for (int i = 0; i < Vertices.Capacity; ++i)
            {
                // Standard vectors
                PmxVertex v = new PmxVertex();
                v.Position = r.ReadVector3();
                v.Normal   = r.ReadVector3();
                v.UV       = r.ReadVector2() * new Vector2(1, -1);
                // Additional UV
                v.UVAdditional = new List <Vector4>(AdditionalUVCount);
                for (int j = 0; j < AdditionalUVCount; ++j)
                {
                    v.UVAdditional.Add(r.ReadVector4());
                }
                // Deform
                byte deformID = r.ReadByte();
                switch (deformID)
                {
                case 0:                         // BDEF1
                    v.DeformData = new Bdef1Deform(r.ReadIndex(PmxTypes.IndexType.Bone));
                    break;

                case 1:                         // BDEF2
                    v.DeformData = new Bdef2Deform(r.ReadIndex(PmxTypes.IndexType.Bone), r.ReadIndex(PmxTypes.IndexType.Bone), r.ReadSingle());
                    break;

                case 2:                         // BDEF4
                    v.DeformData = new Bdef4Deform()
                    {
                        Bone1   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Bone2   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Bone3   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Bone4   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Weight1 = r.ReadSingle(),
                        Weight2 = r.ReadSingle(),
                        Weight3 = r.ReadSingle(),
                        Weight4 = r.ReadSingle(),
                    };
                    break;

                case 3:                         // SDEF
                    v.DeformData = new SdefDeform()
                    {
                        Bone1   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Bone2   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Weight1 = r.ReadSingle(),
                        C       = r.ReadVector3(),
                        R0      = r.ReadVector3(),
                        R1      = r.ReadVector3()
                    };
                    break;

                case 4:                         // QDEF
                    v.DeformData = new QdefDeform()
                    {
                        Bone1   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Bone2   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Bone3   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Bone4   = r.ReadIndex(PmxTypes.IndexType.Bone),
                        Weight1 = r.ReadSingle(),
                        Weight2 = r.ReadSingle(),
                        Weight3 = r.ReadSingle(),
                        Weight4 = r.ReadSingle(),
                    };
                    break;

                default:
                    throw new PmxDeformException(deformID);
                }
                v.EdgeSize = r.ReadSingle();

                Vertices.Add(v);
            }
            #endregion
            #region Triangle data
            int trianglePointCount = r.ReadInt32();
            if ((trianglePointCount % 3) != 0)
            {
                throw new PmxFormatException(string.Format("The triangle count is incorrect. Expected divisible by 3, got {0} (remainder {1})", trianglePointCount, trianglePointCount % 3));
            }
            Triangles = new List <PmxTriangle>(trianglePointCount / 3);
            for (int i = 0; i < Triangles.Capacity; ++i)
            {
                PmxTriangle tri = new PmxTriangle(r.ReadIndex(PmxTypes.IndexType.Vertex), r.ReadIndex(PmxTypes.IndexType.Vertex), r.ReadIndex(PmxTypes.IndexType.Vertex));
                Triangles.Add(tri);
            }
            #endregion
            #region Texture list
            Textures = new List <string>(r.ReadInt32());
            for (int i = 0; i < Textures.Capacity; ++i)
            {
                Textures.Add(r.ReadPmxString(TextEncoding));
            }
            #endregion
            #region Material data
            int assignedVertices = 0;
            Materials = new List <PmxMaterial>(r.ReadInt32());
            for (int i = 0; i < Materials.Capacity; ++i)
            {
                PmxMaterial m = new PmxMaterial(r.ReadPmxString(TextEncoding), r.ReadPmxString(TextEncoding));
                // Colors
                m.DiffuseColor     = r.ReadColor4();
                m.SpecularColor    = r.ReadColor3();
                m.SpecularExponent = r.ReadSingle();
                m.AmbientColor     = r.ReadColor3();
                // Properties
                m.Flags     = (PmxMaterial.MaterialFlags)r.ReadByte();
                m.EdgeColor = r.ReadColor4();
                m.EdgeSize  = r.ReadSingle();
                // Textures
                int index = r.ReadIndex(PmxTypes.IndexType.Texture);
                m.DiffuseTexturePath = index < 0 ? "" : Textures[index];
                index = r.ReadIndex(PmxTypes.IndexType.Texture);
                m.SphereTexturePath = index < 0 ? "" : Textures[index];
                m.SphereBlending    = (PmxMaterial.SphereBlendingMode)r.ReadByte();
                m.ToonReference     = (PmxMaterial.ToonReferenceType)r.ReadByte();
                if (m.ToonReference == PmxMaterial.ToonReferenceType.Internal)
                {
                    index = r.ReadIndex(PmxTypes.IndexType.Texture);
                    try
                    {
                        m.ToonTexturePath = index < 0 ? "" : Textures[index];
                    }
                    catch { }
                }
                else
                {
                    m.ToonInternalIndex = r.ReadByte();
                }
                // Comment
                m.Note = r.ReadPmxString(TextEncoding);
                // Surfaces
                m.FirstVertex     = assignedVertices;
                m.VertexCount     = r.ReadInt32();
                assignedVertices += m.VertexCount;
                Materials.Add(m);
            }
            #endregion
            #region Bone data
            Bones = new List <PmxBone>(r.ReadInt32());
            for (int i = 0; i < Bones.Capacity; ++i)
            {
                PmxBone bone = r.ReadPmxBone(TextEncoding);
                bone.Index = Bones.Count;
                Bones.Add(bone);
            }
            #endregion
            #region Morph data
            Morphs = new List <PmxMorph>(r.ReadInt32());
            for (int i = 0; i < Morphs.Capacity; ++i)
            {
                Morphs.Add(r.ReadPmxMorph(TextEncoding));
            }
            #endregion
            // SKIP FROM HERE
            r.Close(); return;

            #region Frame data

            #endregion
            #region Rigidbody data

            #endregion
            #region Joint data

            #endregion
            #region Soft body data

            #endregion
        }