虚幻4中实现简单的raymarch

时间:2022-04-06 04:04:17

    以前一直都是在Directx或者UnityShaderLab里做raymarch,最近在研究虚幻4的Shader所以在虚幻4里简单实现了一下这个。

虚幻4中实现简单的raymarch

我的step数量调得很低。

刚开始其实不好下手,虚幻的渲染架构过于复杂,高度封装,我们无法直接像unityshaderlab一样对shader进行直接编写,如果想直接自己上传shader而绕过虚幻的材质系统,那么成本将是高昂的。首先先简单捋一下虚幻的shader生成过程。第一步我们在材质系统里完成各种节点的编写,这些节点是c++写的,可以在源码的MaterialExpression里找到全部实现。这些节点带有一个Fstring的字符串,里面保存的是HLSL代码。在材质编译的时候,HLSLTranslator会把这些字符串插入到usf提供的shader模板中,最后生成我们需要的shader。生成后的shader可以在材质编辑器的HLSLCode里看到。如果我们想在CustomNode里调用自己的函数,可以在CommonUSF文件中添加。但是可能会导致引擎崩溃,直到4.17版本,虚幻将usf文件暴露出来,在4.17版本我们就能给自己的项目添加usf从而CustomNode就能调用函数了。除此之外,虚幻的材质如何模拟多pass行为也是一个难题,目前4.17的方式是使用多个Render Target来模拟,但是效率低下。

下面是我ray mach的代码

float4 CustomNodeWithTime
(
float3 worldpos,
float3 objpos,
float3 viewdir,
float stepsize,
float steps,
float4 color,
float radius,
float time,
float3 lightdir
)
{
    float3 seconcenter = { 0, 0, 0 };
    float offset = 300 * sin(time);
    float eoff = 0.01;
    seconcenter.x = objpos.x + offset;
    seconcenter.z = objpos.z + offset;
    seconcenter.y = objpos.y;
    for (int i = 0; i <= steps; i++)
    {
        if ((distance(worldpos, objpos) <= radius) || (distance(worldpos, seconcenter) <= radius - 100))
        {
            float3 outposx = { worldpos.x + eoff, worldpos.y, worldpos.z };
            float3 inposx = { worldpos.x - eoff, worldpos.y, worldpos.z };
            float Xdelta = distance(outposx, objpos) - distance(inposx, objpos);
            float3 outposy = { worldpos.x, worldpos.y + eoff, worldpos.z };
            float3 inposy = { worldpos.x, worldpos.y - eoff, worldpos.z };
            float Ydelta = distance(outposy, objpos) - distance(inposy, objpos);
            float3 outposz = { worldpos.x, worldpos.y, worldpos.z + eoff };
            float3 inposz = { worldpos.x, worldpos.y, worldpos.z - eoff };
            float Zdelta = distance(outposz, objpos) - distance(inposz, objpos);
            float3 normal = { Xdelta, Ydelta, Zdelta };             float3 LightColor = saturate(dot(normal, lightdir));
            color.rgb = color.rgb * LightColor;
            return float4(LightColor,1);
            //return color;
        }
          
        worldpos += viewdir * stepsize;
    }     return float4(0, 0, 0, 0);
}

我喜欢在VS里写代码然后再粘贴到CustomNode里

虚幻4中实现简单的raymarch