游戏编程精粹学习 - 使用定点颜色插值模拟实时光照

Posted hont

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏编程精粹学习 - 使用定点颜色插值模拟实时光照相关的知识,希望对你有一定的参考价值。

终于有空看点新东西,这一篇在《游戏编程精粹1》的5.3节中,主要讲通过烘焙前后左右4个方向光照并插值,来代替顶点光照的做法。

看了下原文例程的代码,似乎是放在cpu部分处理的顶点色,或可能只是参考用的脚本。

这种烘焙4个方向的做法或许优于顶点光照,但缺点是光线角度较为固定,原文描述早期的足球游戏有使用到。

 

优点

  • 优化好比顶点光照更快
  • 精度比光照探针高
  • 可以代替lod2,lod3级别物件的光照

缺点:

  • 只对俯视角、平视角支持比较好
  • 占用一个uv数据

 

 

首先写一个简单的兰伯特光照烘焙四个方向:

技术图片

 

插值的计算用了比较偷懒的做法,原文是转角度进行处理,由于y方向固定,这里直接用Vector2点乘。

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个方向的权重乘起来即可。

可以用uv2,uv3来储存4个方向的光照信息。

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有点占用带宽,于是想了一个办法,左右和前后的方向有一个可以用镜像来达到:

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.x = v.uv2.x;
    o.uv2.y = (1 - v.uv2.x) - 0.8;
    o.uv2.z = v.uv2.y;
    o.uv2.w = (1 - v.uv2.y) - 1;

    return o;
}

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

 

最终效果:

技术图片

 

测试工程地址:

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

以上是关于游戏编程精粹学习 - 使用定点颜色插值模拟实时光照的主要内容,如果未能解决你的问题,请参考以下文章

Tesselation学习

游戏编程精粹学习 - 使用Bloom过滤来提高计算性能(BloomFilter)

游戏编程精粹学习 - 可预测随机数

游戏编程精粹学习 - 一种快速的圆柱棱台相交测试算法

逐顶点光照 逐像素光照 差异对比

逐顶点光照 逐像素光照 差异对比