3D Cloud shadertoy抄入
2019-02-15 本文已影响0人
万里_aa3f
3D Cloud shadertoy抄入

源码来自iq的shadertoyhttps://www.shadertoy.com/view/XslGRr
其中光照部分的算法,没看太懂。但代码结构简单清晰。还是有些参数的作用还是能猜出个大概。
在此先记录下来,以供今后的学习
此篇亦是基于Ray Marching
3D Cloud实现思路:
从摄像机开始步进,进入worldPos的y值进入云层范围,将其传入分形后的3DNoise进行采样求出当前坐标点的雾浓度。然后根据求得的值进行lighting与Alpha的计算。再次步进,再次重复上面的lighting与Alpha的计算。将计算结果叠加。最总,光线穿过云层或浓度达到一定的值 停止计算。
1.3D noise与分形
2.raymarching的方法
3.lighting计算
4.总render
1.3D noise与分形
value Noise+FBM (只展示了FBM5)
float VNoise(float3 p)
{
float3 pi = floor(p);
float3 pf = p - pi;
float3 w = pf * pf * (3.0 - 2.0 * pf);
return lerp(
lerp(
lerp(Hash13(pi + float3(0, 0, 0)), Hash13(pi + float3(1, 0, 0)), w.x),
lerp(Hash13(pi + float3(0, 0, 1)), Hash13(pi + float3(1, 0, 1)), w.x),
w.z),
lerp(
lerp(Hash13(pi + float3(0, 1, 0)), Hash13(pi + float3(1, 1, 0)), w.x),
lerp(Hash13(pi + float3(0, 1, 1)), Hash13(pi + float3(1, 1, 1)), w.x),
w.z),
w.y);
}
float FBM5( float3 p )
{
p*=uv2;
float n = 0.0;
n += 0.50000*VNoise( p*1.0 );
n += 0.25000*VNoise( p*2.0 );
n += 0.12500*VNoise( p*4.0 );
n += 0.06250*VNoise( p*8.0 );
n += 0.03125*VNoise( p*16.0 );
return clamp( 1.5 - p.y - 2.0 + 1.75*n, 0.0, 1.0 );
}
2.raymarching
将解释写在代码注释上
float4 raymarch( float3 ro, float3 rd, float3 bgcol)
{
float4 sum = float4(0,0,0,0);
float t = 0.0;//0.05*texelFetch( iChannel0, px&255, 0 ).x;
MARCH(30,FBM5);
MARCH(30,FBM4);
MARCH(30,FBM3);
MARCH(30,FBM2);
return clamp( sum, 0.0, 1.0 );
}
#define MARCH(STEPS,MAPLOD) \
for(int i=0; i<STEPS; i++)\
{\
float3 pos = ro + t*rd;\
//减少不必要的步进运算 云层控制在-3到2 浓度>0.99 停止步进
if( pos.y<-3.0 || pos.y>2.0 || sum.a > 0.99 ) break;\
//查看校验这次步进达到的地方有没有云的分布:密度
float den = MAPLOD(pos);\
if( den>0.01 )\ //如果浓度大于0,进行dif 计算
{\
//像太阳方向步进 0.3 看该处云的值
float dif = clamp((den - MAPLOD(pos+0.3*sundir))/0.6, 0.0, 1.0 );\
//积分光照
sum = integrate( sum, dif, den, bgcol, t );\
}\
//每次至少步进0.05,或者是 t已经步进的距离的0.02倍
t += max(0.05,0.02*t);\
}
3.Lighting计算
float4 integrate( float4 sum, float dif, float den, float3 bgcol, float t )
{
// lighting
float3 lin = float3(0.65,0.7,0.75)*1.4 + float3(1.0, 0.6, 0.3)*dif;
//太阳光的颜色与云朵阴影的颜色
float4 col =float4( lerp( float3(1.0,0.95,0.8), float3(0.25,0.3,0.35), den ), den );
col.xyz *= lin;
//参考云层的散射公式
col.xyz = lerp( col.xyz, bgcol, 1.0-exp(-0.003*t*t) );
// front to back blending
//密度*0.4 为当前的a
col.a *= 0.4;
//再将当前的a乘以颜色
col.rgb *= col.a;
//此层的value * (1-a)
return sum + col*(1.0-sum.a);
}
4.总render
float4 render( float3 ro, float3 rd )
{
// background sky
float sun = clamp( dot(sundir,rd), 0.0, 1.0 );
float3 col = float3(0.6,0.71,0.75) - rd.y*0.2*float3(1.0,0.5,1.0) + 0.15*0.5;
col += 0.2*float3(1.0,.6,0.1)*pow( sun, 8.0 );
// clouds
float4 res = raymarch( ro, rd, col);
col = col*(1.0-res.w) + res.xyz;
// sun glare
col += 0.2*float3(1.0,0.4,0.2)*pow( sun, 3.0 );
return float4( col, 1.0 );
}