我有一个使用ShaderMaterial的网格,并使用THREE.ShaderLib.phong制服。我也链接了地图,凹凸和世俗地图纹理,并且都很好用。下面是我的代码。

defines = {};
defines[ "USE_MAP" ] = "";
defines[ "USE_BUMPMAP" ] = "";
defines["USE_SPECULARMAP"] = "";

    var uniforms = THREE.UniformsUtils.clone(THREE.ShaderLib.phong.uniforms);
    uniforms.map.value = THREE.ImageUtils.loadTexture('source/images/texture-pink.jpg');
    uniforms.bumpMap.value = THREE.ImageUtils.loadTexture('source/images/texture-pink-bump.jpg');
    uniforms.bumpScale.value = 0.02;
    uniforms.specularMap.value = THREE.ImageUtils.loadTexture('source/images/texture-pink-specular.jpg');

    var parameters = {
        fragmentShader:THREE.ShaderChunk["meshphong_frag"],
        vertexShader:THREE.ShaderChunk["meshphong_vert"],
        defines: defines,
        uniforms: uniforms,
        lights: true,
        fog: false,
        side: THREE.DoubleSide,
        blending: THREE.NormalBlending,
        transparent: (uniforms.opacity.value < 1.0),
        derivatives : true
    };

    material = new THREE.ShaderMaterial(parameters);


以下是我得到的结果。

javascript - 将Three.ShaderLib.phong和次表面散射结合在ThreeJS中-LMLPHP

我有单独的网格地下散射代码。下面是我的代码。

<script id="vertexShader" type="x-shader/x-vertex">
        varying vec3 v_fragmentPos;
        varying vec3 v_normal;

        void main() {

                vec4 mvPositions = modelViewMatrix * vec4( position, 1.0 );
                v_fragmentPos =  (modelMatrix * vec4( position, 1.0 )).xyz;
                v_normal =  (modelMatrix * vec4( normal, 0.0 )).xyz;
                gl_Position = projectionMatrix * mvPositions;
        }
    </script>

<script id="fragment_shader" type="x-shader/x-fragment">
        varying vec3 v_fragmentPos;
        varying vec3 v_normal;
        uniform vec3 u_lightPos;

        void main() {

                vec3 _LightColor0 = vec3(1.0,0.5,0.5);
                float _LightIntensity0 = 2.5;
                vec3 translucencyColor = vec3(0.8,0.2,0.2);
                vec3 toLightVector = u_lightPos - v_fragmentPos;
                float lightDistanceSQ = dot(toLightVector, toLightVector);
                vec3 lightDir = normalize(toLightVector);
                float ndotl = max(0.0, dot(v_normal, lightDir));
                float inversendotl = step(0.0, dot(v_normal, -lightDir));
                vec3 lightColor = _LightColor0.rgb * ndotl / lightDistanceSQ * _LightIntensity0;
                vec3 subsurfacecolor = translucencyColor.rgb * inversendotl / lightDistanceSQ * _LightIntensity0;
                vec3 final = subsurfacecolor + lightColor;
                gl_FragColor=vec4(final,1.0);
        }
    </script>


我在这里Shader - Simple SSS lighting issue找到的相当基本的代码。还有我的材料代码。

sssUniforms = {
   u_lightPos: {type: "v3",value: new THREE.Vector3()}
 };

 var sssMaterial = new THREE.ShaderMaterial({
   uniforms: sssUniforms,
   vertexShader: document.getElementById('vertexShader').textContent,
   fragmentShader: document.getElementById('fragment_shader').textContent,
 });


以下是我通过地下散射得到的结果。

javascript - 将Three.ShaderLib.phong和次表面散射结合在ThreeJS中-LMLPHP

现在,我试图将两者结合起来。我尝试了THREE.UniformsUtils.merge来合并两个制服,并且我很确定将顶点和片段着色器代码结合在一起的方式是错误的。由于它是一个字符串,所以我只复制了两个粘贴在脚本标签中的内容,并且不确定这是否是正确的方法。那么这首先有可能吗?如果可以,那么有人可以指导我。我对javascript有一定的了解,并且开始学到threeJS的知识,但是在打开GL时知识却为零。

任何帮助表示赞赏。

谢谢。

最佳答案

顶点和片段着色器是您与GPU管道进行交谈的方式,合并两个字符串不会产生任何结果,除非您真正了解其背后的机制。

因此,Phong Shading是您在其中将要应用其上的一组顶点的镜面反射+扩散+周围环境读入片段着色器的方式。

javascript - 将Three.ShaderLib.phong和次表面散射结合在ThreeJS中-LMLPHP
[资料来源:维基]

现在,“地下散射”是一种方法,您可以通过该方法来考虑光与材料的相互作用,而通常情况下,您会读取与材料的光相互作用

javascript - 将Three.ShaderLib.phong和次表面散射结合在ThreeJS中-LMLPHP

[来源:Link]

您可以阅读Chapter-16 Nvidia这可以解决您的解决方案的所有数学问题。

我已经为您可以签出次表面散射的解决方案创建了解决方案
Git。这是基于深度图的SSS。

该代码来自pixelnerve

简而言之,您尝试合并三.Phong和Subsurface Scattering,而您可以针对您编写环境的环境扩展相同的示例代码,以编写您的自定义片段着色器(顶点,您可以直接使用此值)。

10-05 21:00