天天看點

Unity系統Cube的法線

前幾天在搞一個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法線貌似不全是垂直于平面的,今天抽空寫個腳本顯示出來看看。

先上圖

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。

Unity系統Cube的法線

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)