2

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.

R-yurew
  • 102
  • 7

2 Answers2

2

I've made modifications to your fragment shader:

float f = clamp((vPos.z - bbMin.z) / (bbMax.z - bbMin.z), 0., 1.);

// Calculate distance to center of XY plane
float distCenter = length(vPos.xy);

// Re-map values so it converts from [0.0, 0.2] => [0, 1]
distCenter = smoothstep(0.0, 0.2, distCenter);

// Multiplying by 0 makes the color black
// Multiplying by 1 keeps the color at original value
vec3 col = mix(color1, color2, f) * distCenter;

vec4 diffuseColor = vec4( col, opacity );`

Result:

Flower blends to black as fragment approaches the center: enter image description here

Play with the 0.2 value inside the smoothstep() to make the gradient wider or narrower. If you've never used length() before, you can read more details on it at the Book of Shaders glossary.

M -
  • 26,908
  • 11
  • 49
  • 81
  • This is fantastic, thank you for answering! I was wondering, perhaps what if black was a different color, let's say blue for contrast? What would have to happen to the code in order for it to be a color? – R-yurew Aug 18 '22 at 18:37
1

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);
      }
    });
prisoner849
  • 16,894
  • 4
  • 34
  • 68