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;
    }
}

 

Unity动态Mesh指的是在游戏运行时使用代码生成、修改和控制游戏对象的网格(Mesh)的过程。Mesh是3D模型的基本组成部分,由顶点、三角形面和纹理坐标等数据组成。 在Unity中,可以通过脚本代码来动态创建、修改和控制一个游戏对象的Mesh。例如,可以通过代码动态生成一个平面、立方体或其他形状的Mesh,然后根据需要调整其顶点坐标、法线、纹理坐标以及三角形面的连接关系等。这样可以实现一些特殊的效果,比如模型的变形、碰撞检测、粒子效果等。 动态Mesh的优势在于它可以在运行时根据游戏逻辑来生成和修改网格,而不需要事先预定义好所有可能的模型。这样在游戏中就可以根据游戏需求生成各种形状独特的道具、场景和角色等。而且,动态Mesh还可以根据游戏对象的运动状态来实时修改网格,使其能够更加逼真地反映游戏对象的变化。 然而,动态Mesh的生成和修改也需要一定的计算资源和代码编写技巧。过多的Mesh变化可能会导致性能下降,因此在使用动态Mesh时需要注意优化。此外,代码编写方面也需要对Mesh的数据结构和相关API有一定的理解,以保证以正确的方式生成和修改Mesh。 总之,Unity动态Mesh是一项强大而灵活的功能,可以帮助开发者实现更加个性化和富有创意的游戏效果。通过脚本代码的控制和调整,可以在游戏中实时生成、修改和控制各种形状和表现力的网格,从而提升游戏的可玩性和视觉效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值