经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
游戏编程精粹学习 - 使用定点颜色插值模拟实时光照
来源:cnblogs  作者:HONT  时间:2019/5/20 8:38:42  对本文有异议

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

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

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

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

 

优点

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

缺点:

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

 

 

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

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

 

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

  1. public class LightingRuntime : MonoBehaviour
  2. {
  3. public Transform virtualLight;
  4. public Color virtualLightCol;
  5. public SkinnedMeshRenderer testRenderer;
  6. void Update()
  7. {
  8. var lightDir = (virtualLight.position - transform.position).normalized;
  9. lightDir = Vector3.ProjectOnPlane(lightDir, Vector3.up);
  10. var lightDir_vec2 = new Vector2(lightDir.x, lightDir.z);
  11. var blend1 = Mathf.Clamp01(Vector2.Dot(lightDir_vec2, Vector2.up));
  12. var blend2 = Mathf.Clamp01(Vector2.Dot(lightDir_vec2, Vector2.down));
  13. var blend3 = Mathf.Clamp01(Vector2.Dot(lightDir_vec2, Vector2.left));
  14. var blend4 = Mathf.Clamp01(Vector2.Dot(lightDir_vec2, Vector2.right));
  15. var vec4 = new Vector4(blend1, blend2, blend3, blend4);
  16. testRenderer.material.SetVector("_TestLight", vec4);
  17. testRenderer.material.SetVector("_TestLightCol", virtualLightCol);
  18. }
  19. }

 

传入4个权重代表4个方向,然后shader部分根据4个方向的权重乘起来即可。

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

  1. v2f vert (appdata v)
  2. {
  3. v2f o = (v2f)0;
  4. o.vertex = UnityObjectToClipPos(v.vertex);
  5. o.uv = TRANSFORM_TEX(v.uv, _MainTex);
  6. o.uv2 = v.uv2;
  7. o.uv3 = v.uv3;
  8. return o;
  9. }
  10. fixed4 frag (v2f i) : SV_Target
  11. {
  12. fixed4 lightVolume = i.uv2.x * _TestLight.x + i.uv2.y * _TestLight.y + i.uv3.x * _TestLight.z + i.uv3.y * _TestLight.w;
  13. return lightVolume * _TestLightCol;
  14. }

 

但是占用uv2,uv3有点占用带宽,于是想了一个办法,左右和前后的方向可以各用一个镜像:

  1. left = 1 - right;

用镜像之前需要记录4个方向,现在只需记录2个。但是要考虑一些长期阴影的区域,所以还需加些参数调节去缓解。

 

优化了一下,将uv2作为光照信息,并镜像了烘焙到顶点上的光照(输出的uv2是float4),以及微调参数:

  1. v2f vert (appdata v)
  2. {
  3. v2f o = (v2f)0;
  4. o.vertex = UnityObjectToClipPos(v.vertex);
  5. o.uv = TRANSFORM_TEX(v.uv, _MainTex);
  6. o.uv2.xz = v.uv2.xy;
  7. o.uv2.y = (1 - v.uv2.x) - 0.8;
  8. o.uv2.w = (1 - v.uv2.y) - 1;
  9. return o;
  10. }
  11. fixed4 frag (v2f i) : SV_Target
  12. {
  13. fixed lightVolume = dot(i.uv2, _TestLight);
  14. return lightVolume * _TestLightCol;
  15. }

 

 

最终效果:

 

测试工程地址:

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

原文链接:http://www.cnblogs.com/hont/p/10887615.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号