<script type="x-shader/x-vertex" id="vertexshader">
			varying vec2 vUv;
			void main() {
				vUv = uv;
				gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
			}
		</script>

		<script type="x-shader/x-fragment" id="fragmentshader">
			uniform sampler2D baseTexture;
			uniform sampler2D bloomTexture;
			varying vec2 vUv;
			vec4 getTexture( sampler2D texelToLinearTexture ) {
				return mapTexelToLinear( texture2D( texelToLinearTexture , vUv ) );
			}
			void main() {
				gl_FragColor = ( getTexture( baseTexture ) + vec4( 1.0 ) * getTexture( bloomTexture ) );
			}
		</script>
<canvas id="scene"></canvas>
@import url('https://fonts.googleapis.com/css?family=Roboto+Condensed')
html,
body
  padding: 0
  margin: 0
  height: 100%
  overflow: hidden
  font-family: 'Roboto Condensed', sans-serif
  cursor: none
  &:hover
    #cursor
      opacity: 1
    
    
canvas
  display: block
  
View Compiled
const API = {
  bloomStrength: 5,
  bloomThreshold: 0,
  bloomRadius: .5
};
var ENTIRE_SCENE = 0, BLOOM_SCENE = 1; 1;
var bloomLayer = new THREE.Layers();
bloomLayer.set( BLOOM_SCENE );


var startTime = Date.now();
var matrix = new THREE.Matrix4();
var quaternion = new THREE.Quaternion();
const cursor = document.body.querySelector("#cursor");
const thumb = document.body.querySelector("#cursor .focus");
class App {
  constructor({ container, caption }) {
    this.caption = caption;
    this.zoom = false;
    this.focusOffset = 0;
    this.sizes = {
      width: document.body.offsetWidth,
      height: document.body.offsetHeight,
      halfWidth: document.body.offsetWidth * 0.5,
      halfHeight: document.body.offsetHeight * 0.5
    };
    this.currentName = null;
    this.mouse = new THREE.Vector2(0.0625, 0.0625);
    this.target = new THREE.Vector2(this.mouse.x, this.mouse.y);
    this.renderer = new THREE.WebGLRenderer({
      canvas: container,
      alpha: false,
      stencil: false,
      depth: false,
      powerPreference: "high-performance",
      antialias: true
    });
    this.renderer.shadowMap.enabled = true;
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(
      75,
      this.sizes.width / this.sizes.hegiht,
      0.1,
      1000
    );
    this.camera.focus = 20;
    this.camera.rotation.order = "YXZ";
    this.wagon = new THREE.Object3D();
    this.camera.position.set(0, 1.25, 6);
    this.wagon.add(this.camera);
    this.camera.lookAt(0, 1.5, 0);
    this.scene.add(this.wagon);
    // this.setSphereMap();
    this.setGround();
    this.setLight();
    this.setPasses();
    this.setMain();
    this.render();
    window.addEventListener("resize", () => this.handleResize(), {
      passive: true
    });
    window.addEventListener("mousemove", e => this.handleMousemove(e), false);
    window.addEventListener("touchmove", e => this.handleMousemove(e), false);
  }
  setGround() {
    var geometry = new THREE.PlaneBufferGeometry(200, 200, 1, 1);
    geometry.rotateX(-Math.PI * 0.5);
    var material = new THREE.MeshStandardMaterial({
      roughness: 0.8,
      color: 0xffffff,
      metalness: 1,
      bumpScale: 0.005
    });

    var textureLoader = new THREE.TextureLoader();

    textureLoader.load(
      "https://threejs.org/examples/textures/hardwood2_bump.jpg",
      function(map) {
        map.wrapS = THREE.RepeatWrapping;
        map.wrapT = THREE.RepeatWrapping;
        map.anisotropy = 4;
        map.repeat.set(80, 192);
        material.bumpMap = map;
        material.needsUpdate = true;
      }
    );
    textureLoader.load(
      "https://threejs.org/examples/textures/hardwood2_roughness.jpg",
      function(map) {
        map.wrapS = THREE.RepeatWrapping;
        map.wrapT = THREE.RepeatWrapping;
        map.anisotropy = 4;
        map.repeat.set(80, 192);
        material.roughnessMap = map;
        material.needsUpdate = true;
      }
    );
    var plane = new THREE.Mesh(geometry, material);
    plane.position.y = 0;
    this.scene.add(plane);
  }
  setLight() {
    this.light = new THREE.Object3D()
    this.scene.add(this.light)
    
    // light.castShadow = true;
    var geometry = new THREE.CylinderGeometry( .1, .1, 4, 32 );
    var material = new THREE.MeshBasicMaterial( {
					color: 0x14fd3e
				} );
    var cylinder = new THREE.Mesh( geometry, material );
    cylinder.layers.enable( BLOOM_SCENE );

    const count = 10
    for(let i = 0; i <= count; i ++) {
      const l = new THREE.PointLight(0x14fd3e, 1, 100, 2);
      l.power = 2
      l.position.set(i* 5 - count*.5 * 5, 2, -10);
      l.add( cylinder.clone() );

      this.light.add(l)
    }
    

    var sgeometry = new THREE.SphereBufferGeometry( .5, 16, 8 );
    let spotlight =  new THREE.DirectionalLight( 0xadd8e6, 0.00525 );
    let smaterial = new THREE.MeshBasicMaterial( {
      color: 0xadd8e6
    } );
    const spot =  new THREE.Mesh( sgeometry, smaterial )
    spot.layers.enable( BLOOM_SCENE );
    spotlight.add(spot );
    spotlight.position.set( -25, 20, -20 );
    spotlight.castShadow = false;
    spotlight.target = new THREE.Vector3(3, 0, -10)
    var targetObject = new THREE.Object3D();
    targetObject.position.set(4, 0, 20)
    this.scene.add(targetObject);
    spotlight.target = targetObject;
    
    
    this.light.add( spotlight );
    const b2 = spotlight.clone()
    b2.position.set( 25, 20, -20 );
    this.light.add( b2 );
    var targetObject = new THREE.Object3D();
    targetObject.position.set(-4, 0, 20)
    this.scene.add(targetObject);
    b2.target = targetObject;
  }
  setPasses() {
    this.renderScene = new THREE.RenderPass(this.scene, this.camera);
    this.bloomPass = new THREE.UnrealBloomPass(
      new THREE.Vector2(this.sizes.width, this.sizes.hegiht),
      1.5,
      0.4,
      0.85
    );
    this.bloomPass.threshold = API.bloomThreshold;
    this.bloomPass.strength = API.bloomStrength;
    this.bloomPass.radius = API.bloomRadius;
    
    this.composer = new THREE.EffectComposer(this.renderer);
    this.composer.renderToScreen = false;
    this.composer.addPass(this.renderScene);
    this.composer.addPass(this.bloomPass);
    
   const finalPass = new THREE.ShaderPass(
      new THREE.ShaderMaterial( {
        uniforms: {
          baseTexture: { value: null },
          bloomTexture: { value: this.composer.renderTarget2.texture }
        },
        vertexShader: document.getElementById( 'vertexshader' ).textContent,
        fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
        defines: {}
      } ), "baseTexture"
    );
    finalPass.needsSwap = true;
    this.finalComposer = new THREE.EffectComposer( this.renderer );
    this.finalComposer.addPass( this.renderScene );
    this.finalComposer.addPass( finalPass );

  }
  handleMousemove(e) {
    e.preventDefault();

    const { pageX: x, pageY: y } =
      event.touches && event.touches[0] ? event.touches[0] : event;
    this.mouse.x = x / this.sizes.width * 2 - 1;
    this.mouse.y = -(y / this.sizes.height) * 2 + 1;
    this.target.x = 0.125 * this.mouse.x;
    this.target.y = 0.09765625 * this.mouse.y;
  }
  getScreenXY(position) {
    const { halfWidth, halfHeight } = this.sizes;
    var vector = position.clone();
    this.camera.updateProjectionMatrix();
    vector.project(this.camera);
    return vector;
  }
  render() {
    requestAnimationFrame(() => this.render());

    this.focusOffset = Math.max(
      Math.min(this.focusOffset + (this.zoom ? 0.005 : -0.025), 1),
      0
    );
    this.wagon.rotation.y += (this.target.x - this.wagon.rotation.y) * 0.04;
    this.camera.updateProjectionMatrix();

    this.camera.layers.set( BLOOM_SCENE );
    this.composer.render();
    this.camera.layers.set( ENTIRE_SCENE );
    this.finalComposer.render();
  }
  setMain() {
    const {width , height} = this.sizes
    this.camera.aspect = width / height;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(width, height);
  	this.composer.setSize( width, height );
    this.finalComposer.setSize( width, height );
  }
  handleResize() {
    this.sizes.width = document.body.offsetWidth;
    this.sizes.height = document.body.offsetHeight;
    this.sizes.halfWidth = this.sizes.width * 0.5;
    this.sizes.halfHeight = this.sizes.height * 0.5;
    this.setMain();
  }
}
const app = new App({
  container: document.body.querySelector("#scene")
});
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.min.js
  2. https://threejs.org/examples/js/postprocessing/EffectComposer.js
  3. https://threejs.org/examples/js/postprocessing/RenderPass.js
  4. https://threejs.org/examples/js/postprocessing/ShaderPass.js
  5. https://threejs.org/examples/js/shaders/CopyShader.js
  6. https://threejs.org/examples/js/shaders/LuminosityHighPassShader.js
  7. https://threejs.org/examples/js/postprocessing/UnrealBloomPass.js