Unity系统Cube的法线

版权声明:本文为博主原创文章,转载请表明来源和网址。 https://blog.csdn.net/thinbug/article/details/89512717

前几天在搞一个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法线貌似不全是垂直于平面的,今天抽空写个脚本显示出来看看。

先上图

cube normal

每个面的4个顶点是一种颜色,数字编号是顶点的顺序编号,看起来直观一些。
白色的法线是世界Forward方向,也是第一个面。
黑色是面向我们的面,这个面的上面两个顶点的法线是向上的。和上方的面的重合的顶点的法线互换了。(这里后期研究下)
左右和下方两个面法线是垂直于面的。

贴上代码:方便下次研究

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//在场景里拉一个Cube,拉上这个脚本.
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.black;
        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.1f;
            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("normal:{0}", 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);
    }

}

猜你喜欢

转载自blog.csdn.net/thinbug/article/details/89512717