UnityShader学习12 关于法线贴图

法线贴图可以使光滑的物体表面看起来凹凸有致,比如砖块、地面等等这些,如果全部都由建模来体现细节的话会使顶点急剧增多,性能消耗急剧增加,所以就有了法线贴图。

砖块、地面等等的模型细节表面能和光照实时交互,得益于法线贴图。

法线贴图记录的是法线的信息,然后根据光照向量来进行点积,从而得到光照强度,进而实现物体凹凸有致的感觉。

基本思路:

把贴图转换成灰度图,然后根据贴图每个像素的颜色分量的一个值(由于是灰度图,所以rgb三个分量都是相等的,所以这里才说是一个值)的上、下的差值,求出差分向量v;

同理,利用左、右,求出差分向量u;然后这两组向量进行叉乘,求出法向量。求出的法向量记录进图片的rgb分量中,由于rgb分量的范围是0到1,所以要进行一个映射。

最后,由于我们的求出的法向量是基于nv坐标系的,如果在多个平面使用同一个法线贴图,这就会造成光照效果的错误(比如说cube),所以,我们要对光进行一个变换来变换到切线空间(TBN)。切线空间的相关文章:https://blog.csdn.net/Game_jqd/article/details/74858146

以下是用c#代码实现法线贴图:

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

public class CreateNormalMap : MonoBehaviour {
    public Texture2D tex0;//原始纹理
    public Texture2D tex1;//处理后的法线纹理

    // Use this for initialization
    void Start () {
        for (int h = 1; h < tex0.height - 1; h++)
        {
            for (int w = 1; w < tex0.width - 1; w++)
            {
                float uleft = tex0.GetPixel(w - 1, h).r;//左边
                float uright = tex0.GetPixel(w, h - 1).r;//右边
                float u = uright - uleft;

                float vtop = tex0.GetPixel(w, h - 1).r;
                float vbottom = tex0.GetPixel(w, h + 1).r;
                float v = vbottom - vtop;

                Vector3 vector_u = new Vector3(1, 0, u);
                Vector3 vector_v = new Vector3(0, 1, v);

                Vector3 N = Vector3.Cross(vector_u, vector_v);

                float r = N.x * 0.5f + 0.5f;
                float g = N.y * 0.5f + 0.5f;
                float b = N.z * 0.5f + 0.5f;

                tex1.SetPixel(w, h, new Color(r, g, b));
            }

            tex1.Apply(false);
        }
    }
    
}

 

posted on 2019-06-20 00:39  炼金师  阅读(193)  评论(0)    收藏  举报

导航