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; | |
} |