162 lines
4.5 KiB
JavaScript
162 lines
4.5 KiB
JavaScript
// inspiration from Etienne Jacob
|
|
// https://www.thisiscolossal.com/wp-content/uploads/2018/12/agifcolossaltd2opt.gif
|
|
|
|
import "./styles.css";
|
|
import * as THREE from "three";
|
|
// import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
|
import vertex from "./shaders/vertex.glsl";
|
|
import fragment from "./shaders/fragment.glsl";
|
|
import txt from "./123.png";
|
|
let timer = 0;
|
|
let mouseIsDown = false;
|
|
export default class Sketch {
|
|
constructor(options) {
|
|
this.clock = new THREE.Clock();
|
|
this.time = 0;
|
|
this.container = options.domElement;
|
|
this.height = this.container.offsetHeight;
|
|
this.width = this.container.offsetWidth;
|
|
this.camera = new THREE.PerspectiveCamera(
|
|
75,
|
|
this.width / this.height,
|
|
0.1,
|
|
1000
|
|
);
|
|
|
|
this.camera.position.set(0, 0, 10);
|
|
this.scene = new THREE.Scene();
|
|
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
|
this.renderer.setPixelRatio(window.devicePixelRatio * 2);
|
|
this.container.appendChild(this.renderer.domElement);
|
|
// this.controls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
this.normal = new THREE.Vector3();
|
|
this.binormal = new THREE.Vector3();
|
|
this.resize();
|
|
this.addObjects();
|
|
this.render();
|
|
this.setUpResize();
|
|
}
|
|
|
|
addObjects() {
|
|
const texture = new THREE.TextureLoader().load(txt, (texture) => {
|
|
texture.minFilter = THREE.NearestFilter;
|
|
texture.magFilter = THREE.NearestFilter;
|
|
});
|
|
|
|
this.material = new THREE.ShaderMaterial({
|
|
side: THREE.DoubleSide,
|
|
// transparent:true,
|
|
// wireframe: true,
|
|
uniforms: {
|
|
time: { type: "f", value: 0 },
|
|
uResolution: { type: "v4", value: new THREE.Vector4() },
|
|
u_texture: { type: "t", value: texture }
|
|
},
|
|
vertexShader: vertex,
|
|
fragmentShader: fragment
|
|
});
|
|
|
|
class CustomSinCurve extends THREE.Curve {
|
|
constructor(scale = 1) {
|
|
super();
|
|
|
|
this.scale = scale;
|
|
}
|
|
|
|
getPoint(t, optionalTarget = new THREE.Vector3()) {
|
|
const tx = Math.cos(2 * Math.PI * t);
|
|
const ty = Math.sin(2 * Math.PI * t);
|
|
const tz = 0.1 * Math.sin(8 * Math.PI * t);
|
|
|
|
return optionalTarget.set(tx, ty, tz).multiplyScalar(this.scale);
|
|
}
|
|
}
|
|
|
|
const path = new CustomSinCurve(10);
|
|
|
|
this.geometry = new THREE.TubeGeometry(path, 200, 0.5, 20, false);
|
|
this.mesh = new THREE.Mesh(this.geometry, this.material);
|
|
this.scene.add(this.mesh);
|
|
}
|
|
|
|
render() {
|
|
this.time = timer;
|
|
|
|
// https://threejs.org/examples/webgl_geometry_extrude_splines.html
|
|
let looptime = 10 * 1000;
|
|
let t = (this.time % looptime) / looptime;
|
|
let pos = this.geometry.parameters.path.getPointAt(t);
|
|
let segments = this.geometry.tangents.length;
|
|
let pickt = t * segments;
|
|
let pick = Math.floor(pickt);
|
|
let pickNext = (pick + 1) % segments;
|
|
|
|
this.binormal.subVectors(
|
|
this.geometry.binormals[pickNext],
|
|
this.geometry.binormals[pick]
|
|
);
|
|
this.binormal
|
|
.multiplyScalar(pickt - pick)
|
|
.add(this.geometry.binormals[pick]);
|
|
|
|
let dir = this.geometry.parameters.path.getTangentAt(t);
|
|
let offset = 0;
|
|
this.normal.copy(this.binormal).cross(dir);
|
|
|
|
pos.add(this.normal.clone().multiplyScalar(offset));
|
|
this.camera.position.copy(pos);
|
|
|
|
let lookAt = this.geometry.parameters.path.getPointAt(
|
|
(t + 1 / this.geometry.parameters.path.getLength()) % 1
|
|
);
|
|
|
|
this.camera.matrix.lookAt(this.camera.position, lookAt, this.normal);
|
|
this.camera.rotation.setFromRotationMatrix(
|
|
this.camera.matrix,
|
|
this.camera.rotation.order
|
|
);
|
|
|
|
this.material.uniforms.time.value = this.clock.getElapsedTime();
|
|
requestAnimationFrame(this.render.bind(this));
|
|
|
|
this.renderer.render(this.scene, this.camera);
|
|
}
|
|
|
|
resize() {
|
|
this.width = this.container.offsetWidth;
|
|
this.height = this.container.offsetHeight;
|
|
this.renderer.setSize(this.width, this.height);
|
|
this.camera.aspect = this.width / this.height;
|
|
this.camera.updateProjectionMatrix();
|
|
}
|
|
|
|
setUpResize() {
|
|
window.addEventListener("resize", this.resize.bind(this));
|
|
}
|
|
}
|
|
|
|
new Sketch({
|
|
domElement: document.getElementById("container")
|
|
});
|
|
|
|
window.addEventListener("mousedown", function (e) {
|
|
mouseIsDown = true;
|
|
});
|
|
window.addEventListener("mouseup", function (e) {
|
|
mouseIsDown = false;
|
|
});
|
|
|
|
window.addEventListener("mousemove", function (e) {
|
|
if (mouseIsDown) {
|
|
timer += ((e.clientY / window.innerHeight) * 2 - 1) * 10;
|
|
}
|
|
|
|
if (timer <= 0) {
|
|
timer = 0;
|
|
}
|
|
});
|
|
|
|
setInterval(() => {
|
|
timer += 1
|
|
}, 10)
|