読者です 読者をやめる 読者になる 読者になる

Onoty3D

Unityに関するメモとか

Unityでプロ生ちゃん新モデルのスパッツ・靴下・靴の表示を切り替える

プロ生ちゃん Unity MMD4Mecanim スクリプト

年末年始にかけて行われた、プロ生ちゃん3Dモデル強化プロジェクト、覚えていますでしょうか。
motion-gallery.net

現在着々とモデルが出来上がってきておりますが、通常頭身のMMDモデルは既に出資者に公開されており、先行利用が可能となっております。
f:id:onoty3d:20160425173928p:plain
f:id:onoty3d:20160425173944p:plain

今回からスパッツ、靴下、靴が材質モーフ表現へ変更となっており、これらパラメータを変更することで材質の表示・非表示が可能となっております。
MMD4MecanimでUnityに取り込んだ場合でもMMD4Mecanim標準のShaderを利用した場合はこれら材質モーフはきちんと表現可能です。
ただし、別のShaderを利用した場合は、下図の様にZファイティングしてしまいます。
(左がMMD4Mecanim標準のShader、右がToon/Lit Outline Shader)
f:id:onoty3d:20160425174017p:plain

このような場合でも、別途透明なマテリアルを用意して、非表示にしたい材質のマテリアルを手動でそれと置き換えればうまく表示はできます。
(材質モーフの様に靴下を50%表示・素足を50%表示…とかは出来ませんが、通常は0%か100%のいずれかしか使わないハズ)

手動でひとつひとつ置き換えるのも面倒なので、スクリプトを作成しました。ソースは最後。
透明なマテリアルだけ別途ご用意ください。
↓こんな感じで
f:id:onoty3d:20160425174101p:plain

スクリプトをプロ生ちゃんモデルに適用したら、TransprentMaterialに透明なマテリアル、SkinnedMeshにスパッツ等を含む方のSkinnedMeshRendererをセットしてください。
f:id:onoty3d:20160425175417p:plain
実行中にShow Spats/Socks/Shoesのチェックを切り替えることで表示が切り替えられます。
f:id:onoty3d:20160425174142g:plain

ソース

using System;
using System.Collections.Generic;
using UnityEngine;

namespace PronamaChan
{
    public class EquipmentsChanger : MonoBehaviour
    {
        public Material TransparentMaterial;
        public SkinnedMeshRenderer SkinnedMesh;

        public bool ShowSpats = false;
        public bool ShowSocks = true;
        public bool ShowShoes = true;

        private Dictionary<MaterialIndexes, Material> _materialsDic;

        private enum MaterialIndexes
        {
            /// <summary>パンツ</summary>
            Pants = 6,

            /// <summary>すね</summary>
            Shin = 13,

            /// <summary>つま先</summary>
            Toe = 14,

            /// <summary>太もも</summary>
            Thigh = 15,

            /// <summary>靴下すね</summary>
            SocksShin = 16,

            /// <summary>靴下つま先</summary>
            SocksToe = 17,

            /// <summary></summary>
            Shoes = 18,

            /// <summary>スパッツ</summary>
            Spats = 19,
        }

        /* TシャツVer.
        private enum MaterialIndexes
        {
            /// <summary>パンツ</summary>
            Pants = 2,

            /// <summary>すね</summary>
            Shin = 9,

            /// <summary>つま先</summary>
            Toe = 10,

            /// <summary>太もも</summary>
            Thigh = 11,

            /// <summary>靴下すね</summary>
            SocksShin = 12,

            /// <summary>靴下つま先</summary>
            SocksToe = 13,

            /// <summary>靴</summary>
            Shoes = 14,

            /// <summary>スパッツ</summary>
            Spats = 15,
        } */

        // Use this for initialization
        private void Start()
        {
            this.StoreMaterials();
            this.ChangeEquipments();
        }

        // Update is called once per frame
        private void Update()
        {
        }

        private void StoreMaterials()
        {
            this._materialsDic = new Dictionary<MaterialIndexes, Material>();
            var materials = this.SkinnedMesh.sharedMaterials;

            foreach (MaterialIndexes index in Enum.GetValues(typeof(MaterialIndexes)))
            {
                this._materialsDic[index] = materials[(int)index];
            }

            //スパッツのRenderQuereを太もものそれより大きくしておく
            this._materialsDic[MaterialIndexes.Spats].renderQueue = this._materialsDic[MaterialIndexes.Thigh].renderQueue + 1;
        }

        private void OnValidate()
        {
            this.ChangeEquipments();
        }

        private void ChangeEquipments()
        {
            if (_materialsDic == null) return;

            var renderer = this.SkinnedMesh.GetComponent<Renderer>();
            var materials = renderer.sharedMaterials;

            if (this.ShowSpats)
            {
                materials[(int)MaterialIndexes.Pants] = this.TransparentMaterial;
                materials[(int)MaterialIndexes.Thigh] = this.TransparentMaterial;
                materials[(int)MaterialIndexes.Spats] = this._materialsDic[MaterialIndexes.Spats];
            }
            else
            {
                materials[(int)MaterialIndexes.Pants] = this._materialsDic[MaterialIndexes.Pants];
                materials[(int)MaterialIndexes.Thigh] = this._materialsDic[MaterialIndexes.Thigh];
                materials[(int)MaterialIndexes.Spats] = this.TransparentMaterial;
            }

            if (this.ShowSocks)
            {
                materials[(int)MaterialIndexes.Shin] = this.TransparentMaterial;
                materials[(int)MaterialIndexes.Toe] = this.TransparentMaterial;
                materials[(int)MaterialIndexes.SocksShin] = this._materialsDic[MaterialIndexes.SocksShin];

                if (this.ShowShoes)
                {
                    materials[(int)MaterialIndexes.SocksToe] = this.TransparentMaterial;
                    materials[(int)MaterialIndexes.Shoes] = this._materialsDic[MaterialIndexes.Shoes];
                }
                else
                {
                    materials[(int)MaterialIndexes.SocksToe] = this._materialsDic[MaterialIndexes.SocksToe];
                    materials[(int)MaterialIndexes.Shoes] = this.TransparentMaterial;
                }
            }
            else
            {
                materials[(int)MaterialIndexes.Shin] = this._materialsDic[MaterialIndexes.Shin];
                materials[(int)MaterialIndexes.SocksShin] = this.TransparentMaterial;
                materials[(int)MaterialIndexes.SocksToe] = this.TransparentMaterial;

                if (this.ShowShoes)
                {
                    materials[(int)MaterialIndexes.Toe] = this.TransparentMaterial;
                    materials[(int)MaterialIndexes.Shoes] = this._materialsDic[MaterialIndexes.Shoes];
                }
                else
                {
                    materials[(int)MaterialIndexes.Toe] = this._materialsDic[MaterialIndexes.Toe];
                    materials[(int)MaterialIndexes.Shoes] = this.TransparentMaterial;
                }
            }

            renderer.sharedMaterials = materials;
        }
    }
}