1/3
2/3
3/3
如何用纯数学公式渲染木纹(SDF+PBR渲染流程)
xxxNeedFor虚空藏xxx
2022年05月06日 00:13

    一是心血来潮,二是看看能不能脱离Texture Based渲染框架。最终结果:

    

    效果和一般PBR差不多,不过由于是computational的,木纹是真实连在一起的,也就是说内部也有,可以随意切开。而且我的SDF模型不管怎么造,都能保证没有啥拉升或者不对齐问题。

参考ShaderToy,看链接:www.shadertoy.com/view/ldscDM 

    这个代码可以看出用Computational Noise可以当作木纹纹理。不过只有木纹颜色,没有NormalMap,DisplacementMap之类的特性。核心代码:

    

代码块
clike
自动换行
复制代码
// Wood shader
        float rings = repramp(length(pos.xz + vec2(NoiseGen(pos*vec3(8.0, 1.5, 8.0)), NoiseGen(-	pos*vec3(8.0, 1.5, 8.0)+4.5678))*0.05)*64.0) / 1.8;
        rings -= NoiseGen(pos *1.0)*0.75;
        texColor = mix(vec3(0.3, 0.19, 0.075)*0.95, vec3(1.0, 0.73, 0.326)*0.4, rings)*1.5;
        texColor = max(vec3(0.0), texColor);
        float rough = (NoiseGen(pos*64.0*vec3(1.0, 0.2, 1.0))*0.1+0.9);
        texColor *= rough;
        texColor = saturate(texColor);
复制成功

转1:优化NoiseGen

    原版用了巨多sin,cos,实时跑,在全占屏情况下会卡。我参考链接的noise生成工具,减少wave数量,结果也能看。

    这个工具还挺方便的,设置好参数,有可视化,能直接拷贝sin/cos组成的数量场和梯度场函数。链接: otaviogood.github.io/noisegen/

    

转2:从数量场构造“Computational NormalMap”

    前面说过,现在只有木纹的颜色。我想加上类似PBR流程中NormalMap的效果。观察Wood Shader代码,可以看出形成木纹的关键是float rings。它是一个3D数量场,如果我用它得到其梯度(法线),再和木板原先的normal混合一下,就能形成类似normalMap的效果。只不过这个“Computational NormalMap”更强,它是无限细节且空间连续的。

    

Computational NormalMap

代码块
clike
自动换行
复制代码
	//生成木纹NormalMap
	float3 tile = float3(1,1,1);
	float woodNEpsilon = NormalEpsilon;
	float3 T = float3(1,0,0);
	float3 B = float3(0,1,0);
	float3 N = float3(0,0,1);
	
	float3 woodN = normalize(float3(
		WoodDisplacement(tile * pos + woodNEpsilon*T) - WoodDisplacement(tile * pos - woodNEpsilon*T),
		WoodDisplacement(tile * pos + woodNEpsilon*B) - WoodDisplacement(tile * pos - woodNEpsilon*B),
		WoodDisplacement(tile * pos + woodNEpsilon*N) - WoodDisplacement(tile * pos - woodNEpsilon*N)
		));

	float normalIntensity = 0.2;
	woodN = normalize(normalIntensity * woodN + minHit.N);
复制成功

    最终效果还算满意。不过细节确实不如那种4K贴图的PBR木纹,倒也不是说纯数学做不到,只是硬件跟不上罢了。而且说到底,大自然本身就是Math Based,哪种方式更加接近自然,其实很难说。

    

    下次把TextureBased木纹也整合到我的SDF渲染流程里,看看效果。