three.js

Implementing a Dissolve Effect with Shaders and Particles in Three.js

Dissolve Effect by Jatin Chopra

Implementing a Dissolve Effect with Shaders and Particles in Three.js

  • code
  • glsl
  • three.js
  • tutorial
float noise = cnoise(vPos * uFreq) * uAmp; // calculate cnoise in fragment shader for smooth dissolve edges
    
if(noise < uProgress) discard; // discard any fragment where noise is lower than progress
    
float edgeWidth = uProgress + uEdge;
if(noise > uProgress && noise < edgeWidth){
    gl_FragColor = vec4(vec3(uEdgeColor),noise); // colors the edge
}
    
gl_FragColor = vec4(gl_FragColor.xyz,1.0);

Implementing a Dissolve Effect with Shaders and Particles in Three.js

  • code
  • glsl
  • three.js
  • tutorial
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Transition</title>
</head>

<body></body>

<style>
  body {
    overflow: hidden;
    margin: 0;
  }
</style>

<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.165.0/build/three.module.js",
      "three/addons/": "https://unpkg.com/three@0.165.0/examples/jsm/"
    }
  }
</script>

<script type="module">
  import * as THREE from "three";
  import { OrbitControls } from "three/addons/controls/OrbitControls.js";

  class Transition {
    constructor(scene1, scene2) {
      this.scenes = [scene1, scene2];
      this.uniforms = {
        aspect: {
          value: innerWidth / innerHeight
        },
        action: {
          value: 0
        },
        timeStart: {
          value: -1000
        },
        duration: { value: 3 }
      };

      this.renderTargets = Array.from({ length: 2 }, () => {
        let rt = new THREE.WebGLRenderTarget(innerWidth, innerHeight, { colorSpace: "srgb", samples: 4 });
        return rt;
      })


      this.screen = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), new THREE.ShaderMaterial({
        uniforms: {
          scene0: { value: this.renderTargets[0].texture },
          scene1: { value: this.renderTargets[1].texture },
          aspect: this.uniforms.aspect,
          action: this.uniforms.action,
          time: gu.time,
          timeStart: this.uniforms.timeStart,
          duration: this.uniforms.duration,
        },
        vertexShader: `
        varying vec2 vUv;
        void main(){vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.);}
      `,
        fragmentShader: `
        uniform sampler2D scene0;
        uniform sampler2D scene1;
        uniform float aspect;
        uniform float action;
        uniform float time;
        uniform float timeStart;
        uniform float duration;
        
        varying vec2 vUv;
        
        void main(){
        
          vec2 uv = vUv;
          
          vec4 s0 = texture(scene0, uv);
          vec4 s1 = texture(scene1, uv);
          
          vec2 transUV = (vUv - 0.5) * 2. * vec2(aspect, 1.);
          float d = length(transUV);
          
          float waveWidth = 0.25;
          float halfWave = waveWidth * 0.5;
          float maxLength = sqrt(aspect * aspect + 2.) + waveWidth;
          float currWavePos = -halfWave + maxLength * clamp((time - timeStart) / duration, 0., 1.);
          float f = smoothstep(currWavePos + halfWave, currWavePos - halfWave, d);
          
          vec3 col = mix(s0.rgb, s1.rgb, f);
          
          gl_FragColor = vec4(col, 1.);
          
        }
      `
      }))

      this.camera = new THREE.Camera();
    }

    generateTransitionTexture() {

    }

    render() {
      this.scenes.forEach((s, sIdx) => {
        renderer.setRenderTarget(this.renderTargets[sIdx]);
        renderer.render(s, camera);
      })
      renderer.setRenderTarget(null);
      renderer.render(this.screen, this.camera);
    }

    setRTSize(w, h) {
      this.uniforms.aspect.value = w / h;
      this.renderTargets.forEach(rt => rt.setSize(w, h));
    }
  }

  class SceneFabric extends THREE.Scene {
    constructor(name) {
      super();
      console.log(name)
      let g = name == "sphere" ? new THREE.SphereGeometry() :
        name == "box" ? new THREE.BoxGeometry(2, 2, 2) :
          new THREE.TetrahedronGeometry();
      let m = Math.random() < 0.5 ? new THREE.MeshBasicMaterial() : new THREE.MeshLambertMaterial();
      m.wireframe = Math.random() < 0.5;
      m.color.setHSL(Math.random(), 0.75, 0.75);

      let io = new THREE.InstancedMesh(g, m, 100);
      let dummy = new THREE.Object3D();
      for (let i = 0; i < 100; i++) {
        dummy.position.random().subScalar(0.5).multiplyScalar(50);
        dummy.rotation.set(
          Math.random() * Math.PI * 2,
          Math.random() * Math.PI * 2,
          Math.random() * Math.PI * 2
        );
        dummy.scale.random().multiplyScalar(0.9).addScalar(0.1).multiplyScalar(5);
        dummy.updateMatrix();
        io.setMatrixAt(i, dummy.matrix);
      }

      this.add(io);

      let light = new THREE.DirectionalLight(0xffffff, Math.PI);
      light.position.randomDirection();
      this.add(light, new THREE.AmbientLight(0xffffff, Math.PI * 0.5));
    }
  }

  let scene = new THREE.Scene();
  let camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 1000);
  camera.position.set(0, 0, 60);
  let renderer = new THREE.WebGLRenderer();
  renderer.setSize(innerWidth, innerHeight);
  document.body.appendChild(renderer.domElement);

  window.addEventListener("resize", event => {
    camera.aspect = innerWidth / innerHeight;
    camera.updateProjectionMatrix();
    transition.setRTSize(innerWidth, innerHeight);
    renderer.setSize(innerWidth, innerHeight);
  });

  window.addEventListener("dblclick", event => {
    console.log(t);
    transition.uniforms.timeStart.value = t;
    transition.scenes[0] = scenes[destSceneIndex];
    destSceneIndex = Math.floor(Math.random() * 7);
    transition.scenes[1] = scenes[destSceneIndex];
  })

  let controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;

  let gu = {
    time: { value: 0 }
  }

  let scenes = Array.from({ length: 7 }, () => {
    let geoms = ["sphere", "box", ""];
    return new SceneFabric(geoms[Math.floor(Math.random() * geoms.length * 2) % geoms.length]);
  });
  let destSceneIndex = Math.floor(Math.random() * 5);
  let transition = new Transition(scenes[0], scenes[destSceneIndex]);

  let clock = new THREE.Clock();
  let t = 0;

  renderer.setAnimationLoop(() => {
    let dt = clock.getDelta();
    t += dt;
    gu.time.value = t;
    controls.update();
    transition.render();
    //renderer.render(scene, camera);
  })

</script>

</html>

Scene transition [render targets]

  • code
  • javascript
  • real time
  • renderTarget
  • shader
  • three.js
Geospatial Rendering in Three.js

three-geospatial

Geospatial Rendering in Three.js

  • 3d
  • cloud
  • javascript
  • library
  • react-three-fiber
  • render
  • shader
  • three.js
Three.ez - InstancedMesh2

InstancedMesh2

Three.ez - InstancedMesh2

  • 3d
  • code
  • library
  • performance
  • real time
  • resource
  • three.js
  • webgl
To skim threejs shaderlib glsl sources with foldable shader chunks.

threejs shaderlib glsl

To skim threejs shaderlib glsl sources with foldable shader chunks.

  • 3d
  • code
  • resource
  • shader
  • three.js