MY BLOG DIRECTORY:
YivanLee:专题概述及目录INTRODUCTION:
光线追踪算是比较接近自然真实的渲染方法了,光栅渲染在光线追踪面前感觉就是“邪教”!就拿阴影渲染为例,在光栅渲染里要先把ShadowMap渲染出来,然后在正常渲染的时候再把该点转换到灯光空间与ShadowMap进行比较,然后还出了各种杂七杂八的算法来模拟影子衰减。但是在如今实时光线追踪的新时代,这些都可以“滚了”。
实时光线追踪里渲染影子基本原理非常简单。首先我们发射一堆射线追踪整个场景,然后光线打到场景上,然后我们从这个光线打到的点再沿着灯光方向发射一条射线,如果这条射线被遮挡,说明这个物体在影子里,如果没有则说明这个物体没有在影子里。下面就在Unreal里实现它吧。
MAIN CONTENT:
还是在上一篇中的RaytracingDebug.usf中做如下修改:
[shader("raygeneration")]
void RayTracingDebugMainRGS()
{
uint2 PixelCoord = DispatchRaysIndex().xy;
float2 RenderTargetUV = (float2(PixelCoord) + .5f) * View.BufferSizeAndInvSize.zw;
RayDesc Ray;
Ray.Origin = ReconstructWorldPositionFromDepth(RenderTargetUV, 0.0f);
Ray.Direction = normalize(ReconstructWorldPositionFromDepth(RenderTargetUV, 10000.f) - Ray.Origin);
Ray.TMin = 0.5f; // 1 unit in UE4 = 1 cm -0> 0.5 ==> 5 mm
Ray.TMax = 1e27f;
FRayCone RayCone = (FRayCone)0;
RayCone.SpreadAngle = View.EyeToPixelSpreadAngle;
uint RayFlags = RAY_FLAG_CULL_BACK_FACING_TRIANGLES;
float4 Result = float4(1, 1, 1, 1);
FMaterialClosestHitPayload Payload = TraceRayInternal(
TLAS, // AccelerationStructure
RayFlags,
RAY_TRACING_MASK_ALL,
RAY_TRACING_SHADER_SLOT_MATERIAL, // RayContributionToHitGroupIndex
RAY_TRACING_NUM_SHADER_SLOTS, // MultiplierForGeometryContributionToShaderIndex
0, // MissShaderIndex
Ray, // RayDesc
RayCone
);
half3 N = Payload.WorldNormal * 0.5 + 0.5;
half3 L = half3(1, 1, 1);
if (Payload.HitT > 0)
{
Ray.Origin = Payload.WorldPos;
Ray.Direction = L;
Ray.TMin = 0.5f; // 1 unit in UE4 = 1 cm -0> 0.5 ==> 5 mm
Ray.TMax = 1e27f;
FMaterialClosestHitPayload Payload_Shadow = TraceRayInternal(
TLAS, // AccelerationStructure
RayFlags,
RAY_TRACING_MASK_ALL,
RAY_TRACING_SHADER_SLOT_MATERIAL, // RayContributionToHitGroupIndex
RAY_TRACING_NUM_SHADER_SLOTS, // MultiplierForGeometryContributionToShaderIndex
0, // MissShaderIndex
Ray, // RayDesc
RayCone
);
if (Payload_Shadow.HitT > 0)
Result = 0.1;
else
Result.rgb = dot(N, L);
}
else
Result = 0.5;
Output[PixelCoord] = Result;
}
首先计算屏幕的像素坐标然后构造Ray,然后调用TraceRayInternal向场景发射射线。第一次发射射线打到场景后,重新调整光线的Ray.Origin和 Ray.Direction,然后沿着灯光的方向再次发射射线,这样就能得到我们想要的影子啦。效果如下:
至此我们轻松就渲染出了ShadowMask
但是我们现在算影子的方式还是十分粗暴,直接是硬影子。
直接让遮住灯光的部分是暗的。
下面就来改进这一部分计算。
我想做影子的衰减,所以需要知道距离,幸运的是这对于实时光线追踪来说不是什么难事,首先在第一次hit的时候记录下hit点的位置
然后在第二次向光源追踪的时候打到物体时,再记录下这时的位置
这时我们就能知道d的距离了
有了这个就能求阴影衰减了,我这里为了快速演示给的算法非常trick且粗略(瞎JB算法)。
然后就可以得到如下效果:
SUMMARY AND OUTLOOK:
如今(2019年7月)实时光线追踪还未普及,但是我们制作效果的思路和方法都已经发生了比较大的改变,以前在光栅渲染时代想都不敢想的实时Caustic等效果,现在可以有实现的可能了。
Enjoy it。
NEXT:
todo...