Skip to content

Instantly share code, notes, and snippets.

@sketchpunk
Created September 16, 2025 20:13
Show Gist options
  • Save sketchpunk/633272faf3ec37767db5686059c86fc1 to your computer and use it in GitHub Desktop.
Save sketchpunk/633272faf3ec37767db5686059c86fc1 to your computer and use it in GitHub Desktop.
import * as THREE from 'three';
export default class SkyGradientMaterial extends THREE.RawShaderMaterial {
static createBox(scl = 1): THREE.Mesh {
const geo = new THREE.BoxGeometry(2, 2, 2);
const mesh = new THREE.Mesh(geo, new SkyGradientMaterial());
mesh.scale.setScalar(scl);
return mesh;
}
static createDome(scl = 1): THREE.Mesh {
const geo = new THREE.SphereGeometry(1, 16, 16);
const mesh = new THREE.Mesh(geo, new SkyGradientMaterial());
mesh.scale.setScalar(scl);
return mesh;
}
constructor(props = {}) {
super();
// Merge custom props with default options
const opts = Object.assign(
{
ramp: [0, '#DCDCDC', 0.3, '#DCDCDC', 0.7, '#60B8D3', 1, '#60B8D3'],
depth: true,
},
props,
);
this.name = 'SkyGradientMaterial';
this.glslVersion = THREE.GLSL3;
this.depthTest = opts.depth;
this.transparent = false;
this.side = THREE.BackSide;
this.uniforms = {
rampWeight: { value: [0, 0, 0, 0, 0, 0, 0, 0] },
rampSize: { value: 0 },
rampColor: {
value: [
new THREE.Color(),
new THREE.Color(),
new THREE.Color(),
new THREE.Color(),
new THREE.Color(),
new THREE.Color(),
new THREE.Color(),
new THREE.Color(),
],
},
};
this.setRamp(opts.ramp);
this.vertexShader = `
in vec3 position;
in vec3 normal;
in vec2 uv;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
out vec3 fragLPos;
void main(){
vec4 wpos = modelMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * viewMatrix * wpos;
fragLPos = position;
}`;
this.fragmentShader = `precision mediump float;
in vec3 fragLPos;
out vec4 outColor;
uniform vec3[8] rampColor;
uniform float[8] rampWeight;
uniform int rampSize;
vec3 colorLerpRamp( vec3[8] color, float[8] wgt, float t, int cnt ){
for( int i=1; i < cnt; i++ ){
if( t <= wgt[ i ] ){
return mix(
color[ i-1 ],
color[ i ],
// smoothstep( wgt[ i-1 ], wgt[ i ] , t )
( t - wgt[ i-1 ] ) / ( wgt[ i ] - wgt[ i-1 ] )
);
}
}
return color[ cnt-1 ];
}
void main(){
outColor.a = 1.0;
// Solid Color
if( rampSize == 1 ){
outColor.rgb = rampColor[0];
return;
}
float t = clamp( fragLPos.y * 0.5 + 0.5 , 0.0, 1.0 );
// t = smoothstep( 0.0, 1.0, t );
outColor.rgb = colorLerpRamp( rampColor, rampWeight, t, rampSize );
// Gamma correction 1.0/2.2 = 0.4545...
outColor.rgb = pow( outColor.rgb, vec3(0.4545) );
}`;
}
setRamp(ramp) {
const cAry = this.uniforms.rampColor.value;
const wAry = this.uniforms.rampWeight.value;
const cnt = Math.min(8, Math.floor(ramp.length / 2));
this.uniforms.rampSize.value = cnt;
let j;
for (let i = 0; i < cnt; i++) {
j = i * 2;
wAry[i] = ramp[j];
cAry[i].set(ramp[j + 1]);
}
return this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment