前幾天在搞一個Voxel的項目,盒子的表現不美觀,于是想給Voxel加上法線增強盒子的立體效果,給shader裡加了法線,但是顯示出來法線效果不對,繞了很大一圈。
一開始懷疑是法線方向不對,法線反了就看不到啊,應該也沒反。
UV順序不對嗎?UV沒頂點重合不會看不到。
後來才發現MagicVoxel For unity的包是沒有切線資料的,沒切線資料無法正确顯示。
切線的描述:
Mesh.tangents 網格切線
var tangents : Vector4[]
Description描述
The tangents of the mesh.
網格的切線
Tangents are mostly used in bump-mapped shaders. A tangent is a unit length vector that follows mesh surface along horizontal (U) texture direction. Tangents in Unity are represented as Vector4, with x,y,z components defining the vector, and w used to flip the binormal if needed.
切線主要用于bump-mapped shaders。切線是一個有方向的機關長度,沿着網格表面指向水準(U)紋理方向。在Unity中切線被描述為Vector4,包括x,y,z這些元件定義的矢量,如果需要,及w用來翻轉副法線。
Unity calculates the other surface vector (binormal) by taking a cross product between normal and tangent, and multiplying result by tangent.w. Thus w should always be 1 or -1.
Unity通過計算向量和法線的叉乘來計算其他表面的向量(副法線),并乘以tangent.w。是以w應該總是1或者-1。
You should calculate tangents yourself if you plan to use bump-mapped shaders on the mesh. Assign tangents after assigning normals or using RecalculateNormals
如果你計劃在網格上用凹凸貼圖着色器,你應該自己計算切線。在指派法線或者用RecalculateNormals之後再指派切線。
另外看MagicVoxel的源碼,發現法線資料都是和面同一方向的,記得unity的Cube法線貌似不全是垂直于平面的,今天抽空寫個腳本顯示出來看看。
先上圖
每個面的4個頂點是一種顔色,數字編号是頂點的順序編号,看起來直覺一些。
白色的法線是世界Forward方向,也是第一個面。
黑色是面向我們的面,這個面的上面兩個頂點的法線是向上的。和上方的面的重合的頂點的法線互換了。(這裡後期研究下)
左右和下方兩個面法線是垂直于面的。
貼上代碼:友善下次研究
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CNVTest : MonoBehaviour
{
MeshFilter mf;
Color[] c = new Color[6];
void Start()
{
mf = GetComponent<MeshFilter>();
int i, no;
int m;
GameObject oParent = null;
c[0] = Color.white;
c[1] = Color.yellow;
c[2] = Color.red;
c[3] = Color.green;
c[4] = Color.blue;
c[5] = Color.cyan;
no = 0;
m = 0;
for (i=0; i < mf.mesh.uv.Length; i++)
{
m = i % 4;
if (m == 0)
{
no = i / 4;
oParent = new GameObject("v_"+no.ToString());
oParent.transform.SetParent(transform);
oParent.transform.localPosition = Vector3.zero;
oParent.transform.localRotation = Quaternion.identity;
}
//頂點
GameObject ob = GameObject.CreatePrimitive(PrimitiveType.Sphere);
ob.transform.SetParent(oParent.transform);
ob.transform.localScale = Vector3.one * 0.07f;
ob.transform.localRotation = Quaternion.identity;
ob.transform.localPosition = mf.mesh.vertices[i];
CNormal nm = ob.AddComponent<CNormal>();
nm.dir = mf.mesh.normals[i];
nm.c = c[no];
nm.txt = string.Format("vertice:{0},uv:{1}", i, mf.mesh.uv[i]);
Debug.Log("cube:i=" + i + ",ver:" + mf.mesh.vertices[i] + ",uv:" + mf.mesh.uv[i] + ",normal:" + mf.mesh.normals[i]);
}
}
}
這個腳本會自動添加到頂點。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CNormal : MonoBehaviour
{
public Vector3 dir;
public Color c;
public string txt;
GUIStyle fontStyle = new GUIStyle();
public Vector3[] lines = new Vector3[2];
//劃線顯示法線
LineRenderer linerender;
Material mat;
Camera cam;
void Start()
{
fontStyle.normal.background = null; //設定背景填充
fontStyle.normal.textColor = c;// new Color(1, 0, 0); //設定字型顔色
linerender = gameObject.AddComponent<LineRenderer>();
mat = new Material(Shader.Find("Standard"));
mat.color = c;
linerender.material = mat;
linerender.startWidth = 0.01f;// .SetWidth(0.01f, 0.01f);
linerender.endWidth = 0.01f;
cam = Camera.main;
}
void OnGUI()
{
lines[0] = transform.position;
lines[1] = transform.position + transform.rotation * dir;
linerender.SetPositions(lines);
Vector3 screenPos = cam.WorldToScreenPoint(lines[1]);
GUI.Label(new Rect(screenPos.x, Screen.height - screenPos.y, 680, 50), txt, fontStyle);
}
}
補一張帶UV的,能看到法線和UV。
cube:i=0,ver:(0.5, -0.5, 0.5),uv:(0.0, 0.0),normal:(0.0, 0.0, 1.0)
cube:i=1,ver:(-0.5, -0.5, 0.5),uv:(1.0, 0.0),normal:(0.0, 0.0, 1.0)
cube:i=2,ver:(0.5, 0.5, 0.5),uv:(0.0, 1.0),normal:(0.0, 0.0, 1.0)
cube:i=3,ver:(-0.5, 0.5, 0.5),uv:(1.0, 1.0),normal:(0.0, 0.0, 1.0)
cube:i=4,ver:(0.5, 0.5, -0.5),uv:(0.0, 1.0),normal:(0.0, 1.0, 0.0)
cube:i=5,ver:(-0.5, 0.5, -0.5),uv:(1.0, 1.0),normal:(0.0, 1.0, 0.0)
cube:i=6,ver:(0.5, -0.5, -0.5),uv:(0.0, 1.0),normal:(0.0, 0.0, -1.0)
cube:i=7,ver:(-0.5, -0.5, -0.5),uv:(1.0, 1.0),normal:(0.0, 0.0, -1.0)
cube:i=8,ver:(0.5, 0.5, 0.5),uv:(0.0, 0.0),normal:(0.0, 1.0, 0.0)
cube:i=9,ver:(-0.5, 0.5, 0.5),uv:(1.0, 0.0),normal:(0.0, 1.0, 0.0)
cube:i=10,ver:(0.5, 0.5, -0.5),uv:(0.0, 0.0),normal:(0.0, 0.0, -1.0)
cube:i=11,ver:(-0.5, 0.5, -0.5),uv:(1.0, 0.0),normal:(0.0, 0.0, -1.0)
cube:i=12,ver:(0.5, -0.5, -0.5),uv:(0.0, 0.0),normal:(0.0, -1.0, 0.0)
cube:i=13,ver:(0.5, -0.5, 0.5),uv:(0.0, 1.0),normal:(0.0, -1.0, 0.0)
cube:i=14,ver:(-0.5, -0.5, 0.5),uv:(1.0, 1.0),normal:(0.0, -1.0, 0.0)
cube:i=15,ver:(-0.5, -0.5, -0.5),uv:(1.0, 0.0),normal:(0.0, -1.0, 0.0)
cube:i=16,ver:(-0.5, -0.5, 0.5),uv:(0.0, 0.0),normal:(-1.0, 0.0, 0.0)
cube:i=17,ver:(-0.5, 0.5, 0.5),uv:(0.0, 1.0),normal:(-1.0, 0.0, 0.0)
cube:i=18,ver:(-0.5, 0.5, -0.5),uv:(1.0, 1.0),normal:(-1.0, 0.0, 0.0)
cube:i=19,ver:(-0.5, -0.5, -0.5),uv:(1.0, 0.0),normal:(-1.0, 0.0, 0.0)
cube:i=20,ver:(0.5, -0.5, -0.5),uv:(0.0, 0.0),normal:(1.0, 0.0, 0.0)
cube:i=21,ver:(0.5, 0.5, -0.5),uv:(0.0, 1.0),normal:(1.0, 0.0, 0.0)
cube:i=22,ver:(0.5, 0.5, 0.5),uv:(1.0, 1.0),normal:(1.0, 0.0, 0.0)
cube:i=23,ver:(0.5, -0.5, 0.5),uv:(1.0, 0.0),normal:(1.0, 0.0, 0.0)