背景
我們通過代碼動態(tài)創(chuàng)建的網(wǎng)格,因為沒有法線,不會接收到光照。
正常情況下調(diào)用Mesh.RecalculateNormals方法,重新生成法線即可。
但特定情況下通過此方法計算出的頂點發(fā)現(xiàn)都是(0, 0,0),這種情況下只能手動生成法線了
如下圖,左邊物體有正確的法線,可以接收光照信息,右側(cè)物體無法線,無法接收光照。
RecalculateNormals計算異常的原因
經(jīng)測試發(fā)現(xiàn)導(dǎo)致Mesh.RecalculateNormals計算異常的情況:
如果Mesh中的某個頂點,在三角形標號數(shù)組中,即畫了正面的網(wǎng)格,又畫了反面的網(wǎng)格,則會導(dǎo)致RecalculateNormals計算錯誤,該點法線計算結(jié)果為(0, 0,0)。
解決方法1
對于雙面網(wǎng)格,將頂點數(shù)組增加一倍,用于繪制反面的網(wǎng)格,分別放入Mesh的三角形標號數(shù)組中,以保證每個點法線計算正確。
解決方法2
用下方的生成頂點法線算法,手動計算期望的法線數(shù)組。
原理
法線:法線是指始終垂直于某平面的直線。在幾何學(xué)中,法線指平面上垂直于曲線在某點的切線的一條線。
網(wǎng)格的法線數(shù)組:法線數(shù)組存放Mesh每個頂點的法線,數(shù)組大小與頂點坐標對應(yīng),normals[i]對應(yīng)頂點vertices[i]的法線。
在 Max Wagner 的 《Generating Vertex Normals》文章 中寫到——嚴格意義上講,點是沒有法線的。點的法線是在使用Phone或Gouraud模型時計算光照使用。如果一個面上的所有法線都一樣,他們的光照也就一樣,就會產(chǎn)生 flatness 效果;而如果把每個頂點的法向設(shè)置不同,則更平滑。
我們通過代碼創(chuàng)建的網(wǎng)格一般都是多邊形,所以給每個頂點賦值他所在的平面的法線即可。
生成頂點法線算法
創(chuàng)建網(wǎng)格,并設(shè)定如上圖的八個點位,三角形序列,uv
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[8];
vertices[0] = new Vector3(0,0,0);
vertices[1] = new Vector3(0,1,0);
vertices[2] = new Vector3(1,0,0);
vertices[3] = new Vector3(1,1,0);
vertices[4] = new Vector3(1,0,0);
vertices[5] = new Vector3(1,1,0);
vertices[6] = new Vector3(2,0,1);
vertices[7] = new Vector3(2,1,1);
mesh.vertices = vertices;
int[] triangles = new int[12];
triangles[0] = 0;
triangles[1] = 1;
triangles[2] = 3;
triangles[3] = 2;
triangles[4] = 0;
triangles[5] = 3;
triangles[6] = 4;
triangles[7] = 5;
triangles[8] = 7;
triangles[9] = 6;
triangles[10] = 4;
triangles[11] = 7;
mesh.triangles = triangles;
Vector2[] uv = new Vector2[8];
uv[0] = new Vector2(0,0);
uv[1] = new Vector2(0,1);
uv[2] = new Vector2(1,0);
uv[3] = new Vector2(1,1);
uv[4] = new Vector2(0,0);
uv[5] = new Vector2(0,1);
uv[6] = new Vector2(1,0);
uv[7] = new Vector2(1,1);
mesh.uv = uv;
生成法線數(shù)組
Vector3[] normals = new Vector3[8];
Vector3 v1 = Vector3.Cross(vertices[0] - vertices[1], vertices[0] - vertices[3]);
normals[0] = v1;
normals[1] = v1;
normals[2] = v1;
normals[3] = v1;
Vector3 v2 = Vector3.Cross(vertices[4] - vertices[5], vertices[4] - vertices[7]);
normals[4] = v2;
normals[5] = v2;
normals[6] = v2;
normals[7] = v2;
mesh.normals = normals;
//mesh.RecalculateNormals();
最終效果
文章來源:http://www.zghlxwxcb.cn/news/detail-639941.html
(此案例中,使用Mesh.RecalculateNormal,也可生成正確法線。)文章來源地址http://www.zghlxwxcb.cn/news/detail-639941.html
完整代碼,增加了點位, 注釋部分為增加了背部網(wǎng)格
public Mesh CreatMeshTest()
{
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[12];
vertices[0] = new Vector3(0,0,0);
vertices[1] = new Vector3(0,1,0);
vertices[2] = new Vector3(1,0,0);
vertices[3] = new Vector3(1,1,0);
vertices[4] = new Vector3(1,0,0);
vertices[5] = new Vector3(1,1,0);
vertices[6] = new Vector3(0.5f,0,1);
vertices[7] = new Vector3(0.5f,1,1);
vertices[8] = new Vector3(0.5f,0,1);
vertices[9] = new Vector3(0.5f,1,1);
vertices[10] = new Vector3(0,0,0);
vertices[11] = new Vector3(0,1,0);
mesh.vertices = vertices;
int[] triangles = new int[18];
triangles[0] = 0;
triangles[1] = 1;
triangles[2] = 3;
triangles[3] = 2;
triangles[4] = 0;
triangles[5] = 3;
triangles[6] = 4;
triangles[7] = 5;
triangles[8] = 7;
triangles[9] = 6;
triangles[10] = 4;
triangles[11] = 7;
triangles[12] = 8;
triangles[13] = 9;
triangles[14] = 11;
triangles[15] = 10;
triangles[16] = 8;
triangles[17] = 11;
// triangles[18] = 0;
// triangles[19] = 3;
// triangles[20] = 1;
//
// triangles[21] = 2;
// triangles[22] = 3;
// triangles[23] = 0;
//
// triangles[24] = 4;
// triangles[25] = 7;
// triangles[26] = 5;
//
// triangles[27] = 6;
// triangles[28] = 7;
// triangles[29] = 4;
//
// triangles[30] = 8;
// triangles[31] = 11;
// triangles[32] = 9;
//
// triangles[33] = 10;
// triangles[34] = 11;
// triangles[35] = 8;
mesh.triangles = triangles;
Vector2[] uv = new Vector2[12];
uv[0] = new Vector2(0,0);
uv[1] = new Vector2(0,1);
uv[2] = new Vector2(1,0);
uv[3] = new Vector2(1,1);
uv[4] = new Vector2(0,0);
uv[5] = new Vector2(0,1);
uv[6] = new Vector2(1,0);
uv[7] = new Vector2(1,1);
uv[8] = new Vector2(0,0);
uv[9] = new Vector2(0,1);
uv[10] = new Vector2(1,0);
uv[11] = new Vector2(1,1);
mesh.uv = uv;
Vector3[] normals = new Vector3[12];
Vector3 v1 = Vector3.Cross(vertices[0] - vertices[1], vertices[0] - vertices[3]);
normals[0] = v1;
normals[1] = v1;
normals[2] = v1;
normals[3] = v1;
Vector3 v2 = Vector3.Cross(vertices[4] - vertices[5], vertices[4] - vertices[7]);
normals[4] = v2;
normals[5] = v2;
normals[6] = v2;
normals[7] = v2;
Vector3 v3 = Vector3.Cross(vertices[8] - vertices[9], vertices[8] - vertices[11]);
normals[8] = v3;
normals[9] = v3;
normals[10] = v3;
normals[11] = v3;
mesh.normals = normals;
//mesh.RecalculateNormals();
return mesh;
}
到了這里,關(guān)于【Unity】為網(wǎng)格生成頂點法線(Mesh.RecalculateNormals計算異常的解決方案)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!