上一篇我們分析了Three.js的材質(zhì)Shader的源碼結(jié)構(gòu),本篇在討論一下官方提供的api onBeforeCompile如何使用。
首先官方描述如下:
.onBeforeCompile ( shader : Shader, renderer : WebGLRenderer ) : undefined
An optional callback that is executed immediately before the shader program is compiled. This function is called with the shader source code as a parameter. Useful for the modification of built-in materials.
Unlike properties, the callback is not supported by .clone(), .copy() and .toJSON().
編譯著色器程序之前立即執(zhí)行的可選回調(diào)。將著色器源代碼作為參數(shù)調(diào)用此函數(shù)。用于修改內(nèi)置材料。
與屬性不同,不支持回調(diào)??寺?、復(fù)制、和toJSON。
其實(shí)就是說,我們shader本來就是以字符串的形式傳進(jìn)去執(zhí)行的,你用這個(gè)onBeforeCompile可以在執(zhí)行之前,修改這個(gè)字符串,以達(dá)到自寫shader的目的。
以下是一個(gè)使用案例:
depthMaterial = new THREE.MeshDepthMaterial();
depthMaterial.userData.darkness = { value: state.shadow.darkness };
depthMaterial.onBeforeCompile = function (shader) {
shader.uniforms.darkness = depthMaterial.userData.darkness;
shader.fragmentShader = /* glsl */`
uniform float darkness;
${shader.fragmentShader.replace(
'gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );',
'gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * darkness );'
)}
`;
};
首先需要選擇一個(gè)Material,直接修改模型的Material的話需要先log清楚當(dāng)前到底用的是哪個(gè)shader。然后按照上述格式使用.replace("","")和普通的string.replace用法一樣。
下面分步講解一下:
1.首先定義需要傳入的參數(shù)uniform float darkness;
2.定義需要replace的代碼段'gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );',這里很重要,必須要從官方的源碼里復(fù)制出來,空格也不能少
3.編寫需要替換后的代碼段'gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * darkness );'
4.從材質(zhì)將數(shù)據(jù)傳到shader中shader.uniforms.darkness = depthMaterial.userData.darkness;
5.從js將數(shù)據(jù)傳輸?shù)組aterial中depthMaterial.userData.darkness = { value: state.shadow.darkness };
用法不是很復(fù)雜,最重要的一點(diǎn)就是如果replace找不到第一個(gè)參數(shù),就會(huì)替換失敗,替換失敗也不會(huì)報(bào)錯(cuò),當(dāng)然了也不會(huì)有效果,可以先寫一段錯(cuò)誤代碼比如缺分號(hào)的,去看看是否replace成功,再修改shader代碼。
另外,能替換的僅僅是fragment$6之類的里面的如下圖藍(lán)色選中部分,而橙色部分output_fragment內(nèi)部的代碼是無法替換的。
