Points are static, the box of visibility moves through them.
A Pen by Faked Weiss on CodePen.
Points are static, the box of visibility moves through them.
A Pen by Faked Weiss on CodePen.
| <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> |
| 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); | |
| } |
| html, body { | |
| height: 100%; | |
| margin: 0; | |
| overflow: hidden; | |
| } | |
| canvas { | |
| width: 100%; | |
| height: 100%; | |
| display; block; | |
| } |