Any idea on how to create an sandstorm effect in Unreal Engine 4

Here’s something to get you started. I’m playing with a tornado post process material, so it didn’t take long to modify. This isn’t cheap, it adds 1-5ms on my 280x, but it stays consistently above 60 fps and doesn’t look bad. Doesn’t play nice with Temporal AA or Motion Blur.

To avoid raymarching everywhere, this raytraces a cylinder to get near and far intersection points. Then it raymarches between the intersection points, sampling a rotating noisefield combined with a noisefield moving in x. Uses a directional derivative for lighting, so unfortunately it doesn’t cast shadows.

Here’s the content of the custom nodes:

//CRotateAboutAxis CMOT Float 3

return RotateAboutAxis (MaterialFloat4 (MaterialFloat3 (NormalizedRotationAxis.x,
NormalizedRotationAxis.y, NormalizedRotationAxis.z), (RotationAngle*6.28318548)),
MaterialFloat3 (PivotPoint.x, PivotPoint.y, PivotPoint.z),
MaterialFloat3 (Position.x, Position.y, Position.z));

//RayTraceMarch CMOT Float 4

float3 CylinderOrigin={25000-5000t,0,0};
float CylinderRadius1 = 35000;
float CylinderRadius2 = 25000;
float3 CylinderD = ro - CylinderOrigin;
float CylinderA = dot( rd.xz, rd.xz );
float CylinderArec=1/CylinderA;
float CylinderB = dot( rd.xz, CylinderD.xz );
float CylinderC = dot( CylinderD.xz, CylinderD.xz ) - CylinderRadius1
CylinderRadius1;
float CylinderDiscrim= CylinderBCylinderB - CylinderACylinderC;
float CylinderDiscrimsqrt=sqrt( CylinderDiscrim );
float far=lerp(0,min(scenedepth0.99,max(-(CylinderB-CylinderDiscrimsqrt)CylinderArec,0)),CylinderDiscrim>0);
float near=lerp(0,min(scenedepth
0.99,max(-(CylinderB+CylinderDiscrimsqrt)CylinderArec,0)),CylinderDiscrim>0);
float3 NoiseScale1={20000,10000,20000};
float3 lightvec = normalize(float3(0.687334,0.506979,-0.520138));
float stepsize=1000;
float numsteps=clamp((far-near)/stepsize,0,1000);
float mul=0.0;
float4 sum={0,0,0,0};
for(int i=0;i<numsteps;i++)
{
if( sum.a > 0.99 ) continue;
float rt=near+stepsize
mul
(1+dither);
float3 pos=rtrd+ro;
float3 rotpos=CustomExpression0(Parameters,float3(0,1,0),-t/10,float3(0,pos.y,0)+CylinderOrigin,pos)+pos;
if(pos.z<0||distance(pos,CylinderOrigin)>250000||rt>scenedepth) break;
float cylinderfade=clamp((CylinderRadius2-distance(pos,float3(0,pos.y,0)+CylinderOrigin))/CylinderRadius2,0,1);
float heightfade=pow((CylinderRadius1-pos.z)/CylinderRadius1,3)+0.5;
float spherefade=clamp((250000-distance(pos,CylinderOrigin))/250000,0,1);
float dens=clamp(SimplexNoise3D_TEX((pos+float3(-5000
t,0,0))/NoiseScale1)+0.5SimplexNoise3D_TEX(rotpos/(NoiseScale1/2))+heightfade,0,1)cylinderfadespherefade;
float4 col=float4(dens,dens,dens,dens)float4(0.62,0.45,0.19,1);
float dif=0.1+0.4
(col.w-clamp(SimplexNoise3D_TEX((pos+lightvec
1000+float3(-5000t,0,0))/NoiseScale1)+0.5SimplexNoise3D_TEX((rotpos+lightvec1000)/(NoiseScale1/2))+heightfade,0,1))cylinderfadespherefade;
col.xyz+=dif;
col.rgb
=col.a;
sum=sum+col*(1.0-sum.a);
mul+=1.0;
}
return clamp(sum,0,1);

The dither texture is just 2048x2048 of random noise.

Here’s what it looks like:

Let me know if you have any questions.