Search code examples
three.jsshadertextures3d-rendering

Two Textures on one Object Three js


My goal is to render two different textures on one object.

I'm trying to render the earth with a night texture and a day texture, similar to this: http://stuffin.space .

The problem is that I'd still like to use the Three.js classes, so that I can add a bump map and phong reflection using the MeshPhongMaterial class, without having to write the whole shaders.

I thought about having two objects with one being transparent on one side or extend the MeshPhongMaterial class, but it seems to be pretty hard.

Is there a simple solution to solve this with three.js ?


Solution

  • You can assign a function to a material's onBeforeCompile property.

    It get's passed an object that has the source for both the vertex and fragment shaders and the uniforms. As in

    someMaterial.onBeforeCompile = function(shader) {
      console.log(shader.vertexShader);
      console.log(shader.fragmentShader);
    });
    

    You modify the shaders as in

    someMaterial.onBeforeCompile = function(shader) {
      shader.fragmentShader = shader.fragmentShader.replace(thingToReplace, replacement);
    });
    

    The shader source is "pre expanded" meaning it's a three.js specific format. For example the default fragment shader source when run above might look something like

    #include <common>
    #include <color_pars_fragment>
    #include <uv_pars_fragment>
    #include <uv2_pars_fragment>
    #include <map_pars_fragment>
    #include <alphamap_pars_fragment>
    #include <aomap_pars_fragment>
    #include <lightmap_pars_fragment>
    #include <envmap_pars_fragment>
    #include <fog_pars_fragment>
    #include <specularmap_pars_fragment>
    #include <logdepthbuf_pars_fragment>
    #include <clipping_planes_pars_fragment>
    void main() {
        #include <clipping_planes_fragment>
        vec4 diffuseColor = vec4( diffuse, opacity );
        #include <logdepthbuf_fragment>
        #include <map_fragment>
        #include <color_fragment>
        #include <alphamap_fragment>
        #include <alphatest_fragment>
        #include <specularmap_fragment>
        ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
        #ifdef USE_LIGHTMAP
            reflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;
        #else
            reflectedLight.indirectDiffuse += vec3( 1.0 );
        #endif
        #include <aomap_fragment>
        reflectedLight.indirectDiffuse *= diffuseColor.rgb;
        vec3 outgoingLight = reflectedLight.indirectDiffuse;
        #include <envmap_fragment>
        gl_FragColor = vec4( outgoingLight, diffuseColor.a );
        #include <premultiplied_alpha_fragment>
        #include <tonemapping_fragment>
        #include <encodings_fragment>
        #include <fog_fragment>
    }
    

    Looking through all those snippets you can try to figure out which part to replace. My guess for you is the #include <color_fragment> part based on this article