javascriptthree.jsgeometryvertex-shadergeometry-shader

THREE.JS SHADER: Apply color gradient blend to geometry on multiple axes?


Using the information from Apply color gradient to material on mesh - three.js

I was able to create a flower shader that applies the color vertically across the space of the Zinnia. The color blends vertically across the space of the flower from red to yellow, creating a gradient that responds to height. (see image 1)

selection of vertex shader:

      float f = clamp((vPos.z - bbMin.z) / (bbMax.z - bbMin.z), 0., 1.);
      vec3 col = mix(color1, color2, f);
      vec4 diffuseColor = vec4( col, opacity );

selection of fragment shader:

      gl_FragColor = vec4(mix(color1, color2, vUv.y), 1.0);

The above code shows that the color is properly responding to a blend taking place on the z-axis.

I was also able to create a flower shader that applies the color from the center of the flower outwards, responding to the Y axis, horizontally. The color is black in the center of the rose, and red on the outer edges. (see image 2)

selection of vertex shader:

      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);

selection of fragment shader:

      gl_FragColor = vec4(mix(color1, color2, vUv.y), 1.0);

the above code shows that the color is properly responding to a blend taking place on the y-axis.

(FINALLY!) My question is: how would I combine these two shaders, making the center of the flower blend closer to black, the closer it is to the center while the vertical gradient still exists? The blend from black to red would be happening on the y axis, (or black to transparent, even?) and the blend from red to yellow happening on the z axis? -- I wanted to "darken" the center of the zinnia so that if viewed from profile it doesn't look like a gradient with no definition.

enter image description here

https://codepen.io/ricky1280/pen/zYWyzQv (shader begins on line 271 in html of this pen)

so that the petals are visible from perfect profile view:

enter image description here

https://codepen.io/ricky1280/pen/RwMEgmj (shader begins on line 227 of html in this pen)

just for instance this is the red-yellow shader applied on the rose, the gradient is visible from perfect profile enter image description here

https://codepen.io/ricky1280/pen/dymwRBW (shader begins on line 265 of html in this pen)

(just for instance this is the red-yellow shader applied to the rose, the gradient is visible from profile)

Thank you for reading all of this—I'm lost when I see GLSL, so I hope that someone can help me.


Solution

  • The answer is in your question, if you want to combine those two shaders, then... just combine them :)

    enter image description here

    Material will look like this:

        let material = new THREE.MeshBasicMaterial({
          roughness: 1,
          metalness: 0,
          side: THREE.DoubleSide,
          // map: new THREE.TextureLoader().load("https://threejs.org/examples/textures/floors/FloorsCheckerboard_S_Diffuse.jpg", tex => {
          //   tex.wrapS = THREE.RepeatWrapping;
          //   tex.wrapT = THREE.RepeatWrapping;
          //   tex.repeat.set( 16, 1 );
          // }),
          onBeforeCompile: shader => {
            shader.uniforms.bbMin = uniforms.bbMin;
            shader.uniforms.bbMax = uniforms.bbMax;
            shader.uniforms.color1 = uniforms.color1;
            shader.uniforms.color2 = uniforms.color2;
            shader.uniforms.color3 = uniforms.color3;
            shader.vertexShader = `
            varying vec2 vUv;
            varying vec3 vPos;
          ${shader.vertexShader}
        `.replace(
              `#include <begin_vertex>`,
              `#include <begin_vertex>
        vPos = transformed;
        vUv = uv;
        `
            );
            shader.fragmentShader = `
            uniform vec3 bbMin;
          uniform vec3 bbMax;
          uniform vec3 color1;
          uniform vec3 color2;
          uniform vec3 color3;
          varying vec2 vUv;
          varying vec3 vPos;
          ${shader.fragmentShader}
        `.replace(
              `vec4 diffuseColor = vec4( diffuse, opacity );`,
              `
          float f = clamp((vPos.z - bbMin.z) / (bbMax.z - bbMin.z), 0., 1.);
          vec3 col = mix(color1, color2, f);
          col = mix(color3, col, vUv.x);
          vec4 diffuseColor = vec4( col, opacity );`
            );
            //console.log(shader.vertexShader);
            //console.log(shader.fragmentShader);
          }
        });