<div class="world" id="world">  
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Today's Date</title>
    <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;

    void main() {

      gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );

    }
  </script>


</head>
  
html,
body {
    margin: 0;
    padding: 0;
    background: linear-gradient(#266F92, #111214);
}
import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
import {
  OrbitControls
} from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";
import {
  EffectComposer
} from 'https://cdn.skypack.dev/three@0.136.0/examples/jsm/postprocessing/EffectComposer.js';
import {
  RenderPass
} from 'https://cdn.skypack.dev/three@0.136.0/examples/jsm/postprocessing/RenderPass.js';
import {
  ShaderPass
} from 'https://cdn.skypack.dev/three@0.136.0/examples/jsm/postprocessing/ShaderPass.js';
import {
  UnrealBloomPass
} from 'https://cdn.skypack.dev/three@0.136.0/examples/jsm/postprocessing/UnrealBloomPass.js';

import {
  ImprovedNoise
} from 'https://cdn.skypack.dev/three@0.136.0/examples/jsm/math/ImprovedNoise.js';


const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);
///////////////////////////////////////////////////////////////////////////////
export function create_geo(config) {
  let geo;
  if (config.geometry_shape == "Box") {
    geo = new THREE.BoxGeometry(config.geometry_size_x, config.geometry_size_y, config.geometry_size_z);
  }
  if (config.geometry_shape == "Icosahedron") {
    geo = new THREE.IcosahedronGeometry(config.geometry_size_x, config.geometry_divisions);
  }

  if (config.geometry_shape == "Plane") {
    geo = new THREE.PlaneGeometry(config.geometry_size_x, config.geometry_size_z);
  }

  if (config.geometry_shape == "Sphere") {
    geo = new THREE.SphereGeometry(config.geometry_radius, config.geometry_divisions, config.geometry_divisions);
  }
  if (config.geometry_shape == "Triangle") {
    let shape = new THREE.Shape();
    const x = 0;
    const y = 0;
    const sommet = .1
    shape.moveTo(x - sommet, y - sommet);
    shape.lineTo(x + sommet, y - sommet);
    shape.lineTo(x, y + 1);
    geo = new THREE.ShapeGeometry(shape);
  }
  return geo;
}

export class Instance {
  /*
  count : number of instance
  geom 
        : geometry_shape
        : geometry_size_x
        : geometry_radius
        : geometry_divisions
  color : 0xffffff
  bloom : 0 éteint - 1 allumé  
  */

  constructor(config) {
    this.config = config;
    this.dummy = [];

    this.geom = create_geo(this.config)

    this.mat = new THREE.MeshPhongMaterial({
      onBeforeCompile: shader => {
        shader.uniforms.bloom = globalUniforms.bloom;
        shader.vertexShader = `
          attribute float shine;
          varying float vShine;
          ${shader.vertexShader}
        `.replace(
          `#include <color_vertex>`,
          `#include <color_vertex>
            vShine = shine;
          `
        );
        shader.fragmentShader = `
          uniform float bloom;
          varying float vShine;
          ${shader.fragmentShader}
        `.replace(
          `#include <dithering_fragment>`,
          `#include <dithering_fragment>            
            gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0), bloom);
            gl_FragColor.rgb = mix(gl_FragColor.rgb, vColor, vShine);
            
          `
        );
      }
    });
    this.color = new THREE.Color();
    this.mesh = new THREE.InstancedMesh(this.geom, this.mat, this.config.count);

    for (let i = 0; i < this.config.count; i++) {
      this.dummy[i] = new THREE.Object3D();
      this.dummy[i].position.set(0, 0, 0);
      this.dummy[i].updateMatrix()
      this.mesh.setMatrixAt(i, this.dummy[i].matrix)
      this.mesh.setColorAt(i, this.color.set(this.config.color))
    };
    this.geom.setAttribute("shine", new THREE.InstancedBufferAttribute(new Float32Array(new Array(this.config.count).fill(0).map(m => {
      return Math.random() < 0.025 ? 1 : 0
    })), 1));
    scene.add(this.mesh);
    this.bloom();
  }
  bloom() {
    let bloom = this.geom.attributes.shine;
    for (let i = 0; i < this.config.count; i++) {
      bloom.setX(i, this.config.bloom);
    }
    bloom.needsUpdate = true;
  }
  animate() {
    this.mesh.instanceMatrix.needsUpdate = true;
    for (let i = 0; i < (this.config.count); i++) {
      this.dummy[i].updateMatrix();
      this.mesh.setMatrixAt(i, this.dummy[i].matrix);
    }
  }
}
/////////////////////////////////////////////////////////////////////////////
let scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x020C26, 0, 500);

let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
const renderer = new THREE.WebGLRenderer({
	antialias: true,
	alpha: true,
});
renderer.setClearColor(0x01010d, 1);

renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);

document.body.appendChild(renderer.domElement);
window.addEventListener("resize", () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight)
})

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

//let light = new THREE.DirectionalLight(0xffffff, 1.5);
//light.position.setScalar(1);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));

let globalUniforms = {
  bloom: {
    value: 0
  }
}

let conf_master = {
  count: 10,
  color: 0xffeb00,
  bloom: 0,
  geometry_shape: 'Box',
  geometry_size_x: .2,
  geometry_size_y: .2,
  geometry_size_z: .2,
}

let conf_slave = {
  count: 10,
  color: 0xffffff,
  bloom: 1,
  geometry_shape: 'Box',
  geometry_size_x: .1,
  geometry_size_y: .2,
  geometry_size_z: .1,
}

let master = new Instance(conf_master)
let slave = new Instance(conf_slave)
for (let i = 0; i < conf_master.count; i++) {
  master.dummy[i].position.set(random(-5, 5), random(-1, 1), random(-5, 5))
  slave.dummy[i].position.set(master.dummy[i].position.x, master.dummy[i].position.y, master.dummy[i].position.z - .05)
  master.dummy[i].add(slave.dummy[i])
};
// DON'T WORKS
// master.mesh.add(slave.mesh)

// BLOOM
const params = {
  exposure: 4,
  bloomStrength: 1,
  bloomThreshold: .1,
  bloomRadius: 10
};

const renderScene = new RenderPass(scene, camera);

const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;

const bloomComposer = new EffectComposer(renderer);
bloomComposer.renderToScreen = false;
bloomComposer.addPass(renderScene);
bloomComposer.addPass(bloomPass);

const finalPass = new ShaderPass(
  new THREE.ShaderMaterial({
    uniforms: {
      baseTexture: {
        value: null
      },
      bloomTexture: {
        value: bloomComposer.renderTarget2.texture
      }
    },
    vertexShader: document.getElementById('vertexshader').textContent,
    fragmentShader: document.getElementById('fragmentshader').textContent,
    defines: {}
  }), 'baseTexture'
);
finalPass.needsSwap = true;

const finalComposer = new EffectComposer(renderer);
finalComposer.addPass(renderScene);
finalComposer.addPass(finalPass);

renderer.setAnimationLoop(() => {
  globalUniforms.bloom.value = 1;
  bloomComposer.render();
  globalUniforms.bloom.value = 0;
  finalComposer.render();
  master.animate()
  slave.animate()
  
for (let i = 0; i < conf_master.count; i++) {
  //master.dummy[i].rotation.y += 0.1
};  
////////////////////////////////////////////////////////////////////////////////////
//  WHAT I WOULD LIKE :
// i would like that slave.dummy follow master.dummy and turn also but with the origin of master
////////////////////////////////////////////////////////////////////////////////////
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.