虚幻4渲染编程(光线追踪篇)【第六卷:Shadow in real-time raytracing】

MY BLOG DIRECTORY:

YivanLee:专题概述及目录​zhuanlan.zhihu.com图标

INTRODUCTION:

光线追踪算是比较接近自然真实的渲染方法了,光栅渲染在光线追踪面前感觉就是“邪教”!就拿阴影渲染为例,在光栅渲染里要先把ShadowMap渲染出来,然后在正常渲染的时候再把该点转换到灯光空间与ShadowMap进行比较,然后还出了各种杂七杂八的算法来模拟影子衰减。但是在如今实时光线追踪的新时代,这些都可以“滚了”。

v2-0fb5d95001c9be57e6670b06509a4193_b.jpg

实时光线追踪里渲染影子基本原理非常简单。首先我们发射一堆射线追踪整个场景,然后光线打到场景上,然后我们从这个光线打到的点再沿着灯光方向发射一条射线,如果这条射线被遮挡,说明这个物体在影子里,如果没有则说明这个物体没有在影子里。下面就在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,然后沿着灯光的方向再次发射射线,这样就能得到我们想要的影子啦。效果如下:

v2-190d333c87330932dc9c19039d44c06a_b.gif

至此我们轻松就渲染出了ShadowMask

但是我们现在算影子的方式还是十分粗暴,直接是硬影子。

v2-768e5ca9ab339b39b46f04433b519d4f_b.png

直接让遮住灯光的部分是暗的。

v2-073f04bf5156151184f672377cdaed9e_b.jpg

下面就来改进这一部分计算。

我想做影子的衰减,所以需要知道距离,幸运的是这对于实时光线追踪来说不是什么难事,首先在第一次hit的时候记录下hit点的位置

v2-5c8ce9daffcff05dde0b1dd11f541b4f_b.png

然后在第二次向光源追踪的时候打到物体时,再记录下这时的位置

v2-33f9b84c3b5bfef6fb450facdfd2800b_b.png

这时我们就能知道d的距离了

v2-4a93610149121e7cbf8934dffc717b43_b.jpg

有了这个就能求阴影衰减了,我这里为了快速演示给的算法非常trick且粗略(瞎JB算法)。

v2-8ce6735e33d4cb98ec7b3d8e47d18952_b.jpg

然后就可以得到如下效果:

v2-4c8074a86d46d1c2dbfcc8f4eddbc217_b.gif
v2-b1f64425a0ac91ecc72424dc70f3ad9f_b.jpg

SUMMARY AND OUTLOOK:

如今(2019年7月)实时光线追踪还未普及,但是我们制作效果的思路和方法都已经发生了比较大的改变,以前在光栅渲染时代想都不敢想的实时Caustic等效果,现在可以有实现的可能了。

Enjoy it。


NEXT:

todo...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpongo11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值