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

Onoty3D

Unityに関するメモとか

プロ生ちゃんの髪を伸ばす

ボーンの位置を動かすと、メッシュが連動して引き伸ばされます。
f:id:onoty3d:20150227110409p:plain
これを利用して、プロ生ちゃんの髪を伸ばすスクリプトを書いてみました。

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;

namespace PronamaChan
{
    public class HairExtender : MonoBehaviour
    {
        //後髪上部伸縮値
        [Range(0f, 0.1f)]
        public float ExtentionBackUpper = 0f;

        //後髪下部伸縮値
        [Range(0f, 2f)]
        public float ExtentionBackLower = 0f;

        //前髪右伸縮値
        [Range(-0.2f, 0.6f)]
        public float ExtentionFrontRight = 0f;

        //前髪左伸縮値
        [Range(-0.2f, 0.6f)]
        public float ExtentionFrontLeft = 0f;

        //直近の伸縮値
        private float _lastExtentionBackUpper;

        private float _lastExtentionBackLower;
        private float _lastExtentionFrontRight;
        private float _lastExtentionFrontLeft;

        //各部位のTransform
        private List<Transform> _backUpperHairs;

        private List<Transform> _backLowerHairs;
        private List<Transform> _frontRightHairs;
        private List<Transform> _frontLeftHairs;

        //初期X座標の保存用
        private List<float> _backUpperHairBaseXPositions;

        private List<float> _backHairLowerBaseXPositions;
        private List<float> _frontRightHairBaseXPositions;
        private List<float> _frontLeftHairBaseXPositions;

        private const string FRONT_RIGHT_HAIR_PATTERN = "_F0[1-6]$";
        private const string FRONT_LEFT_HAIR_PATTERN = "_F0[7-9]$";
        private const string BACK_LOWER_HAIR_PATTERN = "-2(_R|_L)?$";

        // Use this for initialization
        private void Start()
        {
            this._backUpperHairs = new List<Transform>();
            this._backLowerHairs = new List<Transform>();
            this._frontRightHairs = new List<Transform>();
            this._frontLeftHairs = new List<Transform>();

            this._backUpperHairBaseXPositions = new List<float>();
            this._backHairLowerBaseXPositions = new List<float>();
            this._frontRightHairBaseXPositions = new List<float>();
            this._frontLeftHairBaseXPositions = new List<float>();

            var hairs = this.GetComponentsInChildren<Transform>().Where(x => x.name.StartsWith("hair"));
            foreach (var hair in hairs)
            {
                if (Regex.IsMatch(hair.name, HairExtender.FRONT_RIGHT_HAIR_PATTERN))
                {
                    this._frontRightHairs.Add(hair);
                    this._frontRightHairBaseXPositions.Add(hair.localPosition.x);
                }
                else if (Regex.IsMatch(hair.name, HairExtender.FRONT_LEFT_HAIR_PATTERN))
                {
                    this._frontLeftHairs.Add(hair);
                    this._frontLeftHairBaseXPositions.Add(hair.localPosition.x);
                }
                else if (Regex.IsMatch(hair.name, HairExtender.BACK_LOWER_HAIR_PATTERN))
                {
                    this._backLowerHairs.Add(hair);
                    this._backHairLowerBaseXPositions.Add(hair.localPosition.x);
                }
                else
                {
                    this._backUpperHairs.Add(hair);
                    this._backUpperHairBaseXPositions.Add(hair.localPosition.x);
                }
            }
        }

        // Update is called once per frame
        private void Update()
        {
            if (this._lastExtentionBackUpper != this.ExtentionBackUpper)
            {
                this._lastExtentionBackUpper = this.ExtentionBackUpper;
                for (int i = 0; i < this._backUpperHairs.Count; i++)
                {
                    var position = this._backUpperHairs[i].localPosition;
                    position.x = this._backUpperHairBaseXPositions[i] + this._lastExtentionBackUpper;
                    this._backUpperHairs[i].localPosition = position;
                }
            }

            if (this._lastExtentionBackLower != this.ExtentionBackLower)
            {
                this._lastExtentionBackLower = this.ExtentionBackLower;
                for (int i = 0; i < this._backLowerHairs.Count; i++)
                {
                    var position = this._backLowerHairs[i].localPosition;
                    position.x = this._backHairLowerBaseXPositions[i] - this.ExtentionBackLower;
                    this._backLowerHairs[i].localPosition = position;
                }
            }

            if (this._lastExtentionFrontRight != this.ExtentionFrontRight)
            {
                this._lastExtentionFrontRight = this.ExtentionFrontRight;
                for (int i = 0; i < this._frontRightHairs.Count; i++)
                {
                    var position = this._frontRightHairs[i].localPosition;
                    position.x = this._frontRightHairBaseXPositions[i] + this._lastExtentionFrontRight;
                    this._frontRightHairs[i].localPosition = position;
                }
            }

            if (this._lastExtentionFrontLeft != this.ExtentionFrontLeft)
            {
                this._lastExtentionFrontLeft = this.ExtentionFrontLeft;
                for (int i = 0; i < this._frontLeftHairs.Count; i++)
                {
                    var position = this._frontLeftHairs[i].localPosition;
                    position.x = this._frontLeftHairBaseXPositions[i] + this._lastExtentionFrontLeft;
                    this._frontLeftHairs[i].localPosition = position;
                }
            }
        }
    }
}

プロ生ちゃんモデルに適用させてください。
f:id:onoty3d:20150227120824p:plain
後髪上部、後髪下部、前髪右、前髪左の単位で調整できるようにしています。
また、各設定値は振る舞いや見た目があまり崩れないような範囲でRange指定をしています。
もっと色々やりたい人は好きに改造しちゃってください。
f:id:onoty3d:20150227110440p:plain
今回はX座標しか操作しませんでしたが、3軸とも動かせるようにすればすれば、もっと不思議な髪型にできるかもしれません。

前髪左は伸ばすと髪留めまで伸びてしまいます。
気になるようでしたら、歯の色を変えた要領で、髪留めのMaterialに透明なMaterialを設定するのもいいかもしれません。