• 游戏编程精粹学习


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

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

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

    或许改成贴图的话可以烘焙进一些法线效果,或是做成粒子光照。。

    优点

    • gpu上优于顶点光照
    • 可作为辅助光源使用
    • 较高的精度

    缺点:

    • 消耗一定的cpu
    • 占用一块uv数据
    • 常规烘焙的情况下,只对俯视角、水平视角支持比较好

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

    这4个方向的灯光信息会被烘焙到uv2,uv3中,运行后cpu计算当前角度的权重,到shader里进行混合。

    插值的计算用了比较偷懒的做法,原文是转角度进行处理,由于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.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

  • 相关阅读:
    kafka常见问题汇总
    kafka可视化工具kafkatool
    VB.NET DevExpress GirdView 搜素框界面Find Clear按钮转换为自定义中文
    winform DevExpress GridView复制单元格方法
    DevExPress GridView获取单元格坐标和内容
    Winform Log4Net使用(一)(产生yyyyMMdd'.log)便于每天使用记录一眼能看出哪天使用时出错
    winform 判断重复检测,是否开启相同应用程序 和 线程异常捕获
    winfrom Run状态控件刷新办法
    C# winform Panel自定义移动窗口
    C# 控制台CMD辅助类
  • 原文地址:https://www.cnblogs.com/hont/p/10887615.html
Copyright © 2020-2023  润新知