Three.js - Fireflies Shader

Aus Wikizone
Version vom 6. Februar 2022, 11:07 Uhr von 134.3.74.15 (Diskussion)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

Links[Bearbeiten]

Three.js - Shaders

Beispiel[Bearbeiten]

script.js

import firefliesVertexShader from './shaders/fireflies/vertex.glsl'
import firefliesFragmentShader from './shaders/fireflies/fragment.glsl'

//...

/**
 * Fireflies
 */
const firefliesGeometry = new THREE.BufferGeometry()
const firefliesCount = 30
const positionArray = new Float32Array(firefliesCount * 3)
const scaleArray = new Float32Array(firefliesCount)
for(let i = 0; i < firefliesCount; i++){
    positionArray[i * 3 + 0] = ( Math.random() -0.5) * 4.5 // from -0.5 to 4
    positionArray[i * 3 + 1] = ( Math.random() + 0.05) * 3 // from 0.05 to 2.95
    positionArray[i * 3 + 2] = ( Math.random() ) * 4.5 // from 0 to 4.5
    scaleArray[i] = Math.random()
}

firefliesGeometry.setAttribute('position', new THREE.BufferAttribute(positionArray, 3))
firefliesGeometry.setAttribute('aScale', new THREE.BufferAttribute(scaleArray, 1))


//const firefliesMaterial = new THREE.PointsMaterial({ size: 0.1, sizeAttenuation: true })
const firefliesMaterial = new THREE.ShaderMaterial({
    transparent: true,
    blending: THREE.AdditiveBlending,
    depthWrite: false, // fixes some clipping issues
    uniforms:{
        uPixelRatio : {value: Math.min(window.devicePixelRatio, 2)},
        uSize: { value: 100 },
        uTime: { value: 0 }
    },
    vertexShader: firefliesVertexShader,
    fragmentShader: firefliesFragmentShader
})
const fireflies = new THREE.Points(firefliesGeometry, firefliesMaterial)
scene.add(fireflies)
gui.add(firefliesMaterial.uniforms.uSize, 'value').min(0).max(500).step(1).name('firefliesSize')

// ...

window.addEventListener('resize', () =>
{
    // ...
    // Update fireflies 
    // Update ratio in case s.o. has different screens
    firefliesMaterial.uniforms.uPixelRatio.value = Math.min(window.devicePixelRatio, 2)
})

vertex.glsl

uniform float uPixelRatio;
uniform float uSize;
uniform float uTime;
attribute float aScale;

void main()
{
    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
    modelPosition.y += sin(uTime + modelPosition.x * 100.0) * aScale * 0.2; 
    // move up and down and use x pos to create a offset
    // * aScale -> reduce Amplitude more for smaller fireflies
    // * 0.2 -> reduce amplitude in general
    vec4 viewPosition = viewMatrix * modelPosition;
    vec4 projectionPosition = projectionMatrix * viewPosition;

    gl_Position = projectionPosition;
    
    // Take care of retinas etc but not more than 2 (performance)
    gl_PointSize = uSize * uPixelRatio * aScale; 
    gl_PointSize *= (1.0 / - viewPosition.z); // size attenuation (far->smaller)

}

fragment.glsl

void main()
{
  //gl_FragColor = vec4(gl_PointCoord, 1.0, 1.0);
  float distanceToCenter = distance(gl_PointCoord, vec2(0.5));
  float strength = 0.05 / distanceToCenter - 0.1; // -0.1 that our formular reaches 0. Otherwise we'd see borders
  gl_FragColor = vec4(1.0, 1.0, 1.0, strength);
}