Unity Mesh的初步使用(创建贝塞尔曲线的一个模型片)

Unity中Mesh的初步使用

    • 什么是Mesh?
    • 原理
    • 理论基础:
    • Mesh的组成部分
      • 原文链接
    • 示例
      • 完整代码
      • 最终效果

什么是Mesh?

Mesh是指的模型的网格,3D模型是由多边形拼接而成,而多边形实际上又是由多个三角形拼接而成的。即一个3D模型的表面其实是由多个彼此相连的三角面构成。三维空间中,构成这些三角形的点和边的集合就是Mesh

原理

即动态创建一个Mesh,设置三角形和顶点数据,然后赋值给MeshFilter(增加mesh属性),通过MeshRenderer(增加材质并渲染出Mesh)绘制出来

理论基础:

1、左手坐标系和右手坐标系
我们的三维坐标系,在3dmax里是右手坐标系,而在Unity里是左手坐标系
左手坐标系和右手坐标系的区别 http://www.cnblogs.com/mythou/p/3327046.html
Unity Mesh的初步使用(创建贝塞尔曲线的一个模型片)_第1张图片
2、三边面如何组成四边面
Unity Mesh的初步使用(创建贝塞尔曲线的一个模型片)_第2张图片
如图,左边是Unity里的左手坐标系,右边是在此坐标系里生成的一个面以及它的各个点坐标。
012和230这两个三边面就组成了一个四边面。
如果我问这个四边面有几个顶点,想必大家都会回答4个,实际上是6个,012和230这是6个顶点,不同面的顶点不公用。
要组成2个三边面可以有很多种顺序,例如012和320、012和032、023和012等等等
但是我们一般都是按照4个点的顺序来画2个三边面组成四边面,所以可选的只有【012和230、230和012】,以及【032和210、210和032】这两大类
这两类画法有什么区别呢?细心的童鞋应该已经发现,这两种方式前者是逆时针,后者是顺时针
这种循环的方向会导致面的法线方向不同,而这个法线方向会决定这个面的朝向。
我们要确定这个法线方向其实很简单,上面说了,Unity里是左手坐标系,拿出左手,伸直,拇指与其他四个指头垂直,然后四指弯曲,指尖朝向循环的方向,拇指就指向法线的方向
由此我们得出结论,要想生成正确的面(法线指向我们),我们只能用【032和210、210和032】
这里需要注意的一点是,我们确定4个点的循环方向,和生成三边面时的循环方向无关,只要生成三边面时,用到的前4个点的index顺序没错就行了。

Mesh的组成部分

  1. vertices(顶点数据数组Vector3[])
  2. triangles(三角形顶点索引数组,int[])
  3. normals(法线向量数组,Vector3[])
  4. uv(纹理坐标数组,Vector2[])
  • 顶点坐标:顶点坐标数组存放Mesh的每个顶点的空间坐标,假设某mesh有n个顶点,则vertex的size为n
  • 法线:法线数组存放mesh每个顶点的法线,大小与顶点坐标对应,normal[i]对应顶点vertex[i]的法线

法线详解:

  • 法线就是垂直于面的一条线,它有方向,没有大小。
  • 法线的方向就是面朝外的方向。比如我们现在盯着显示器看,从显示器的正中心会有一条法线垂直于屏幕指向我们。
  • 法线向外的面就是正面,相反的就是背面,一般来讲,从正面看才能看到面,背面看面是看不到的。
  • 纹理坐标:它定义了图片上每个点的位置的信息. 这些点与3D模型是相互联系的, 以决定表面纹理贴图的位置. UV就是将图像上每一个点精确对应到模型物体的表面. uv[i]对应vertex[i]
  • 三角形序列:每个mesh都由多个三角面组成,而三角面的三个点就是顶点坐标里的点,三角形的数组的size = 三角形个数 * 3

三边面和四边面:

  • 三边面就是三条边组成的面,四边面就是四条边组成的面。
  • 三边面在三维空间中是不可扭曲的,而四边面在三维空间中可以扭曲。所以Unity里只支持三边面。其他支持四边面的软件例如3dmax在导出fbx的时候,会把四边面转换成三边面。

原文链接

原文链接:https://www.cnblogs.com/answer-yj/p/11231247.html。
该文章后面还有一个例子,这里我不用,而用一个我自己的一个Demo,是建一个贝塞尔曲线的模型片,是我面试一家企业时做的,这里记录一下。

示例

首先,需要画出一条贝塞尔曲线,代码如下:

public List<Transform> anchor = new List<Transform>();
private List<Vector3> point = new List<Vector3>();
//计算出指定个点,将他们练成一条直线,使其开起来像是曲线
void GetPathPoints()
{
    Vector3[] temp_1 = new Vector3[anchor.Count];
    for (int i = 0; i < temp_1.Length; i++)
    {//获取锚点坐标
        temp_1[i] = anchor[i].position;
    }
    point = new List<Vector3>();//最终贝塞尔曲线上点的链表集合
    float pointNumber = 50;//贝塞尔曲线上点的数量
    Vector3[] temp_2;
    Vector3[] temp_3;
    for (int i = 0; i <= (int)pointNumber; i++)
    {
        temp_3 = temp_1;
        for (int j = temp_3.Length - 1; j > 0; j--)
        {
            temp_2 = new Vector3[j];
            for (int k = 0; k < j; k++)
            {
                temp_2[k] = Vector3.Lerp(temp_3[k], temp_3[k + 1], i / pointNumber);
            }
            temp_3 = temp_2;
        }
        Vector3 find = temp_3[0];
        point.Add(find);
    }
}
//画线
void OnDrawGizmos()
{
    GetPathPoints();
    Gizmos.color = Color.yellow;
    for (int i = 0; i < point.Count - 1; i++)
    {
        Gizmos.DrawLine(point[i], point[i + 1]);
    }
}

上面的代码源自关于贝塞尔曲线的链接:https://blog.csdn.net/f_957995490/article/details/106571818
上面代码中最终获得贝塞尔曲线上的点的数量为50,将这些点按一定顺序排列,建立成顶点数组和顶点索引数组,并赋值到Mesh对象中,再将其赋值到MeshFilter中添加材质球即可。先看代码:

void Awake()
{
    GetPathPoints();
    Vector3 start = point[point.Count - 1];
    Vector3 end = point[point.Count - 1];
    for (int i = 1; i < point.Count - 1; i++)
    {
        _vertices.Add(point[i - 1]);
        _vertices.Add(end);
        _vertices.Add(point[i]);
    }
    for (int i = _vertices.Count - 1; i >= 0; i--)
    {
        _triangles.Add(i);
    }
}

void Start()
{
    Mesh mesh = new Mesh();
    mesh.vertices = _vertices.ToArray();
    mesh.triangles = _triangles.ToArray();
    mesh.RecalculateNormals();
    gameObject.AddComponent<MeshFilter>().mesh = mesh;
    gameObject.AddComponent<MeshRenderer>().material = Resources.Load<Material>("Standard");
}

关于我设置的顶点顺序,自己画个图,大致表现一下,更加直观吧。
Unity Mesh的初步使用(创建贝塞尔曲线的一个模型片)_第3张图片

完整代码

using System.Collections.Generic;
using UnityEngine;

namespace ZM_Code
{
    public class DrawBezierCurve : MonoBehaviour
    {
        public List<Transform> anchor = new List<Transform>();
        private List<Vector3> point = new List<Vector3>();
        //计算出指定个点,将他们练成一条直线,使其开起来像是曲线
        void GetPathPoints()
        {
            Vector3[] temp_1 = new Vector3[anchor.Count];
            for (int i = 0; i < temp_1.Length; i++)
            {//获取锚点坐标
                temp_1[i] = anchor[i].position;
            }
            point = new List<Vector3>();//最终贝塞尔曲线上点的链表集合
            float pointNumber = 50;//贝塞尔曲线上点的数量
            Vector3[] temp_2;
            Vector3[] temp_3;
            for (int i = 0; i <= (int)pointNumber; i++)
            {
                temp_3 = temp_1;
                for (int j = temp_3.Length - 1; j > 0; j--)
                {
                    temp_2 = new Vector3[j];
                    for (int k = 0; k < j; k++)
                    {
                        temp_2[k] = Vector3.Lerp(temp_3[k], temp_3[k + 1], i / pointNumber);
                    }
                    temp_3 = temp_2;
                }
                Vector3 find = temp_3[0];
                point.Add(find);
            }
        }
        //画线
        void OnDrawGizmos()
        {
            GetPathPoints();
            Gizmos.color = Color.yellow;
            for (int i = 0; i < point.Count - 1; i++)
            {
                Gizmos.DrawLine(point[i], point[i + 1]);
            }
        }

        private List<Vector3> _vertices = new List<Vector3>();
        private List<int> _triangles = new List<int>();

        void Awake()
        {
            GetPathPoints();
            Vector3 start = point[point.Count - 1];
            Vector3 end = point[point.Count - 1];
            for (int i = 1; i < point.Count - 1; i++)
            {
                _vertices.Add(point[i - 1]);
                _vertices.Add(end);
                _vertices.Add(point[i]);
            }
            for (int i = _vertices.Count - 1; i >= 0; i--)
            {
                _triangles.Add(i);
            }
        }

        void Start()
        {
            Mesh mesh = new Mesh();
            mesh.vertices = _vertices.ToArray();
            mesh.triangles = _triangles.ToArray();
            mesh.RecalculateNormals();
            gameObject.AddComponent<MeshFilter>().mesh = mesh;
            gameObject.AddComponent<MeshRenderer>().material = Resources.Load<Material>("Standard");
        }
    }
}

最终效果

Unity Mesh的初步使用(创建贝塞尔曲线的一个模型片)_第4张图片

你可能感兴趣的:(面试笔试)