Skip to content

Instantly share code, notes, and snippets.

@afektmedia
Created June 1, 2022 15:19
Show Gist options
  • Save afektmedia/a451fe83ceb5507dffab72db4c66b7b8 to your computer and use it in GitHub Desktop.
Save afektmedia/a451fe83ceb5507dffab72db4c66b7b8 to your computer and use it in GitHub Desktop.
Practice / 3.js
#loading
.circle
#container
.box
//h1 #[span.expansion A]FR#[span.expansion A]ID
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.121.1/build/three.module.js';
import {OrbitControls} from 'https://cdn.jsdelivr.net/npm/three@0.121.1/examples/jsm/controls/OrbitControls.js';
// vertex shader source
const vertexParticleShader = `
uniform float uTime;
float PI = 3.14159265359;
attribute float number;
float a = 300.0;
float b = 280.0;
void main(){
vec3 pos = position.xyz;
pos.x = (a + b * cos(number + uTime)) * cos(number * PI / 180.0 + uTime);
pos.z = (a + b * cos(number + uTime)) * sin(number * PI / 180.0 + uTime);
pos.y = b * sin(number + uTime);
vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
gl_PointSize = 60.0 * (120.0 / - mvPosition.z);
gl_Position = projectionMatrix * mvPosition;
}
`;
// fragment shader source
const fragmentParticleShader = `
uniform float uTime;
varying vec3 vPos;
void main () {
float f = length(gl_PointCoord - vec2(0.5, 0.5));
if (f > 0.1) discard;
gl_FragColor = vec4(1.0);
}
`;
/**
* Dat class
*/
class Dat {
constructor(sketch) {
this.sketch = sketch;
this.initialize();
}
initialize() {
this.gui = new dat.GUI();
this.parameters = this.setParameters();
this.controller = this.setController();
this.gui.close();
}
setParameters() {
let parameters;
parameters = {
number: 5000
};
return parameters;
}
setController() {
let controller;
controller = {
number: this.gui.add(this.parameters, 'number', 100, 50000, 100)
.onChange(() => this.sketch.initialize())
};
return controller;
}
}
/**
* Mouse class
*/
class Mouse {
constructor(sketch) {
this.sketch = sketch;
this.initialize();
}
initialize() {
this.mouse = new THREE.Vector3();
this.touchStart = new THREE.Vector3();
this.touchMove = new THREE.Vector3();
this.touchEnd = new THREE.Vector3();
this.delta = 1;
this.setupEvents();
}
setupEvents() {
this.sketch.renderer.domElement.addEventListener('mousemove', this.onMousemove.bind(this), false);
this.sketch.renderer.domElement.addEventListener('touchstart', this.onTouchstart.bind(this), false);
this.sketch.renderer.domElement.addEventListener('touchmove', this.onTouchmove.bind(this), false);
this.sketch.renderer.domElement.addEventListener('touchend', this.onTouchend.bind(this), false);
this.sketch.renderer.domElement.addEventListener('onWheel', this.onWheel.bind(this), false);
}
onMousemove(e) {
this.mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
this.mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
this.mouse.z = 0;
}
onTouchstart(e) {
const touch = e.targetTouches[0];
this.touchStart.x = touch.pageX;
this.touchStart.y = touch.pageY;
this.touchStart.z = 0.0;
this.mouse.x = (touch.pageX / window.innerWidth) * 2 - 1;
this.mouse.y = -(touch.pageY / window.innerHeight) * 2 + 1;
this.mouse.z = 0;
}
onTouchmove(e) {
const touch = e.targetTouches[0];
this.touchMove.x = touch.pageX;
this.touchMove.y = touch.pageY;
this.touchMove.z = 0.0;
this.touchEnd.x = this.touchStart.x - this.touchMove.x;
this.touchEnd.y = this.touchStart.y - this.touchMove.y;
this.touchEnd.z = 0.0;
this.mouse.x = (touch.pageX / window.innerWidth) * 2 - 1;
this.mouse.y = -(touch.pageY / window.innerHeight) * 2 + 1;
this.mouse.z = 0;
if (this.touchMove.y < this.touchStart.y) {
this.delta += (this.touchEnd.y - this.touchStart.y) * 0.0001;
} else {
this.delta -= (this.touchEnd.y - this.touchStart.y) * 0.0001;
}
}
onTouchend(e) {
this.touchStart.x = null;
this.touchStart.y = null;
this.touchStart.z = null;
this.touchMove.x = null;
this.touchMove.y = null;
this.touchMove.z = null;
this.touchEnd.x = null;
this.touchEnd.y = null;
this.touchEnd.z = null;
}
onWheel(e) {
this.delta -= e.deltaY * 0.01;
}
}
/**
* class Sketch
*/
class Sketch {
constructor() {
this.createCanvas();
this.setupEvents();
//this.setupStats();
this.time = new THREE.Clock(true);
this.mouse = new Mouse(this);
this.dat = new Dat(this);
this.initialize();
}
createCanvas() {
this.renderer =
new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
document.getElementById('container').
appendChild(this.renderer.domElement);
}
setupStats() {
this.stats = new Stats();
this.stats.setMode(0);
this.stats.domElement.style.position = 'absolute';
this.stats.domElement.style.left = '0';
this.stats.domElement.style.top = '0';
document.getElementById('container').
appendChild(this.stats.domElement);
}
initialize() {
if (this.animationId) {
cancelAnimationFrame(this.animationId);
}
this.width = Math.ceil(window.innerWidth);
this.height = Math.ceil(window.innerHeight);
this.scene = new THREE.Scene();
this.setupCanvas();
this.setupCamera();
this.setupLight();
this.setupShape();
this.draw();
}
setupCanvas() {
this.renderer.setSize(this.width, this.height);
//this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setPixelRatio(1.0);
this.renderer.setClearColor(0x000000, 1.0);
this.renderer.domElement.style.position = 'fixed';
this.renderer.domElement.style.top = '0';
this.renderer.domElement.style.left = '0';
this.renderer.domElement.style.width = '100%';
this.renderer.domElement.style.height = '100%';
this.renderer.domElement.style.zIndex = '0';
this.renderer.domElement.style.outline = 'none';
}
setupCamera() {
const fov = 70;
const fovRadian = (fov / 2) * (Math.PI / 180);
this.dist = this.height / 2 / Math.tan(fovRadian);
this.camera =
new THREE.PerspectiveCamera(
fov,
this.width / this.height,
0.01,
this.dist * 5
);
this.camera.position.set(0, 0, this.dist);
this.camera.lookAt(new THREE.Vector3());
this.scene.add(this.camera);
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
}
updateCamera(time) {
this.camera.position.set(
Math.cos(-time * 0.1) * this.dist,
Math.sin( time * 0.1) * this.dist,
Math.sin(-time * 0.1) * this.dist
);
this.camera.lookAt(new THREE.Vector3());
}
setupLight() {
// directinal light
this.directionalLight = new THREE.DirectionalLight(0xffffff);
this.scene.add(this.directionalLight);
// point light
this.spotLight = new THREE.SpotLight(0xffffff);
this.spotLight.position.set(this.dist, this.dist, this.dist);
this.scene.add(this.spotLight);
}
setupShape() {
this.shapes = new Array();
const s = new Shape(this);
this.shapes.push(s);
}
draw() {
//this.stats.begin();
const time = this.time.getElapsedTime();
for (let i = 0; i < this.shapes.length; i++) {
this.shapes[i].render(time);
}
this.renderer.render(this.scene, this.camera);
//this.stats.end();
this.animationId = requestAnimationFrame(this.draw.bind(this));
}
setupEvents() {
window.addEventListener('resize', this.onResize.bind(this), false);
}
onResize() {
this.initialize();
}
}
/**
* shape class
*/
class Shape {
/**
* @constructor
* @param {object} sketch - canvas
*/
constructor(sketch) {
this.sketch = sketch;
this.initialize();
}
/**
* initialize shape
*/
initialize() {
this.number = this.sketch.dat.parameters.number;
this.particleGeometry = new THREE.BufferGeometry();
this.positions = new Float32Array(this.number * 3);
this.numbers = new Float32Array(this.number);
for (let i = 0; i < this.number; i++) {
/*
const a = 100;
const b = 100;
let u = i * Math.PI / 180 * 0.01;
const x = (a + b * Math.cos(u)) * Math.cos(i);
const y = (a + b * Math.cos(u)) * Math.sin(i);
const z = b * Math.sin(u);
*/
this.positions.set([0, 0, 0], i * 3);
}
for (let i = 0; i < this.number; i++) {
this.numbers.set([i], i);
}
this.particleGeometry.setAttribute('position', new THREE.BufferAttribute(this.positions, 3));
this.particleGeometry.setAttribute('number', new THREE.BufferAttribute(this.numbers, 1));
this.particleMaterial = new THREE.ShaderMaterial({
side: THREE.DoubleSide,
uniforms: {
uTime: {type: 'f', value: 0},
uResolution: {
type: 'v2',
value: new THREE.Vector2(this.sketch.width, this.sketch.height)
}
},
blending: THREE.AdditiveBlending,
transparent: true,
vertexShader: vertexParticleShader,
fragmentShader: fragmentParticleShader
});
this.particlePoint = new THREE.Points(this.particleGeometry, this.particleMaterial);
this.sketch.scene.add(this.particlePoint);
}
updateParameters(time) {
this.particlePoint.material.uniforms.uTime.value = time;
}
/**
* render shape
* @param {number} time - time
*/
render(time) {
this.updateParameters(time);
}
}
(() => {
window.addEventListener('load', () => {
console.clear();
const loading = document.getElementById('loading');
loading.classList.add('loaded');
new Sketch();
});
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/16/Stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
html, body
height: 100%;
width: 100%;
body
font-size: 62.5%;
background: #000;
overflow: hidden;
color: #FFF;
font-family: serif;
overscroll-behavior: none;
#loading
background: black;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
visibility: visible;
opacity: 1;
transition: visibility 1.6s, opacity 1.6s;
.circle
width: 50px;
height: 50px;
background: white;
border-radius: 50%;
opacity: 0;
transform: scale(0, 0);
animation: circle-animation 1.6s ease-in-out 0s infinite normal none;
#loading.loaded
visibility: hidden;
opacity: 0;
#container
width: 100%;
height: 100%;
.box
color: white;
font-size: 3.2rem;
position: fixed;
z-index: 1;
top: 50%;
left: 10%;
transform: translateY(-50%);
overflow: hidden;
h1
letter-spacing: 0.4rem;
padding-bottom: 0.8rem;
&::after
content: '';
position: absolute;
height: 4px;
width: 100%;
background: #fff;
bottom: 0.8rem;
left: 0;
p
font-size: 0.8rem;
.expansion
font-size: 6.4rem;
/** css animation */
@keyframes circle-animation
0%
opacity: 0;
transform: scale(0, 0);
50%
opacity: 1;
transform: scale(1, 1);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment