遊戲編程精粹學習 - 使用定點顏色插值模擬實時光照

終於有空看點新東西,這一篇在《遊戲編程精粹1》的5.3節中,主要講經過烘焙先後左右4個方向光照並插值,來代替頂點光照的作法git

看了下原文例程的代碼,彷佛是放在cpu部分處理的頂點色,或可能只是參考用的腳本編程

這種烘焙4個方向的作法或許優於頂點光照,但缺點是光線角度較爲固定,原文描述早期的足球遊戲有使用到app

或許改爲貼圖的話能夠烘焙進一些法線效果,或是作成粒子光照。。測試

 

優勢

  • gpu上優於頂點光照
  • 可做爲輔助光源使用
  • 較高的精度

缺點:

  • 消耗必定的cpu
  • 佔用一塊uv數據
  • 常規烘焙的狀況下,只對俯視角、水平視角支持比較好

 

 

首先寫一個簡單的蘭伯特光照,烘焙四個方向:優化

這4個方向的燈光信息會被烘焙到uv2,uv3中,運行後cpu計算當前角度的權重,到shader裏進行混合。spa

 

插值的計算用了比較偷懶的作法,原文是轉角度進行處理,因爲y方向固定,這裏直接用Vector2點乘。3d

public class LightingRuntime : MonoBehaviour
{
    public Transform virtualLight;
    public Color virtualLightCol;
    public SkinnedMeshRenderer testRenderer;


    void Update()
    {
        var lightDir = (virtualLight.position - transform.position).normalized;
        lightDir = Vector3.ProjectOnPlane(lightDir, Vector3.up);

        var lightDir_vec2 = new Vector2(lightDir.x, lightDir.z);
        var blend1 = Mathf.Clamp01(Vector2.Dot(lightDir_vec2, Vector2.up));
        var blend2 = Mathf.Clamp01(Vector2.Dot(lightDir_vec2, Vector2.down));
        var blend3 = Mathf.Clamp01(Vector2.Dot(lightDir_vec2, Vector2.left));
        var blend4 = Mathf.Clamp01(Vector2.Dot(lightDir_vec2, Vector2.right));

        var vec4 = new Vector4(blend1, blend2, blend3, blend4);
        testRenderer.material.SetVector("_TestLight", vec4);
        testRenderer.material.SetVector("_TestLightCol", virtualLightCol);
    }
}

 

傳入4個權重表明4個方向,而後shader部分根據4個方向的權重乘起來便可。code

能夠用uv2,uv3來儲存4個方向的光照信息。orm

v2f vert (appdata v)
{
    v2f o = (v2f)0;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    o.uv2 = v.uv2;
    o.uv3 = v.uv3;

    return o;
}

fixed4 frag (v2f i) : SV_Target
{
    fixed4 lightVolume =  i.uv2.x *  _TestLight.x + i.uv2.y * _TestLight.y + i.uv3.x * _TestLight.z + i.uv3.y * _TestLight.w;
    return lightVolume * _TestLightCol;
}

 

可是佔用uv2,uv3有點佔用帶寬,因而想了一個辦法,左右和先後的方向能夠各用一個鏡像:blog

left = 1 - right;

用鏡像以前須要記錄4個方向,如今只需記錄2個。可是要考慮一些長期陰影的區域,因此還需加些參數調節去緩解。

 

優化了一下,將uv2做爲光照信息,並鏡像了烘焙到頂點上的光照(輸出的uv2是float4),以及微調參數:

v2f vert (appdata v)
{
    v2f o = (v2f)0;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    o.uv2.xz = v.uv2.xy;
    o.uv2.y = (1 - v.uv2.x) - 0.8;
    o.uv2.w = (1 - v.uv2.y) - 1;

    return o;
}

fixed4 frag (v2f i) : SV_Target
{
    fixed lightVolume = dot(i.uv2, _TestLight);
    return lightVolume * _TestLightCol;
}

 

 

最終效果:

 

2019/06/2補充,增長一組面片的使用狀況:

 

測試工程地址:

https://gitee.com/Hont/4DirBakeLighting

相關文章
相關標籤/搜索