codepens/instancedmesh-hierarchy-mat.../dist/script.js

203 lines
5.7 KiB
JavaScript

import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.123.0/build/three.module.js";
import { OrbitControls } from "https://cdn.jsdelivr.net/npm/three@0.123.0/examples/jsm/controls/OrbitControls.js";
import { TWEEN } from "https://cdn.jsdelivr.net/npm/three@0.123.0/examples/jsm/libs/tween.module.min.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(-5, 10, 20);
let renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
const textureCube = generateCubeMap();
let controls = new OrbitControls(camera, renderer.domElement);
controls.enableZoom = false;
controls.enablePan = false;
controls.enableKeys = false;
let square = new THREE.GridHelper(20, 1, 0xaaaaff, 0xaaaff);
square.position.y = 0.01;
scene.add(square);
let grid = new THREE.GridHelper(20, 10, "magenta", "magenta");
console.log(grid.geometry.attributes.position.count);
let moveable = [];
for(let i = 0; i < grid.geometry.attributes.position.count / 4; i++){
moveable.push(1, 1, 0, 0);
}
console.log(moveable.length)
grid.geometry.setAttribute("moveable", new THREE.Float32BufferAttribute(moveable, 1));
let uniforms = {
time: {value: 0},
speed: {value: 1},
size: {value: 20}
}
grid.material.onBeforeCompile = shader => {
shader.uniforms.time = uniforms.time;
shader.uniforms.speed = uniforms.speed;
shader.uniforms.size = uniforms.size;
shader.vertexShader = `
uniform float time;
uniform float speed;
uniform float size;
attribute float moveable;
${shader.vertexShader}
`.replace(
`#include <begin_vertex>`,
`#include <begin_vertex>
if (floor(moveable + 0.1) > 0.5){
float start = size * -0.5;
float zPos = mod( (position.z - start) + (time * speed), size) + start;
transformed.z = zPos;
}
`
);
console.log(shader.vertexShader)
}
scene.add(grid);
// palm
let base = new THREE.Object3D();
let baseSpline = new THREE.CatmullRomCurve3([
new THREE.Vector2(),
new THREE.Vector2(3, 0),
new THREE.Vector2(2.5, -7),
new THREE.Vector2(-4, -6),
new THREE.Vector2(-4.8, 0)
], true, "catmullrom", 0.1);
let baseG = new THREE.ExtrudeBufferGeometry(new THREE.Shape(baseSpline.getPoints(50)), {depth: 0.2, bevelEnabled: true, bevelThickness: 0.8, bevelSize: 0.2});
let baseObject = new THREE.Mesh(baseG, new THREE.MeshBasicMaterial({color: "magenta", wireframe: false, envMap: textureCube}));
base.add(baseObject);
scene.add(base);
let phalanxes = [];
let f1 = createFinger(new THREE.Object3D(), 0.8, false); // pinky
let f2 = createFinger(new THREE.Object3D(), 0.95, false); // ring
let f3 = createFinger(new THREE.Object3D(), 1, false); // middle
let f4 = createFinger(new THREE.Object3D(), 0.95, false); // index
let f5Base = new THREE.Object3D();
let f5 = createFinger(new THREE.Object3D(), 0.75, true); // thumb
f5Base.add(f5);
base.add(f1, f2, f3, f4, f5Base);
f1.position.set( -4, 0.2, 0);
f2.position.set( -2, 0.2, 0);
f3.position.set( 0, 0.2, 0);
f4.position.set( 2, 0.2, 0);
f5Base.position.set( 3, -3, 0);
f5Base.rotation.set( 0, 0, THREE.MathUtils.degToRad(-60));
f5Base.updateMatrixWorld();
let g = createPhalanxGeom(1, 3);
let m = new THREE.MeshBasicMaterial({color: "aqua", wireframe: false, envMap: textureCube});
let o = new THREE.InstancedMesh(g, m, phalanxes.length);
phalanxes.forEach( (ph, i) => {
ph.updateMatrixWorld();
o.setMatrixAt(i, ph.matrixWorld);
})
scene.add(o);
window.addEventListener( 'resize', onWindowResize, false );
let t = new TWEEN.Tween({value: Math.PI * 0.075})
.to({value: Math.PI * 0.45}, 4000)
.easing(TWEEN.Easing.Quadratic.InOut)
.repeat(Infinity)
.yoyo(true)
.onUpdate(val => {
phalanxes.forEach((ph, i) => {
ph.rotation.x = val.value;
ph.updateMatrixWorld();
o.setMatrixAt(i, ph.matrixWorld)
});
o.instanceMatrix.needsUpdate = true;
});
t.start();
let clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
let t = clock.getElapsedTime();
TWEEN.update();
uniforms.time.value = t;
base.rotation.x = (Math.sin(t * 0.125) * 0.5 + 0.5) * -Math.PI * 0.5;
base.rotation.y = -t * 0.125;
renderer.render(scene, camera);
});
function onWindowResize() {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( innerWidth, innerHeight );
}
function createFinger(phalanx, scale, isThumb){
phalanxes.push(phalanx);
let current = phalanx;
for(let i = 0; i < (isThumb ? 1 : 2); i++){
let p = new THREE.Object3D();
p.position.y = 3;
p.scale.setScalar(0.85);
current.add(p);
phalanxes.push(p);
current = p;
}
phalanx.scale.setScalar(scale);
return phalanx;
}
function createPhalanxGeom(R, L){
let r = R * 0.85;
let R1 = R - r;
let a = Math.asin(R1 / L);
let path = new THREE.Path();
path.absarc(0, 0, R, Math.PI * 1.5, a);
path.absarc(0, L, r, a, Math.PI * 0.5);
let pts = path.getPoints(5);
let g = new THREE.LatheBufferGeometry(pts);
return g;
}
function generateCubeMap(){
let images = [];
let c = document.createElement("canvas");
c.width = 4;
c.height = c.width;
let ctx = c.getContext("2d");
for(let i= 0; i < 6;i++){
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, c.width, c.height);
for(let j = 0; j < (c.width * c.height) / 2; j++){
ctx.fillStyle = Math.random() < 0.5 ? "#f0f" : "#40f";
ctx.fillRect(
Math.floor(Math.random() * c.width),
Math.floor(Math.random() * c.height),
2,
1
);
}
images.push(c.toDataURL());
}
let cm = new THREE.CubeTextureLoader().load(images);
console.log(cm);
return cm;
}