最近尝试实现了一下光线追踪体积光,效果以下:算法
光线追踪(Ray tracing)是三维计算机图形学中的特殊渲染算法,跟踪从眼睛发出的光线而不是光源发出的光线,经过这样一项技术生成编排好的场景的数学模型显现出来。(摘自维基百科)cookie
实现步骤:app
1、在灯光区域生成体积光的载体mesh,即咱们的体积光其实是渲染在mesh上的,所以光线追踪的起点是每一个顶点的位置,并计算出该顶点的视线方向,延视线进行递进:性能
2、在灯光空间生成深度图渲染相机:.net
咱们须要在射线递进的过程当中经过比较深度来判断是否当前点处于光线不可到达的遮挡位置,以此来渲染体积光中的阴影位置,这里我渲染了视空间深度(固然若是考虑直接使用unity的阴影贴图也能够,这样就能够直接为unity灯光添加体积光效果了):3d
Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 vertex : SV_POSITION; float depth : TEXCOORD0; }; v2f vert(appdata_base v) { v2f o; UNITY_INITIALIZE_OUTPUT(v2f, o); o.vertex = UnityObjectToClipPos(v.vertex); o.depth = COMPUTE_DEPTH_01; return o; } fixed4 frag(v2f i) : SV_Target { return EncodeFloatRGBA(i.depth); } ENDCG }
3、光线追踪:code
为了在每次递进后能够方便的采样深度图,我将递进的过程放到了投影空间,而且在投影空间下能够方便的计算每次递进的距离:blog
for (float k = 0; k< RAY_STEP; k++) { float4 curpos = beginPjPos; float3 vdir = pjViewDir.xyz*k*delta; curpos.xyz += vdir; half cdep = LinearLightEyeDepth(-curpos.z); float boardFac = step(-1, curpos.x)*step(-1, curpos.y)*step(-1, curpos.z)*step(curpos.x, 1)*step(curpos.y, 1)*step(curpos.z, 1); curpos = ComputeScreenPos(curpos); half2 pjuv = curpos.xy / curpos.w; #if UNITY_UV_STARTS_AT_TOP pjuv.y = 1 - pjuv.y; #endif #ifdef USE_COOKIE fixed4 cookie = tex2D(internalCookie, pjuv); fixed3 cookiecol = cookie.rgb*cookie.a; #else half2 toCent = pjuv - half2(0.5, 0.5); half l = 1 - saturate((length(toCent) - 0.3) / (0.5 - 0.3)); fixed3 cookiecol = fixed3(l, l, l); #endif half dep = DecodeFloatRGBA(tex2D(internalShadowMap, pjuv)) / internalProjectionParams.w; float shadow = step(cdep, dep) *(1 - saturate(cdep*internalProjectionParams.w)); col.rgb += cookiecol*i.vcol.rgb*delta / 2 * boardFac*shadow; }
Demo GitHub连接请点击http://www.lsngo.net/2017/10/22/unityshader_volumetriclight/ip
更多文章:http://www.lsngo.netci