(抱歉一下,前面理解有错误,被误导的同学抱歉了)
本来想记录这个文章的:Image-based ambient lighting(比较属于作者拍脑袋想出来的,不是理论推出来的)
http://blog.wolfire.com/2010/03/Image-based-ambient-lighting
但是下面评论的这个给出的链接更好一些,所以反客为主了,:)
Shading in Valve’s Source Engine:
http://www.valvesoftware.com/publications/2006/SIGGRAPH06_Course_ShadingInValvesSourceEngine.pdf
当时06年siggraph的一个course,但是这个是直接介绍valve的source engine的技术,工程性意义很大。
上来先分析面向硬件平台,06年时候我的x1600就这么点人用啊,:(
可以看出shading技术主要针对nv6到7系列,可见xbox360渲染能力当时优势有多大
笔记主要包括lightmap和irradiance volume(动态物体从静态场景拿到的间接光照)。
lightmap,一般做法是直接offline计算从这个点出射的光(exit radiance),然后存在texture里。
valve目标是:
- offline cook任意数量的diffuse lighting
- 这些lighting是准确的(不是n个方向的光合成一个方向的光)
- lightmap仍旧保持低精度
- 和高精度的normal map作用,可以表达出高精度normalmap和周围任意静态光源作用出来的结果
理论推导:
这里做法本质上是把normal分解成3个正交向量。
考虑dot(n,l1)
n可以表达为a*base0 + b*base1 + c*base2----base0,base1,base2为正交单位向量
a == dot(base0,n);b == dot(base1,n);c==dot(base2,n);
so:
dot(n,l1)==
a*dot(base0,l1)+b*dot(base1,l1)+c*dot(base2,l1);
进一步考虑dot(n,l1)+dot(n,l2)->
a*dot(base0,l1)+b*dot(base1,l1)+c*dot(base2,l1)+a*dot(base0,l2)+b*dot(base1,l2)+c*dot(base2,l2)->
a*(dot(base0,l1)+dot(base0,l2)+
b*(dot(base1,l1)+dot(base1,l2)+
c*(dot(base2,l1)+dot(base2,l2)
上面l1,l2是入射光,n是normal,a,b,c是normal n在正交单位向量上的投影,可以看出对于2个光源和nromal n的dot的和可以分解成a*(dot(base0,l1)+dot(base0,l2)+b*(dot(base1,l1)+dot(base1,l2)+c*(dot(base2,l1)+dot(base2,l2)
这样每个入射光和base0,base1,base2做dot,然后加起来,存起来,实时计算的时候,取出normal map里的normal,和base0,base1,base2做dot算出a,b,c然后带入a*(dot(base0,l1)+dot(base0,l2)+b*(dot(base1,l1)+dot(base1,l2)+c*(dot(base2,l1)+dot(base2,l2)
就可以算出dot(n,l1)+dot(n,l2)了。
而且结果是没有折中的,理论正确的。
实现步骤:
每个lighting转到tangent space和三个basis vector做dot,结果乘以lighting rgb,和之前的lighting结果加起来,存入lightmap。
结果lightmap一共3张,每张rgb三个channel。
realtime计算的时候是result = light_map_color0*dot(normal,basis_vector0)+
light_map_color1*dot(normal,basis_vector1)+
light_map_color2*dot(normal,basis_vector2)
最后的tradeoff是3倍普通lightmap消耗,但是得到了可以和normalmap交互的lightmap。
然后是irradiancevolume部分,也不是存sh系数,而是变成xyz方向上的lightingcolor(rgb)。
然后就是直接用。
后面locallighting,没什么意思,跳过。
最后一个hdr部分,是用rgba8的rendertarget,也没有特别的encoding,就是在lighting shader输出的时候做tonemapping,然后才输出,而不是存好floating的rendertarget,然后tonemapping的典型(也很费)的做法。
然后计算luminance来指导下一帧怎么做tonemapping那部分比较“怪”,是统计出来一个亮度的histogram,这个在其他engine里也见过类似做法,文中说是相比一个平均的luminance可以给designer更好的灵活性。这个没看出来有啥特别的灵活性,实际试验中换成一般的平均luminance也没啥不一样,怪怪!
反客为主到此告一段落,http://blog.wolfire.com/2010/03/Image-based-ambient-lighting这里说的一个是一种简化irradiancevolume做法,直接弄一个cubemap存储环境光(比如褐色的大地和蓝色的天空),然后model渲染的时候直接sample就好。
这个在室外场景的确很有实用价值。