Unity 动态生成网格

在Unity中我们可以实现动态网格,并将部分信息写入(顶点,UV,法线信息,切线信息);
在这里插入图片描述
首先明确一点的是Unity采用的坐标系

坐标系


在unity当中,采用的 左手坐标系
左手坐标系
左手坐标系

顶点Vertex


因为Unity空间坐标系是基于左手,网格亦是遵循此规则,
在生成顶点Vertex时,是按照左下角开始,向右上角逐个生成.
其中Z分量越大,则深度越大,分量越小,则高度越高.
顶点位置

多边形Triangle


在完成顶点坐标的确定之后,需要对mesh的多边形进行设置,
这里要注意2个问题:

  1. 对图形内外的判断:
    因为三角形是通过顶点索引数组定义的.由于每个三角形都有三个点,因此三个连续的索引描述一个三角形.
    而这个方向是按照顶点序列的顺时针进行判断的,因此,我们可以通过左手定则进行判断内外.
    所以要正确显示,就需要按照正确的顶点序列去构建三角形数组.
    请添加图片描述
    左手定则
  2. 构建三角形数组
    在搞清楚顺序之后,我们可以先按照顺序构建一行4个三角形,这样便于我们发现规律
    在这里插入图片描述
    顶点相邻关系
    因为每两个相邻的三角形会共用两个顶点,且每6次就会迭代一次
    迭代关系
    这样我们得出这一行的规律:
		int[] triangles = new int[xSize * 6];
		for (int ti = 0, vi = 0, x = 0; x < xSize; x++, ti += 6, vi++) {
			triangles[ti] = vi;
			triangles[ti + 3] = triangles[ti + 2] = vi + 1;
			triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
			triangles[ti + 5] = vi + xSize + 2;
		}

再按照这一规律拓展到每一行:

        int[] triangles = new int[xSize * ySize * 6];
        for (int ti = 0, vi = 0, y = 0; y < ySize; y++, vi++)
        {
            for (int x = 0; x < xSize; x++, ti += 6, vi++)
            {
                triangles[ti] = vi;
                triangles[ti + 3] = triangles[ti + 2] = vi + 1;
                triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
                triangles[ti + 5] = vi + xSize + 2;
                mesh.triangles = triangles;//设置三角形
            }
        }
         mesh.tangents = tangents;//设置切线

UV坐标


UV坐标

UV坐标一般是由两个分量构成,其范围为0~1,
如果要将UV信息录入Mesh网格,则需要将顶点信息进行归一化,每个顶点的位置映射在uv坐标中,对应顶点的分量取值范围为[0,1].

  uv[i] = new Vector2((float)x / xSize, (float)y / ySize);//归一化得到uv坐标
  mesh.uv = uv;//设置uv

法线Normal


法线的方向为垂直于三角形的切面,并且方向向外.
但是,默认的法线方向是(0, 0, 1),这与我们需要的完全相反.(根据左手原则,Z分量1的方向朝里)
因此我们需要unity辅助函数RecalculateNormals()计算法线.

 mesh.RecalculateNormals();//重新计算法线

切线Tangent


切线的方向正好于发现正好垂直,我们取一个单位向量作为切线方向.
因为切线是需要4个分量作为计算参数,最后一个W分量取-1.
至于为什么要用4个分量,可能与图形基本变换矩阵有关,因为需要完成非线性变换,所以使用齐次
坐标.可以参考图形学中的基本变换.
可以发现tangent 和normal的点乘结果为0,即法线和切线为正交关系.

	Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);

完整代码:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Grid : MonoBehaviour
{
    public int xSize, ySize;
    private void Awake()
    {
        StartCoroutine(Generate());
    }

    private Vector3[] vertices;
    private Mesh mesh;

    IEnumerator Generate()
    {
        WaitForSeconds wait = new WaitForSeconds(0.05f);
        GetComponent<MeshFilter>().mesh = mesh = new Mesh();
        mesh.name = "Procedural Grid";
        vertices = new Vector3[(xSize + 1) * (ySize + 1)];
        Vector2[] uv = new Vector2[vertices.Length];
        Vector4[] tangents = new Vector4[vertices.Length];//切线
        Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);
        for (int i = 0, y = 0; y <= ySize; y++)
        {
            for (int x = 0; x <= xSize; x++, i++)
            {
                vertices[i] = new Vector3(x, y);
                uv[i] = new Vector2((float)x / xSize, (float)y / ySize);//归一化得到uv坐标
                tangents[i] = tangent;
                yield return wait;
            }
        }
        mesh.vertices = vertices;//设置顶点
        mesh.uv = uv;//设置uv
        mesh.tangents = tangents;//设置切线


        int[] triangles = new int[xSize * ySize * 6];
        for (int ti = 0, vi = 0, y = 0; y < ySize; y++, vi++)
        {
            for (int x = 0; x < xSize; x++, ti += 6, vi++)
            {
                triangles[ti] = vi;
                triangles[ti + 3] = triangles[ti + 2] = vi + 1;
                triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
                triangles[ti + 5] = vi + xSize + 2;
                mesh.triangles = triangles;//设置三角形
                yield return wait;
            }
        }

        mesh.RecalculateNormals();//重新计算法线

    }
    private void OnDrawGizmos()
    {
        if (vertices == null)
        {
            return;
        }
        Gizmos.color = Color.black;
        for (int i = 0; i < vertices.Length; i++)
        {
            Gizmos.DrawSphere(vertices[i], 0.1f);
        }
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值