手动创建Mesh及相关理论知识

这篇教程说的非常清楚.

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))] public class CodeMeshTriangle : MonoBehaviour { public Transform p0; public Transform p1; public Transform p2; private void Generate() { GetComponent<MeshFilter>().mesh = mMesh = new Mesh(); var vertices = new[] {p0.localPosition, p1.localPosition, p2.localPosition}; var triangles = new[] {0, 1, 2}; mMesh.vertices = vertices; mMesh.triangles = triangles; } }

构建一个Mesh只需要两部分,一个是顶点坐标(vertices),一个是由顶点坐标构成的三角形(triangles)

需要注意就是其正反面,顺时针(clockwise)正面,逆时针(Counter-clockwise)反面

UV映射及Normal映射

教程前半部分很好理解,比较让我困惑的是后半部分关于NormalMap中TBN(Tangent,Bitangent,Normal)的阐述.

NormalMap的含义

首先要说的是什么是NormalMap,官网解说的非常清楚了.

普通Mesh

加入NormalMap

{% note success %}
each pixel in the texture of the normal map (called a texel) represents a deviation in surface normal direction away from the “true” surface normal of the flat (or smooth interpolated) polygon.
{% endnote %}

Normal映射及TBN

最让我不理解的是教程中关于切线(tangents)的解释. 他直接说到

As we have a flat surface, all tangents simply point in the same direction,which is to the right.

然后直接给出代码

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

让人不明所以,不知道他这个为啥直接就point了right.

不过搞清楚这点要有几个预备知识.

首先是UV映射. 可以看Y2B上的这个视频,

没有涉及到太底层的数学推导,感性的认知UVMaping就是

{% note success %}
给定UV中的一个三角形U(三个点分别为U1,U2,U3) => 通过某种方法映射到 => 模型中的三角形P(P1,P2,P3)
{% endnote %}

这个视频有开了一个头,但是也没具体讲. 不过具体的映射方法,应该是和线性插值有关,没有细研究

QQ20171203-190005

可以用线性插值,双线性插值,Trilinear,Bilinear 作为Key搜搜看.

不过重点是下面这张图

个人理解,不一定对. 无论UV映射也好,Normal映射也好. 都需要将贴图首先旋转到与需要映射的三角形相同的一个角度. 也就是对UV图,Normal图的坐标系有旋转

如图,左边的P'三角形 和右边的P三角形 就不在一个平面. 相应的做UV时候,其坐标轴也发生的旋转.

而这个旋转的角度 从某种角度来说就是TBN

原因可以看OpenGL的教程

选定Normal后

垂直与该Normal的向量有很多

为了方便计算,所以选择和和纹理空间对齐方向

结合我自己画的那个图,也就是说 纹理空间的方向就是P'三角形所在的那个坐标系. 这个坐标系也就是UV的坐标系,也是NormalMap的切线(Tangent)和副切线(Bitangent)方向.

至于这个坐标系的求出

给定UV中的一个三角形U(三个点分别为U1,U2,U3) => 通过某种方法映射到 => 模型中的三角形P(P1,P2,P3)

我是理解为,给出了UV上的三个点,然后给出模型上的三个点,Unity已经就帮我们算出来了.(通过数学推导肯定是可以算出来的,我没有细研究).

所以我理解的设置NormalMap流程应该是,设定好UV,然后给定Normal方向,最后通过Mesh.RecalculateTangents重新计算出TB两个方向,而不是反过来直接给定了Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);

不过直接给定Tangent角度现在想想似乎也可以理解. 教程中的Mesh角度和我自己画的图中右侧的正方形一样,此时UV图面没有任何旋转,(1,0,0)也就是其x轴方向.

完整代码:

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))] public class CodeMeshTriangle : MonoBehaviour { public Transform p0; public Transform p1; public Transform p2; private Mesh mMesh; private Vector3[] mVertices; private Vector3[] mNormals; private void Update() { Generate(); } private void Generate() { GetComponent<MeshFilter>().mesh = mMesh = new Mesh(); var normal = new Vector3(0, 0, -1); mVertices = new[] {p0.localPosition, p1.localPosition, p2.localPosition}; mNormals = new[] {normal, normal, normal}; var triangles = new[] {0, 1, 2}; Vector2[] uv = new Vector2[3]; uv[0] = new Vector2(0, 0); uv[1] = new Vector2(0, 1); uv[2] = new Vector2(1, 0); mMesh.vertices = mVertices; mMesh.triangles = triangles; mMesh.uv = uv; mMesh.normals = mNormals; mMesh.RecalculateTangents(); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjzzg.html