zoukankan      html  css  js  c++  java
  • unity, editable mesh

    一,需求

    从fbx载入的模型是不可以在unity里编辑的。

    我有一人特殊的需求就是想在unity里为mesh的各顶点K动画。

    于是需要自己实现一个可编辑(其实只是顶点可以拖动)的mesh。

    二,思路

    首先由导入的mesh复制一个新mesh,并将原mesh替换掉,这样是为了以后编辑过程不会破坏原mesh,然后就没有原mesh的事儿了。

    假设mesh是一个立方体,则其mesh.vertices会有36个元素,mesh.triangles有12个元素。

    我们要创建8个gameObject表示立方体的8个顶点gameObject,并根据mesh.vertices的坐标值设定顶点gameObject的localPosition(注意是localPosition而不是position),并且还要找出各顶点gameObject对象mesh.vertcies中的哪些元素。因为一共有8个顶点gameObject,但mesh.vertices有36个元素,所以一个gameObject对应多个元素。

    三,unity里实现

    1,创建一个gameObject,命句为editableMesh,并添加Mesh Filter和Mesh Renderer,Mesh Filter中添加模型mesh(例如从3dmax或blender中导出的模型)。

    2,为editableMesh节点添加子节点vertexObjTemplate并将勾去掉使其变成Active==false状态,其上挂脚本vertexobjControl.cs:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    public class vertexObjControl : MonoBehaviour {
        public List<int> m_vIDList=new List<int>();
    }

    3,为editableMesh节点添加脚本convertmeshToEditableMesh.cs

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine.Assertions.Must;
    [ExecuteInEditMode]
    public class convertMeshToEditableMesh : MonoBehaviour {
        private GameObject m_vertexObjs;
        private GameObject m_vertexObjTemplate;
        void Awake(){
            m_vertexObjTemplate=transform.FindChild("vertexObjTemplate").gameObject;

            CreateReplaceMeshFromOriginMesh ();
        }
        void Update(){
            updateMeshVertex ();
        }
        void updateMeshVertex(){
            int vertexCount = gameObject.GetComponent<MeshFilter> ().sharedMesh.vertexCount;
            Vector3[] vertices = new Vector3[vertexCount] ;

            int vertexObjCount = m_vertexObjs.transform.childCount;
            for (int i=0; i<vertexObjCount; i++) {
                GameObject vobj=m_vertexObjs.transform.GetChild(i).gameObject;
                Vector3 vobjPos=vobj.transform.localPosition;
                int nVID=vobj.GetComponent<vertexObjControl>().m_vIDList.Count;
                for(int j=0;j<nVID;j++){
                    int vID=vobj.GetComponent<vertexObjControl>().m_vIDList[j];
                    vertices[vID]=vobjPos;
                }
            }
            gameObject.GetComponent<MeshFilter> ().sharedMesh.vertices = vertices;


            gameObject.GetComponent<MeshFilter> ().sharedMesh.RecalculateNormals();
            gameObject.GetComponent<MeshFilter> ().sharedMesh.RecalculateBounds();
        }
        void CreateReplaceMeshFromOriginMesh()
        {
            //if vertexObjs is not created, create it
            Transform vertexObjsTransform=transform.FindChild("vertexObjs");
            if (vertexObjsTransform == null) {
                m_vertexObjs = new GameObject ();
                m_vertexObjs.name = "vertexObjs";
                m_vertexObjs.transform.SetParent (gameObject.transform);
            } else {
                m_vertexObjs=vertexObjsTransform.gameObject;
            }

            //if mesh not replaced, replace it
            if (gameObject.GetComponent<MeshFilter> ().sharedMesh.name != "replaceMesh") {
                Mesh replaceMesh = Instantiate (gameObject.GetComponent<MeshFilter> ().sharedMesh) as Mesh;
                replaceMesh.name = "replaceMesh";
                gameObject.GetComponent<MeshFilter> ().sharedMesh = replaceMesh;
            }


            //if vobjs not generated, generate vobjs from replaved mesh
            if (m_vertexObjs.transform.childCount == 0) {
                int vertexCount = gameObject.GetComponent<MeshFilter> ().sharedMesh.vertexCount;
                List<bool> list_isVIDHasAddedToVObj = new List<bool> ();
                for (int i=0; i<vertexCount; i++) {
                    list_isVIDHasAddedToVObj.Add (false);
                }
                for (int vID=0; vID<vertexCount; vID++) {
                    if (list_isVIDHasAddedToVObj [vID]) {
                        continue;
                    }
                    //add vID of current vertex to existing vertexObj

                    Vector3 vPos = gameObject.GetComponent<MeshFilter> ().sharedMesh.vertices [vID];
                    int vertexObjCount = m_vertexObjs.transform.childCount;
                    for (int vobjID=0; vobjID<vertexObjCount; vobjID++) {
                        GameObject vobj = m_vertexObjs.transform.GetChild (vobjID).gameObject;
                        Vector3 vobjPos = vobj.transform.localPosition;
                        if (vPos == vobjPos) {
                            //add vID to vobj
                            vobj.GetComponent<vertexObjControl> ().m_vIDList.Add (vID);
                            list_isVIDHasAddedToVObj [vID] = true;
                        }
                    }
                    if (list_isVIDHasAddedToVObj [vID]) {//vID has added to existing vobj
                        //do nothing

                    } else {//no existing vobj for vID to add to
                        //create new vobj, and add vID to it
                        GameObject vobj = Instantiate (m_vertexObjTemplate);
                        vobj.SetActive (true);
                        vobj.name = "vobj_" + m_vertexObjs.transform.childCount;
                        vobj.transform.SetParent (m_vertexObjs.transform);
                        vobj.transform.localPosition = vPos;
                        vobj.GetComponent<vertexObjControl> ().m_vIDList.Add (vID);
                        list_isVIDHasAddedToVObj [vID] = true;
                    }

                }
            }
            gameObject.GetComponent<MeshFilter> ().sharedMesh.RecalculateNormals();
            gameObject.GetComponent<MeshFilter> ().sharedMesh.RecalculateBounds();
        }
    }

    然后就可以在编辑器里移动mesh的顶点或给顶点K动画了。

    ----补充:

    以上是通用的代码,可将任何mesh转成可编辑(只是移动顶点)的。

    如果只想做一个可编辑的四边形面片,可以像下面这样简单实现:

    1,创建一个gameObject命名为editableQuad。为editableQuad创建子节点vertexObjs。再为vertexObjs依次创建子节点vertexObj_0,vertexObj_1,vertexObj_2,vertexObj_3(按顺序排列)。

    2,再为editableQuad添加脚本editableQuadControl.cs:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine.Assertions.Must;
    [ExecuteInEditMode]
    public class editableQuadControl : MonoBehaviour {
        private GameObject vertexObjs;
        void Awake(){

            vertexObjs=transform.FindChild("vertexObjs").gameObject;
            int childCount = vertexObjs.transform.childCount;
            int n = 4;

            for (int i=0; i<n; i++) {
                if(i>=childCount){
                    GameObject vertexObj=new GameObject ();
                    vertexObj.name="vertexObj_"+i;
                    vertexObj.transform.SetParent(vertexObjs.transform);
                    vertexObj.transform.localPosition=Random.insideUnitSphere;
                }
            }
            gameObject.GetComponent<MeshFilter> ().mesh = CreateMesh ();
        }
        void Update(){
            updateMeshVertex ();
        }
        void updateMeshVertex(){
            Vector3 vLU = vertexObjs.transform.GetChild(0).localPosition;
            Vector3 vLD = vertexObjs.transform.GetChild(1).localPosition;
            Vector3 vRU = vertexObjs.transform.GetChild(2).localPosition;
            Vector3 vRD = vertexObjs.transform.GetChild(3).localPosition;
            gameObject.GetComponent<MeshFilter> ().sharedMesh.vertices = new Vector3[]{vLD,vLU,vRU,vRD};
        }
        Mesh CreateMesh()
        {
            Mesh m = new Mesh();
            m.name = "ScriptedMesh";
            //note: unity is left-hand system
            Vector3 vLU = vertexObjs.transform.GetChild(0).localPosition;
            Vector3 vLD = vertexObjs.transform.GetChild(1).localPosition;
            Vector3 vRU = vertexObjs.transform.GetChild(2).localPosition;
            Vector3 vRD = vertexObjs.transform.GetChild(3).localPosition;
            m.vertices = new Vector3[] {
                vLD,//LD
                vLU,//LU
                vRU,//RU
                vRD//RD
            };
            m.uv = new Vector2[] {
                new Vector2 (0, 0),
                new Vector2 (0, 1),
                new Vector2 (1, 1),
                new Vector2 (1, 0)
            };
            m.triangles = new int[] { 0, 1, 2, 0, 2, 3};
            m.RecalculateNormals();
            m.RecalculateBounds();
            return m;
        }
    }

  • 相关阅读:
    解决Qt creator无法输入中文
    JSP 问题总结
    oracle锁与死锁概念,阻塞产生的原因以及解决方案
    QT学习记录
    使用函数式接口
    使用函数式接口来传递行为
    Prototype(原型)
    Singleton(单例)
    Factory
    Template
  • 原文地址:https://www.cnblogs.com/wantnon/p/4918549.html
Copyright © 2011-2022 走看看