Skip to content

Instantly share code, notes, and snippets.

@jupegarnica
Created October 23, 2021 09:11
Show Gist options
  • Save jupegarnica/9cb7a066fa3bfa3dcf96c3575ae329b8 to your computer and use it in GitHub Desktop.
Save jupegarnica/9cb7a066fa3bfa3dcf96c3575ae329b8 to your computer and use it in GitHub Desktop.
tixy.land - three.js
<div class="buttons">
<button onclick="prevTixy()">&lt;</button>
<button onclick="nextTixy()">&gt;</button>
</div>
import * as $ from '//unpkg.com/three@0.123.0/build/three.module.js'
import { OrbitControls } from '//unpkg.com/three@0.123.0/examples/jsm/controls/OrbitControls.js'
import { EffectComposer } from '//unpkg.com/three@0.123.0/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from '//unpkg.com/three@0.123.0/examples/jsm/postprocessing/RenderPass'
import { UnrealBloomPass } from '//unpkg.com/three@0.123.0/examples/jsm/postprocessing/UnrealBloomPass'
import { BokehPass } from '//unpkg.com/three@0.123.0/examples/jsm/postprocessing/BokehPass'
const renderer = new $.WebGLRenderer({ antialias: true });
const scene = new $.Scene();
const camera = new $.PerspectiveCamera(45, 2, .1, 1000);
const controls = new OrbitControls(camera, renderer.domElement);
const composer = new EffectComposer(renderer);
const drawingBufferSize = new $.Vector2();
window.addEventListener('resize', () => {
const { clientWidth, clientHeight } = renderer.domElement;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(clientWidth, clientHeight, false);
camera.aspect = clientWidth / clientHeight;
camera.updateProjectionMatrix();
composer.setPixelRatio(window.devicePixelRatio);
composer.setSize(clientWidth, clientHeight);
renderer.getDrawingBufferSize(drawingBufferSize);
});
document.body.append(renderer.domElement);
window.dispatchEvent(new Event('resize'));
const SIZE = 16;
const ITEM_BASE_SIZE = 1.8;
scene.background = new $.Color('rgba(30,30,30)');
camera.position.set(-30, 60, -30);
controls.autoRotate = true;
controls.autoRotateSpeed = 0.5;
const light = new $.DirectionalLight('white', 1);
light.position.set( -3, 15, -1 );
light.castShadow = true;
scene.add(light);
const limit = (v) => Math.max(Math.min(v,1),-1);
class Inst {
constructor(mesh, idx, r, g, b, x, z) {
this.mesh = mesh;
this.idx = idx;
this.color = new $.Color(r, g, b);
this.matrix = new $.Matrix4();
this.translateMatrix = new $.Matrix4();
this.scaleMatrix = new $.Matrix4();
this.x = x;
this.z = z;
this.matrix.makeTranslation(x, 0, z);
this.updateColor();
this.updateMatrix();
}
setValue(v) {
v = limit(v);
if (v>=0) {
this.color.r = v;
this.color.g = v;
this.color.b = v;
} else {
this.color.r = Math.abs(v);
this.color.g = 0;
this.color.b = 0;
}
this.updateColor();
const y = v*5;
const s = Math.abs(v);
this.translateMatrix.makeTranslation(1, y, 1);
this.scaleMatrix.makeScale(s, s, s);
this.updateMatrix();
}
updateColor() {
this.mesh.setColorAt(this.idx, this.color);
this.mesh.instanceColor.needsUpdate = true;
}
updateMatrix() {
this.matrix.makeTranslation(this.x, 0, this.z)
.multiply(this.translateMatrix)
.multiply(this.scaleMatrix);
this.mesh.setMatrixAt(this.idx, this.matrix);
this.mesh.instanceMatrix.needsUpdate = true;
}
}
const geom = new $.SphereBufferGeometry( 1, 16, 16 ).translate(0, 0.5, 0);
const mat = new $.MeshLambertMaterial();
const mesh = new $.InstancedMesh(geom, mat, SIZE * SIZE);
scene.add(mesh);
const insts = [];
for (let i = 0, I = SIZE; i < I; ++i) {
for (let j = 0, J = SIZE; j < J; ++j) {
const n = i * SIZE + j;
const x = (j / J - 0.5) * (ITEM_BASE_SIZE * 1.01 * SIZE);
const z = (i / I - 0.5) * (ITEM_BASE_SIZE * 1.01 * SIZE);
insts.push(new Inst(mesh, n, 0, 0, 0, x, z));
}
}
const tixy = [
(t, i, x, y) => Math.sin(t),
(t, i, x, y) => Math.random() < 0.3,
(t, i, x, y) => Math.sin(t-Math.sqrt((x-7.5)**2+(y-6)**2)),
(t, i, x, y) => Math.sin(y/8 + t),
(t, i, x, y) => -.4/(Math.hypot(x-t%10,y-t%8)-t%2*9),
(t, i, x, y) => Math.sin(2*Math.atan((y-7.5)/(x-7.5))+5*t)
]
let current = 5;
let transform = tixy[current];
window.prevTixy = () => {
current--;
if (current<0) current = tixy.length - 1;
transform = tixy[current];
}
window.nextTixy = () => {
current++;
if (current>=tixy.length) current = 0;
transform = tixy[current];
}
const size = SIZE;
const loop = () => {
const t = window.performance.now()/1000;
insts.forEach((inst, i) => {
const x = i%size;
const y = Math.floor(i/size);
const v = transform(0.66*t, i, x, y);
inst.setValue(v);
})
}
renderer.setAnimationLoop(() => {
composer.render();
controls.update();
loop();
});
const renderPass = new RenderPass(scene, camera);
const bokehPass = new BokehPass(scene, camera, { focus: 40, aperture: 0.01 / 20, maxblur: 0.01 });
const bloomPass = new UnrealBloomPass(drawingBufferSize, 0.5, 0.2, 0.2);
composer.addPass(renderPass);
//composer.addPass(bloomPass);
//composer.addPass(bokehPass);
<script src="https://unpkg.co/gsap@3/dist/gsap.min.js"></script>
canvas {
display: block; width: 100vw; height: 100vh;
cursor: grab;
}
.buttons {
position: absolute;
padding: 10px;
}
button {
margin: 5px;
background: none;
border: 1px solid #fff;
color: white;
font-family: monospace;
font-size: 24px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment