前几天在搞一个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();
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();
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();
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);
}
}
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)