コード例 #1
0
 public CopyValueDirective(string raw, PmxMaterial source, string name, string dest) : base(raw)
 {
     if (!_keywords.Contains(name))
     {
         throw new ArgumentException(string.Format("{0} is not a valid keyword.", name), "name");
     }
     _name   = name;
     _dest   = dest;
     _source = source;
 }
コード例 #2
0
 /// <summary>
 /// Determines whether the specified material should be treated as transparent or opaque.
 /// </summary>
 /// <param name="material">The material in question.</param>
 /// <param name="texture">The material's diffuse texture, if any.</param>
 /// <param name="threshold">The threshold below which a color is considered transparent.</param>
 /// <returns>True if the diffuse color, or at least one pixel in the diffuse texture, is transparent. False otherwise.</returns>
 public static bool IsTransparent(PmxMaterial material, Texture2D texture = null, float threshold = 1.0f)
 {
     if (material.DiffuseColor.a < threshold)
     {
         return(true);
     }
     if (texture != null)
     {
         Color[] pixels = texture.GetPixels();
         for (int i = 0; i < pixels.Length; ++i)
         {
             if (pixels[i].a < threshold)
             {
                 return(true);
             }
         }
     }
     return(false);
 }
コード例 #3
0
 public MaterialDirectiveException(string message, PmxMaterial material, string directiveContent) : base(message)
 {
     Material  = material;
     Directive = directiveContent;
 }
コード例 #4
0
        public override void Execute(Material material)
        {
            switch (_name)
            {
            case "diffuse":
                material.SetColor(_dest, _source.DiffuseColor);
                break;

            case "ambient":
                material.SetColor(_dest, _source.AmbientColor);
                break;

            case "emissive":
                material.SetColor(_dest, _source.AmbientColor);
                break;

            case "specular":
                material.SetColor(_dest, _source.SpecularColor);
                break;

            case "smoothness":
                material.SetFloat(_dest, _source.SpecularExponent);
                break;

            case "exponent":
                material.SetFloat(_dest, _source.SpecularExponent);
                break;

            case "roughness":
                material.SetFloat(_dest, 1 - _source.SpecularExponent);
                break;

            case "edge":
                material.SetColor(_dest, _source.EdgeColor);
                break;

            case "edgesize":
                material.SetFloat(_dest, _source.EdgeSize);
                break;

            case "diffusetex":
                if (string.IsNullOrEmpty(_source.DiffuseTexturePath))
                {
                    break;
                }
                material.SetTexture(_dest, PmxMaterial.LoadTexture(_source.DiffuseTexturePath));
                break;

            case "spheretex":
                if (string.IsNullOrEmpty(_source.SphereTexturePath))
                {
                    break;
                }
                material.SetTexture(_dest, PmxMaterial.LoadTexture(_source.SphereTexturePath));
                break;

            case "sphereblend":
                material.SetInt(_dest, (int)_source.SphereBlending);
                break;

            case "toonindex":
                if (_source.ToonReference == PmxMaterial.ToonReferenceType.Internal)
                {
                    material.SetInt(_dest, _source.ToonInternalIndex);
                }
                break;

            case "toontex":
                if (_source.ToonReference == PmxMaterial.ToonReferenceType.Texture)
                {
                    material.SetTexture(_dest, PmxMaterial.LoadTexture(_source.ToonTexturePath));
                }
                break;
            }
        }
コード例 #5
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);
        }
コード例 #6
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
        }