Created
September 16, 2025 20:13
-
-
Save sketchpunk/633272faf3ec37767db5686059c86fc1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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