<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.3/dat.gui.min.js"></script>
html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
}
canvas {
  width: 100%;
  height: 100%;
  display; block;
}
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
camera.position.set(0, 120, 90);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setClearColor(0x606060);
var canvas = renderer.domElement;
document.body.appendChild(canvas);

var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target = new THREE.Vector3(0, 50, 0);
controls.update();

scene.add(new THREE.GridHelper(50, 50));

let xSize = 50;
let ySize = 100;
let zSize = 50;
let n = xSize * ySize * zSize;

let geometry = new THREE.BufferGeometry();
let positions = [];

for (let i = 0; i < n * 2; i++) {
  positions.push(
    Math.random() * xSize,
    Math.random() * ySize,
    Math.random() * zSize
  );
}

let positionAttribute = new THREE.Float32BufferAttribute(positions, 3);
geometry.addAttribute("position", positionAttribute);
geometry.center();
geometry.translate(0, ySize * 0.5, 0);

let points = new THREE.Points(
  geometry,
  new THREE.ShaderMaterial({ 
    uniforms:{
      box: {
        value: {
            size: new THREE.Vector3(10, 10, 10),
            position: new THREE.Vector3(0, -5, 0),
            rotation: new THREE.Vector3()
        }
      },
      size: {
        value: 0.75
      }
    },
    vertexShader:`
      uniform float size;
      varying vec3 vPos;
      void main(){
        vPos = position;
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        gl_PointSize = size * ( 300.0 / length( mvPosition.xyz ) );
        gl_Position = projectionMatrix * mvPosition;
      }
    `,
    fragmentShader: `
      struct boxParams {
        vec3 size;
        vec3 position;
        vec3 rotation;
      };

      uniform boxParams box;

      varying vec3 vPos;

      mat3 rotationMatrix(vec3 axis, float angle)
      {
          axis = normalize(axis);
          float s = sin(angle);
          float c = cos(angle);
          float oc = 1.0 - c;

          return mat3(
            oc * axis.x * axis.x + c,           oc * axis.x * axis.y - axis.z * s,  oc * axis.z * axis.x + axis.y * s,
            oc * axis.x * axis.y + axis.z * s,  oc * axis.y * axis.y + c,           oc * axis.y * axis.z - axis.x * s,
            oc * axis.z * axis.x - axis.y * s,  oc * axis.y * axis.z + axis.x * s,  oc * axis.z * axis.z + c         
            );
      }

      bool isInside(boxParams box, vec3 pt){

        vec3 nullVector0 = - box.size * 0.5;
        vec3 nullVectorX = nullVector0 + vec3(box.size.x, 0, 0);
        vec3 nullVectorY = nullVector0 + vec3(0, box.size.y, 0);
        vec3 nullVectorZ = nullVector0 + vec3(0, 0, box.size.z);
        
        mat3 matX = rotationMatrix(vec3(1, 0, 0), box.rotation.x);
        mat3 matY = rotationMatrix(vec3(0, 1, 0), box.rotation.y);
        mat3 matZ = rotationMatrix(vec3(0, 0, 1), box.rotation.z);
        mat3 mat = matX * matY * matZ;
      
        nullVector0 = nullVector0 * mat + box.position;
        nullVectorX = nullVectorX * mat + box.position;
        nullVectorY = nullVectorY * mat + box.position;
        nullVectorZ = nullVectorZ * mat + box.position;


        vec3 ptPos = pt - nullVector0;
        
        vec3 nullX = nullVectorX - nullVector0;
        vec3 nullY = nullVectorY - nullVector0;
        vec3 nullZ = nullVectorZ - nullVector0;

        float dotX = dot(nullX, ptPos);
        float dotY = dot(nullY, ptPos);
        float dotZ = dot(nullZ, ptPos);
        
        float dotNullX = dot(nullX, nullX);
        float dotNullY = dot(nullY, nullY);
        float dotNullZ = dot(nullZ, nullZ);

        bool isX = (0.0 <= dotX) && (dotX <= dotNullX);
        bool isY = (0.0 <= dotY) && (dotY <= dotNullY);
        bool isZ = (0.0 <= dotZ) && (dotZ <= dotNullZ);

        return isX && isY && isZ;
      }

      void main(){
        if (isInside(box, vPos) == false) discard;
        gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);
      }
    `})
);
scene.add(points);

var box3 = new THREE.Box3().setFromObject(points);
var box3Helper = new THREE.Box3Helper(box3, 0x404040);
scene.add(box3Helper);

var clock = new THREE.Clock();
var delta = 0;
var time = 0;
var boxSpeed = 12.5;
var boxRotation = new THREE.Vector3(Math.PI * 0.5, Math.PI, Math.PI * 0.25);

var gui = new dat.GUI();
var linearSpeed = gui.addFolder("linear speed");
linearSpeed.add(window, "boxSpeed", 0, 25).name("y");
linearSpeed.open();
var rotationSpeed = gui.addFolder("rotation speed")
rotationSpeed.add(boxRotation, "x", -Math.PI, Math.PI).name("x");
rotationSpeed.add(boxRotation, "y", -Math.PI, Math.PI).name("y");
rotationSpeed.add(boxRotation, "z", -Math.PI, Math.PI).name("z");
rotationSpeed.open();

render();

function resize(renderer) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

function render() {
  if (resize(renderer)) {
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }
  delta = clock.getDelta();
  time += delta;
  
  
  points.material.uniforms.box.value.position.y += boxSpeed * delta;
  points.material.uniforms.box.value.rotation.addScaledVector(boxRotation, delta);
  if (points.material.uniforms.box.value.position.y >= ySize + (points.material.uniforms.box.value.size.y * 0.5)){
    
    points.material.uniforms.box.value.size.set(
      THREE.Math.randInt(5, 30),
      THREE.Math.randInt(5, 30),
      THREE.Math.randInt(5, 30)
    );
    
    points.material.uniforms.box.value.position.x = THREE.Math.randFloatSpread(50);
    points.material.uniforms.box.value.position.z = THREE.Math.randFloatSpread(50);
    
    points.material.uniforms.box.value.position.y = -points.material.uniforms.box.value.size.y * 0.5;
  }
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.