Chango的数学Shader世界(十九)RayMarch云层(一) —— 造型,优化

21 篇文章 5 订阅
4 篇文章 3 订阅

目的:

在ue4中RayMarch云层效果。

本篇只考虑云层造型。

 

参考:

1.IQ在shadertoy上的Clouds和其引用

https://www.shadertoy.com/view/XslGRr

https://www.shadertoy.com/view/4sfGzS

2.shadertoy上的Simplex3d

https://www.shadertoy.com/view/XtBGDG

 

观察:

目前大部分shader对于云的形状没有物理层面上的推导,都使用三维噪声然后利用fbm。

 

分析:

假设我们现在使用Simplex 3d噪声,结合fbm造出云的形状,那么很简单。Simplex noise在此不说,网上都有。

float fbm(float3 p)
{
	float f;
    f  = 0.50000*simplex3D( p ); p = p*2.01;
    f += 0.25000*simplex3D( p ); p = p*2.02; //from iq
    f += 0.12500*simplex3D( p ); p = p*2.03;
    f += 0.06250*simplex3D( p ); p = p*2.04;
    f += 0.03125*simplex3D( p );
	return clamp(f,0,1);
}

float GainCloud(float3 pos,float CloudSample,float maxHeight,float a,float b)
{
	if(pos.z>0&&pos.z<maxHeight)
	{
		return mfbm(pos/CloudSample,a,b);
	}
	else
	{
		return 0;
	}

但问题很明显:

在我的笔记本1070上,仅ray云层就基本在20fps左右。更别说应用到复杂场景下。

我们在shader中实时手动计算出Simplex3d的操作,称作Procedual的。

相反的,我们知道一个固定的3d pos对应了固定的simplex3dnoise。能否离线储存下来,利用LUT(LookupTable)查询之类的呢?

对于小型云朵,显然可以使用2d分层纹理,或使用3d纹理。

但如果我希望一个大场景,例如主角在穿梭云层,这种就不适合了。大场景离线存储,空间又是个问题。

然后,IQ大神的操作让我看傻眼了:

尽管可能由于光照模型的原因,有些模糊,但穿梭在其中没有明显的重复感。

最重要的是,它在webGL上都能跑到40-60FPS,如果删1,2个fbm,还能更快。

1.IQ的3d noise

从单张rand图上生成。

float msimplex3D(float3 x,float a,float b)
{
	float3 p = floor(x/a);
	float3 f = frac(x/b);
	//chango: cubic interpolation
	f = f*f*(3.0-2.0*f);
	
	float2 uv = (p.xy+float2(37.0,17.0)*p.z) + f.xy;
    float2 rg = Texture2DSample(Material.Texture2D_0,Material.Texture2D_0Sampler,(uv+0.5)/256).yx;
	return -1+2*clamp(lerp( rg.x, rg.y, f.z ),0,1);
}

其中关键在于:

1.
uv = (p.xy+float2(37.0,17.0)*p.z) + f.xy;
2.
(uv+0.5)/256
3.
.yx
4.
lerp( rg.x, rg.y, f.z )

而且,被采样贴图必须是一张256*256的rand贴图,g通道为r通道加上(37,17)。

原文原文引用的shadertoy里一大堆评论,但没有一个真正说清楚这部分的,iq也没有解释。有些关于生成贴图的算法的评论是错误的。网上也找不到解释。

还希望知道原因的读者赐教。

我将我用ue4材质系统画的贴图放上来,(读者要是实现,追求精细最好还是得自己画):

从大致的思路来讲,单位立方体(缩放后)最底下和最上面是uv有偏移的noise图,中间再通过f.z插值。最后*2-1来减少云的密度。

无*2-1:

有*2-1:

 

至于为什么这个偏移是(37,17),因为shadertoy系统提供噪声图就是这样偏移来的。

至于为什么要保证r,g两通道也保持同样偏移。我没思考出原因。

对于这个0.5,去掉云会变得不连续。可能这个(0.5,0.5)+xxx跟Warp模式下纹理寻址有关。

应该是用来作边界融合。因为如果近从我们原来生成的rand图生成noise,并不能保证上下左右无缝拼接。而像下图一样,将边界包含在rand图内后,由于生成noise图时会融合,边界连续起来。

我将0.5改为0.1,0.3,效果也一样,基本上证明了我的猜想。

讲道理应该放在/256以外。我改成

(uv)/256+0.1

也不影响。因为只要x,y分别都有一点偏移,横边界和竖边界就能包含进来。所以IQ原来的代码也没错,但是太蛋疼了。

 

 

--更新

我找到了一篇类似的,可以参考,并对比理解iq的代码。

https://stackoverflow.com/questions/30596055/glsl-using-a-2d-texture-for-3d-perlin-noise-instead-of-procedural-3d-noise

https://www.shadertoy.com/view/MtBGDt

对比之下,iq不需要二次tex2D,效率提升很多

对比之下,IQ的p.xy+f.xy就是上图的p.xy,也就是未偏移UV。

而g相对r的偏移对应了b_offset的+1偏移

 

结语

总的来说,ray云层造型,目前多数是fbm。从生成3d噪声上而言,procedual式,或离线缓存式是正解,但分别有计算量太大和空间量太大的缺点。IQ的2d纹理方法是一种hack,目前还未完全理解。它在实时渲染上的表现是完美的。

下节完善云层的光照模型。

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值