How would you texture a sphere with a linear gradient with multiple colour-stops?

I’ve been trying to texture a sphere with a verticle linear gradient to act as a stylised sky and have been using the below code to achieve this:

var vertexShader = document.getElementById( 'vertexShader' ).textContent;
	var fragmentShader = document.getElementById( 'fragmentShader' ).textContent;
	var uniforms = {
		topColor:      { type: "c", value: new THREE.Color(0x000000) },
		bottomColor: { type: "c", value: new THREE.Color( 0xC1987C ) },
		offset:         { type: "f", value: 10 },
		exponent:     { type: "f", value: 0.25}
	}

	var skyGeo = new THREE.SphereGeometry( 2000, 32, 15 );
	var skyMat = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: uniforms, side: THREE.BackSide} );

	var sky2 = new THREE.Mesh( skyGeo, skyMat );
	scene.add( sky2 );

along with:

   <script type="x-shader/x-vertex" id="vertexShader">

      varying vec3 vWorldPosition;

      void main() {

        vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
        vWorldPosition = worldPosition.xyz;

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

      }

    </script>

and:

    <script type="x-shader/x-fragment" id="fragmentShader">

      uniform vec3 topColor;

      uniform vec3 bottomColor;
      uniform float offset;
      uniform float exponent;

      varying vec3 vWorldPosition;

      void main() {

        float h = normalize( vWorldPosition + offset ).y;
        gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 );

      }

    </script>

This something I’ve found as I’m not anywhere good enough with shaders to be able to figure them out quite yet. My question is how this could be done with multiple colour-stops instead of just the start and the end colours?

I’ve been searching around for quite a while now with little luck so many thanks in advance to anyone who can help me out!

Hi!
Take a look at this SO answer:


The third example there seems what you’re looking for.
3 Likes

Amazing cheers, I’ll check this out!

Thanks so much for this. Learned a lot from it!

1 Like

@prisoner849 Can we apply these methods to the ExtrudeGeometry? I am having some troubles.

@Uros_Cvijanovic
What troubles do you have with ExtrudeGeometry? What have you tried? Any link to a working live code example?

Hello, @prisoner849, actually I figured it out. I am able to make multiple color gradient shader, but my ultimate goal is to have a single color gradiant with different level of transparacy. Do you know how can this be achieved?

gl_FragColor.a = your_function_to_change_alpha ; ?
I don’t know what approach you used to achieve color gradient on mesh.

My code looks something like this:

private vertexShader() {
        return `
    varying vec3 vUv; 

    void main() {
      vUv = position; 

      vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
      gl_Position = projectionMatrix * modelViewPosition; 
    }
    `
    }

    private fragmentShader(){
        return `
        uniform vec3 color1; 
        uniform vec3 color2; 
        //uniform float positionVlak3;
        varying vec3 vUv;
  
        void main() {
            // y < 0 = transparent, > 1 = opaque
            //float alpha = smoothstep(0.0, 1.0, vUv.z);
            // y < 1 = color1, > 2 = color2
            //float colorMix = smoothstep(1.0, 2.0, vUv.z);
            gl_FragColor = vec4(mix(color1, color2, vUv.z - 15.1), 0.4);
        }
    `
  }

  private addShaderShape(){
    let uniforms = {
        color1: { value: new THREE.Color('#F55250')},
        color2: { value: new THREE.Color('#F5525D')},
    }

    let material =  new THREE.ShaderMaterial({
        uniforms: uniforms,
        fragmentShader: this.fragmentShader(),
        vertexShader: this.vertexShader(),
        transparent: true,
    })
    return material;
  }

Looks nice )
What result do you have? What result do you want to achieve? Any reference pics?

Right now is using two colors, but I would like to have same color with different levels of trasparancy. Basically I want color to gradually decrease in opacity from bottom to the top. I am not quite sure if its possible to achieve this with shaders (I just started working with shaders recently, I didnt explore all possibilities).

0.4 is the value of opacity. Put there your formula to get a float value in range 0..1 that depends, if I got you correctly, on z-value of vUv. :thinking:

Yes, that was inital idea. The effect is not working as expected, the object is basically completely transparent after adding alpha formula to the value of opacity.

Only you know structure and parameters of your geometry.
Put some effort into research of how to cast ranges to 0..1.

You are right, at least I know I am on the right track. Thank you for the assistance!