selective volumetric
by bemuse
HTML
<canvas id="canvas"></canvas>
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://threejs.org/examples/js/postprocessing/ShaderPass.js"></script>
<script src="https://threejs.org/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://threejs.org/examples/js/shaders/CopyShader.js"></script>
CSS
body{
background: black;
}
#canvas{
position: absolute;
top: 0;
left: 0;
}
JavaScript
// variable
const width = window.innerWidth, height = window.innerHeight
const canvas = document.querySelector('#canvas')
const volumetricLightShader = {
uniforms: {
tDiffuse: {value: null},
lightPosition: {value: new THREE.Vector2(0.5, 0.5)},
exposure: {value: 0.18},
decay: {value: 0.95},
density: {value: 0.8},
weight: {value: 0.4},
samples: {value: 50}
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`,
fragmentShader: `
varying vec2 vUv;
uniform sampler2D tDiffuse;
uniform vec2 lightPosition;
uniform float exposure;
uniform float decay;
uniform float density;
uniform float weight;
uniform int samples;
const int MAX_SAMPLES = 100;
void main(){
vec2 texCoord = vUv;
vec2 deltaTextCoord = texCoord - lightPosition;
deltaTextCoord *= 1.0 / float(samples) * density;
vec4 color = texture2D(tDiffuse, texCoord);
float illuminationDecay = 1.0;
for(int i=0; i < MAX_SAMPLES; i++){
if(i == samples){
break;
}
texCoord -= deltaTextCoord;
vec4 SSS = texture2D(tDiffuse, texCoord);
SSS *= illuminationDecay * weight;
color += SSS;
illuminationDecay *= decay;
}
gl_FragColor = color * exposure;
}
`
}
const finalShader = {
uniforms: {
baseTexture: {value: null},
vTexture: {value: null},
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`,
fragmentShader: `
uniform sampler2D...