Skip to content

Instantly share code, notes, and snippets.

@onotchi
Created May 11, 2017 13:50
Show Gist options
  • Save onotchi/97078dd96293657dea5e7cb3efd72a67 to your computer and use it in GitHub Desktop.
Save onotchi/97078dd96293657dea5e7cb3efd72a67 to your computer and use it in GitHub Desktop.
メッシュの頂点を動かして、プロ生ちゃんの舌を操作する
using System.Linq;
using UnityEngine;
namespace PronamaChan
{
public class TongueMorph : MonoBehaviour
{
private class DefaultVertex
{
public int Index { get; set; }
public Vector3 Vertex { get; set; }
}
public SkinnedMeshRenderer SkinnedMeshRenderer;
public float Width = 1;
//前後移動
[Range(0, 4)]
public float MoveForward = 0;
//上下移動
[Range(0, 2)]
public float MoveUp = 0;
//縦回転中心
[Range(0, 1)]
public float VerticalRotationCenter = 0.5f;
//縦回転
[Range(-90, 90)]
public float VerticalRotation = 0;
//横回転
[Range(-90, 90)]
public float HorizontalRotation = 0;
//傾き
[Range(-90, 90)]
public float Inclination = 0;
public int TongueIndex;
private Vector3 _rotationCenter;
private float _verticalRotationCenterZero;
private float _verticalRotationCenterVolume;
private Mesh _mesh;
private DefaultVertex[] _defaultTongueVertices;
// Use this for initialization
private void Start()
{
//SkinnedMeshRendererの取得
if (this.SkinnedMeshRenderer == null)
{
this.SkinnedMeshRenderer = this.GetComponentInChildren<SkinnedMeshRenderer>();
}
//メッシュのクローンをSkinnedMeshRendererにセット
this._mesh = this.SkinnedMeshRenderer.sharedMesh;
this._mesh = GameObject.Instantiate(this._mesh);
this._mesh.MarkDynamic();
this.SkinnedMeshRenderer.sharedMesh = this._mesh;
//舌のサブメッシュのインデックスリスト取得
var triangles = this._mesh.GetTriangles(this.TongueIndex);
var trianglesUnique = triangles.Distinct().ToArray();
//舌の頂点位置保存
this._defaultTongueVertices = trianglesUnique.Select(x => new DefaultVertex { Index = x, Vertex = this._mesh.vertices[x] }).ToArray();
//回転中心の決定
var minMax = _defaultTongueVertices.Select(x => new { MinY = x.Vertex.y, MaxY = x.Vertex.y, MinZ = x.Vertex.z, MaxZ = x.Vertex.z })
.Aggregate((x, y) => new { MinY = Mathf.Min(x.MinY, y.MinY), MaxY = Mathf.Max(x.MaxY, y.MaxY), MinZ = Mathf.Min(x.MinZ, y.MinZ), MaxZ = Mathf.Max(x.MaxZ, y.MaxZ) });
this._rotationCenter = new Vector3(0, 0, (minMax.MinZ + minMax.MaxZ) / 2f);
this._verticalRotationCenterZero = minMax.MaxY;
this._verticalRotationCenterVolume = minMax.MaxY - minMax.MinY;
}
// Update is called once per frame
private void Update()
{
}
public void OnValidate()
{
if (this._defaultTongueVertices == null)
{
return;
}
//現在の頂点取得
var vertices = this._mesh.vertices;
foreach (var defaultVertex in this._defaultTongueVertices)
{
var newVertex = defaultVertex.Vertex;
//舌の幅の変更
newVertex.x *= this.Width;
//縦方向回転
{
//回転の中心を舌の根元から任意の位置に移動
var rotationCenterVertical = this._rotationCenter;
rotationCenterVertical.y = this._verticalRotationCenterZero - this._verticalRotationCenterVolume * this.VerticalRotationCenter;
//任意の位置から先だけを回転
if (defaultVertex.Vertex.y < rotationCenterVertical.y)
{
newVertex = Quaternion.Euler(this.VerticalRotation, 0, 0) * (newVertex - rotationCenterVertical) + rotationCenterVertical;
}
}
//横方向回転・傾き
newVertex = Quaternion.Euler(0, this.Inclination, this.HorizontalRotation) * (newVertex - this._rotationCenter) + this._rotationCenter;
//前後上下移動
newVertex.y += -this.MoveForward / 100.0f;
newVertex.z += this.MoveUp / 100.0f;
vertices[defaultVertex.Index] = newVertex;
}
this._mesh.vertices = vertices;
this._mesh.RecalculateNormals();
this._mesh.RecalculateBounds();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment