【UE5】可以实时绘制的体积渲染 【第二章 体积渲染 - 5.渲染章总结】

因为马上就要进入下一个阶段,制作动态编辑体积纹理的模块。

但在这之前,要在这一章做最后一些整理。

  • 首先,我们完成没完成的部分。
  • 其次,最后整理一下图表。
  • 最后,本文附上正在用的贴图

完善Shader

还记得我们之前注释掉了"阶梯纹理修复"的部分吗?
在这里插入图片描述
在这里插入图片描述

在第二章第七节中,我们已经修复了这个阶梯纹理。

CurPos += LocalCamVec * (1 - FinalStepSize);//只留了它

然而,在第三章对Shader进行大幅修改时,我们暂时将其注释掉并未继续处理。现在,我们将重新着手修复这个阶梯纹理问题。

希望你还记得,修复阶梯纹理的原理是将for循环的一步单独再以一个小步FinalStepSize执行一次。
因此,基本上就是将for循环中的内容复制出来,在for之后再运行一次。

//创建变量,从0开始累加沿相机方向步进过程中的总密度
float accumdens = 0;

//Shadow部分
//创建变量,透射率和光线的能量
float transmittance =1;
float3 lightenergy = 0;
//基本和相机方向步进一样,但这些都是常量,不需要写进for里
Density *= StepSize;
LightVector *= ShadowStepSize;
ShadowDensity *= ShadowStepSize;
//一个对数来计算阈值,用来判断光线是否还值得计算
float shadowthresh = -log(ShadowThreshold)/ShadowDensity;

//使用 MaxSteps 作为最大步数进行循环,每次循环执行以下操作
for (int i = 0; i < MaxSteps; i++)
{
    float cursample = PseudoVolumeTexture(Tex, TexSampler, saturate(CurPos), XYFrames, NumFrames).r;// 在当前步进位置进行纹理采样

    //Shadow部分
    if(cursample > 0.001)//如果采样位置没有密度,则跳过
    {
        float3 Lpos = CurPos;//Lpos将作为光线步进的起始位置
        float shadowdist = 0;//和之前的accumdens一样,积累阴影
        
        //自阴影
        for(int s = 0; s < ShadowSteps; s++)
        {
            Lpos += LightVector;//移动步进位置
            float Lsample = PseudoVolumeTexture(Tex, TexSampler, saturate(Lpos), XYFrames, NumFrames).r;//采样
            
            //判断是否在框内,不是则直接break退出for
            float3 shadowboxtest = floor( 0.5+ (abs(0.5-Lpos)));
            //float exitshadowbox = shadowboxtest.x + shadowboxtest.y + shadowboxtest.z;
            float exitshadowbox = dot(shadowboxtest,1);//简短的通道相加
            if(shadowdist > shadowthresh || exitshadowbox >= 1) break;

            shadowdist += Lsample;//累计
        }

        //接收阴影
        float3 dfpos = 2 * (CurPos -0.5) * LocalObjectBoundsMax;//-0.5 * 2,得到一个居中的Bound
        dfpos = LWCToFloat(TransformLocalPositionToWorld(Parameters,dfpos)) - CameraPosWS;//将dfpos转换为世界空间,需要LWC精度所以在代码里转换,减去相机位置
        float dftracedist = 1; //创建四个变量
        float dfshadow = 1;//这是我们最终要的
        float curdist = 0;
        float DistanceAlongTrace = 0;

        for (int d = 0; d < DFSSteps; d++)//又一次的光线步进
        {
            DistanceAlongTrace += curdist;//增加距离
            curdist = GetDistanceToNearestSurfaceGlobal(dfpos);//采样全局距离场,他和蓝图里`DistanceToNearestSurface`是相同函数

            float SphereSize = DistanceAlongTrace * LightTangent;//采样距离场软阴影的球形距离

            dfshadow = min( saturate(curdist/SphereSize),dfshadow);//用小于它的结果来更新变量

            dfpos.xyz += LightVectorWS * dftracedist * curdist;//继续移动位置
            dftracedist *= 1.0001;//增加一个很小的因子
        }

        //更新样本和光能,算法是BeersLaw函数
        cursample = 1 -exp(-cursample * Density);
        lightenergy += exp(-shadowdist * ShadowDensity) * cursample * transmittance * LightColor * dfshadow;//在结果上乘dfshadow
        transmittance *= 1-cursample;
        
        //环境光照部分
        shadowdist = 0;//重置一下阴影距离,继续利用它计算光照

        Lpos = CurPos + float3(0,0,0.025);//新位置
        float Lsample = PseudoVolumeTexture(Tex, TexSampler, saturate(Lpos), XYFrames, NumFrames).r;//采样
        shadowdist += Lsample;

        Lpos = CurPos + float3(0,0,0.05);
        Lsample = PseudoVolumeTexture(Tex, TexSampler, saturate(Lpos), XYFrames, NumFrames).r;//采样
        shadowdist += Lsample;

        Lpos = CurPos + float3(0,0,0.15);
        Lsample = PseudoVolumeTexture(Tex, TexSampler, saturate(Lpos), XYFrames, NumFrames).r;//采样
        shadowdist += Lsample;

        lightenergy += exp(-shadowdist * AmbientDensity) *cursample * SkyColor * transmittance;//累计到光
   
    }

    CurPos += -LocalCamVec;
}

CurPos += LocalCamVec * (1 - FinalStepSize);
float cursample = PseudoVolumeTexture(Tex, TexSampler, saturate(CurPos), XYFrames, NumFrames).r;

//从上面复制过来,使用 FinalStepSize 结果再 Step 一次,进行阶梯修复
    if(cursample > 0.001)
    {
        float3 Lpos = CurPos;
        float shadowdist = 0;
        
        for(int s = 0; s < ShadowSteps; s++)
        {
            Lpos += LightVector;
            float Lsample = PseudoVolumeTexture(Tex, TexSampler, saturate(Lpos), XYFrames, NumFrames).r;
            
            float3 shadowboxtest = floor( 0.5+ (abs(0.5-Lpos)));
            float exitshadowbox = dot(shadowboxtest,1);
            if(shadowdist > shadowthresh || exitshadowbox >= 1) break;

            shadowdist += Lsample;
        }

        float3 dfpos = 2 * (CurPos -0.5) * LocalObjectBoundsMax;
        dfpos = LWCToFloat(TransformLocalPositionToWorld(Parameters,dfpos)) - CameraPosWS;
        float dftracedist = 1; 
        float dfshadow = 1;
        float curdist = 0;
        float DistanceAlongTrace = 0;

        for (int d = 0; d < DFSSteps; d++)
        {
            DistanceAlongTrace += curdist;
            curdist = GetDistanceToNearestSurfaceGlobal(dfpos);

            float SphereSize = DistanceAlongTrace * LightTangent;

            dfshadow = min( saturate(curdist/SphereSize),dfshadow);

            dfpos.xyz += LightVectorWS * dftracedist * curdist;
            dftracedist *= 1.0001;
        }

        cursample = 1 -exp(-cursample * Density);
        lightenergy += exp(-shadowdist * ShadowDensity) * cursample * transmittance * LightColor * dfshadow;
        transmittance *= 1-cursample;
        
        shadowdist = 0;

        Lpos = CurPos + float3(0,0,0.025);
        float Lsample = PseudoVolumeTexture(Tex, TexSampler, saturate(Lpos), XYFrames, NumFrames).r;
        shadowdist += Lsample;

        Lpos = CurPos + float3(0,0,0.05);
        Lsample = PseudoVolumeTexture(Tex, TexSampler, saturate(Lpos), XYFrames, NumFrames).r;
        shadowdist += Lsample;

        Lpos = CurPos + float3(0,0,0.15);
        Lsample = PseudoVolumeTexture(Tex, TexSampler, saturate(Lpos), XYFrames, NumFrames).r;
        shadowdist += Lsample;

        lightenergy += exp(-shadowdist * AmbientDensity) *cursample * SkyColor * transmittance;
   
    }

return float4(lightenergy, transmittance);

整理图表

老样子,我们做整理,消除意大利面可以让我们更直观的感受shader中的各种关系

  1. 将这一部分RayMarching的参数折叠为RayMarchingParameter
    在这里插入图片描述
    在这里插入图片描述

  2. 打包环境和常量参数Constant
    在这里插入图片描述
    在这里插入图片描述

  3. 整理自阴影距离场的变量SelfShadow
    在这里插入图片描述
    在这里插入图片描述

  4. 打包投影的参数ShadowRayParameter
    在这里插入图片描述
    在这里插入图片描述

  5. 最后整理一下ShadowRayMarching输入顺序,按功能排序
    在这里插入图片描述


当前Shader

抄抄党注目

模型

在这里插入图片描述

长宽高100cm,轴居中,双面双材质ID的Cube模型

本文附下载

预览贴图

在这里插入图片描述

长宽高100cm,轴居中,双面双材质ID的Cube模型。

本文附下载

材质球

M_VolRayMarching
MI_VolRayMarching
MI_VolRayMarching_Shadow

父子关系
子实例材质
子实例材质
MI_VolRayMarching
M_VolRayMarching
MI_VolRayMarching_Shadow

在这里插入图片描述

M_VolRayMarching

细节

在这里插入图片描述

图表

在这里插入图片描述

MI_VolRayMarching

父材质为M_VolRayMarching

MI_VolRayMarching_Shadow

父材质为MI_VolRayMarching

  • 细节:
    在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值