threejs物理材质续篇

283 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

上篇提到了一些属性的shader代码。 但是,如果你是第一次去读,你找起来会很麻烦。

怎么个麻烦法呢? 且看源码。 我们用执果索因之法,先来到物理材质的js文件

image.png 除了这个,你发现完全找不到哪里用了shader。

于是,你可能想到,这个应用着色器代码应该是共性,或许在基类Material里面。

好,我们来看

image.png 发现还是找不到。

这说明,应用着色器就不归它管,但是不同的材质就是应用了不同的着色器。 我知道有两个材质肯定有用到,那就是自定义材质,

image.png果然,有用到,我猜着色器文件应该都是放在一起的,所以进去那个文件夹。找physical相关文件,其实是不是该直接搜索文件名的。 然后,找到了这个,

image.png但是,你发现,居然一个uniform 变量都对应不上, 仔细看文件名,确实不是,起名还是挺规范的。 不要紧,下面还有一个文件夹。

image.png看这名字,应该是对了。

但是问题才刚刚开始。 #include 关键字 预编译文件? glsl本身不太可能支持,应该是用了什么扩展,后面肯定是打包成一个文件。

搜不到,也不知到这个include 是引入哪里的文件。 不要紧,我们搜索一下uniform float transparent 。搜不到,于是我想了想,搜opacity。 好吧,就在刚才那个文件里。 试着,搜一下 include后面的文件, 我终于发现了, 原来,include 的文件都是这个shaderChunk下面的。

但是读起来,还是很麻烦,跨文件读麻烦,为啥,因为不能直接转到定义了,而且大量的数学计算,和条件处理,这不是我们通常的代码模块化了, 从某种角度来说, 除了函数和变量定义,它只是简单的把代码分裂开来。 image.png

获取完整的shader代码

于是,我就想,能不能获取完整的shader代码。 我知道,初始化着色器的时候,传给gl的一定是完整的着色器字符串。 所以,我又去找初始化着色器的代码。 这怎么找,回顾一下初始化流程,搜initShader试试,估计也是这个名字,还是没搜到。 直接搜shadersource,它肯定调用了这个方法,这是原生方法。

image.png 果然,找到了。 然后,我只要打个log,把shader打出来,复制粘贴即可。

继续探究

完整代码有了,这样我们探究起来就很方便了。 我们先来直接看最后几行。 最终肯定是要给fragColor赋值,所以我们看它的变化。

image.png

对了,glsl预编译和js材质属性的关系,在这个文件里, 虽然,大部分宏的命名和原属性有关,但也有,在我们看起来毫不相关的。 比如tranparent 。 为什么,我如此在意它,因为开始的时候,我就是为了它,但是却找不到。

image.png

image.png

因为transparent 根本不是直接决定opaque的。

光的来源

好了,我们来逆光分析。

不考虑fog premultipliedAlpha sheen dithering 这些属性的情况,可以看到, 最终光照rgb和alpha是分开的

gl_FragColor = vec4( outgoingLight, diffuseColor.a );

我比较看重 alpha通道的来源,因为我本来就是为了这个才看源码的。

alpha 通道的

gl_FragColor = vec4( outgoingLight, diffuseColor.a ) 
vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;

//这两个是顺序 

#ifdef OPAQUE diffuseColor.a = 1.0; 

#endif 

#ifdef USE_TRANSMISSION diffuseColor.a *= transmissionAlpha + 0.1;

#endif diffuseColor.a *= transmissionAlpha + 0.1;
// 这两也是顺序 #ifdef USE_ALPHAMAP diffuseColor.a *= texture2D( alphaMap, vUv ).g;
#endif 

#ifdef USE_ALPHATEST
if ( diffuseColor.a < alphaTest ) discard;
#endif

看上没有什么问题,但是,实际上 transmissionAlpha 这个很成问题,之前说了,即便开启了transimission , opacity也会影响到alpha。 所以,我们走进这个vec4 transmission,不是我们材质上的属性,js属性到了shader里,换了个变量名 transmissionFactor。

我们可以看到,这个vec transmission 就是由getIBLVolumeRefraction 计算得到。

transmissionAlpha 默认是1 ,然后和 transmission.a按 transmissionFactor混合, 也就是说,假如transmissionFactor是0 ,那么alpha就为1.并不是,不能等于0 ,可以接近,js 0也是false

parameters.transmission ? '#define USE_TRANSMISSION' : ''。

#ifdef USE_TRANSMISSION
	float transmissionAlpha = 1.0;
	float transmissionFactor = transmission;
	float thicknessFactor = thickness;
	#ifdef USE_TRANSMISSIONMAP
		transmissionFactor *= texture2D( transmissionMap, vUv ).r;
	#endif
	#ifdef USE_THICKNESSMAP
		thicknessFactor *= texture2D( thicknessMap, vUv ).g;
	#endif
	vec3 pos = vWorldPosition; //世界坐标
	vec3 v = normalize( cameraPosition - pos );// 视线
	vec3 n = inverseTransformDirection( normal, viewMatrix );//法线
	vec4 transmission = getIBLVolumeRefraction(
		n, v, roughnessFactor, material.diffuseColor, material.specularColor, material.specularF90,
		pos, modelMatrix, viewMatrix, projectionMatrix, ior, thicknessFactor,
		attenuationColor, attenuationDistance );
	totalDiffuse = mix( totalDiffuse, transmission.rgb, transmissionFactor );
	transmissionAlpha = mix( transmissionAlpha, transmission.a, transmissionFactor );
#endif

看到这里,想必大家也累了(我累了),明天再继续。