Skip to content

Commit 529c4a5

Browse files
NOPR9D ☄️NOPROD
NOPR9D ☄️
andauthored
[wip] 🎨 : music aviator (#7)
* 🎨 : music aviator * 🌱 : a little of shaders * 🌱 : a little of setup * save Co-authored-by: NOPR9D <contact@boucham-amine.fr>
1 parent 9274c80 commit 529c4a5

33 files changed

+4649
-23
lines changed

package-lock.json

+3,433-18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "Animations used by all mylabz.xyz's websites",
55
"main": "index.js",
66
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"serve":"webpack serve"
89
},
910
"repository": {
1011
"type": "git",
@@ -19,6 +20,7 @@
1920
"dependencies": {
2021
"@types/three": "^0.141.0",
2122
"glslify": "^7.1.1",
23+
"rxjs": "^7.5.5",
2224
"three": "^0.141.0"
2325
},
2426
"devDependencies": {

threejs/games/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './musicAviator'

threejs/games/musicAviator/app.ts

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { MusicAviatorOptions } from '.';
2+
import {
3+
BoxGeometry,
4+
Clock,
5+
Color,
6+
Mesh,
7+
PerspectiveCamera,
8+
PlaneBufferGeometry,
9+
Scene,
10+
SpotLight,
11+
WebGLRenderer
12+
} from 'three';
13+
import { EngineBluePrint } from '../../models';
14+
import { Engine } from './services';
15+
16+
export class MusicAviator {
17+
private scene!: Scene;
18+
private camera!: PerspectiveCamera;
19+
private geometry!: PlaneBufferGeometry | BoxGeometry;
20+
private light!: SpotLight;
21+
private material!: any;
22+
private mesh!: Mesh;
23+
private renderer!: WebGLRenderer;
24+
private clock!: Clock;
25+
26+
private options: MusicAviatorOptions = {
27+
backgroundColor: new Color(0xffffff),
28+
speed: 0.1
29+
};
30+
31+
private engine!: EngineBluePrint;
32+
constructor(options?: MusicAviatorOptions) {
33+
if (options) {
34+
this.options = { ...this.options, ...options };
35+
}
36+
}
37+
38+
public async init(canvas?: HTMLElement) {
39+
this.scene = new Scene();
40+
this.scene.background = this.options.backgroundColor
41+
this.light = new SpotLight(this.options.backgroundColor, 1);
42+
43+
const fov = 45;
44+
const aspect = window.innerWidth / window.innerHeight;
45+
const near = 1;
46+
const far = 100;
47+
this.camera = new PerspectiveCamera(fov, aspect, near, far);
48+
49+
this.renderer = new WebGLRenderer({
50+
canvas: canvas
51+
});
52+
this.renderer.setClearColor(this.options.backgroundColor, 1);
53+
this.renderer.setPixelRatio(window.devicePixelRatio);
54+
this.renderer.setSize(window.innerWidth, window.innerHeight);
55+
56+
this.clock = new Clock();
57+
58+
await this.runEngine();
59+
}
60+
61+
public run() {
62+
window.requestAnimationFrame(this.run.bind(this));
63+
this.renderer.render(this.scene, this.camera);
64+
}
65+
66+
public setOptions(options: MusicAviatorOptions) {
67+
if (options && Object.keys(options).length > 0) {
68+
this.options = { ...this.options, ...options };
69+
}
70+
}
71+
72+
private runEngine() {
73+
this.engine = new Engine();
74+
return this.engine.importSceneCameraRenderer(this.scene, this.camera, this.renderer).init();
75+
}
76+
private addEvents(): void {
77+
window.addEventListener('resize', this.onResize.bind(this), false);
78+
}
79+
80+
private onResize() {
81+
this.material.uniforms.uResolution = {
82+
value: { x: window.innerWidth, y: window.innerHeight }
83+
};
84+
this.camera.aspect = window.innerWidth / window.innerHeight;
85+
this.camera.updateProjectionMatrix();
86+
this.renderer.setSize(window.innerWidth, window.innerHeight);
87+
}
88+
}

threejs/games/musicAviator/assets/index.ts

Whitespace-only changes.

threejs/games/musicAviator/audio/index.ts

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { LoadingManager } from 'three';
2+
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
3+
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
4+
5+
export class AirPlane {
6+
public mesh!: GLTF;
7+
private loader: GLTFLoader;
8+
private loadingManager: LoadingManager;
9+
10+
constructor() {
11+
this.loadingManager = new LoadingManager();
12+
this.loader = new GLTFLoader(this.loadingManager);
13+
const dracoLoader = new DRACOLoader();
14+
dracoLoader.setDecoderPath('/js/libs/draco/');
15+
this.loader.setDRACOLoader(dracoLoader);
16+
}
17+
18+
public createAsync() {
19+
return new Promise((res, err) => {
20+
this.loader.load(
21+
'/three/Ship.glb',
22+
(gltf) => {
23+
gltf.scene.scale.set(1.5, 1.5, 1.5);
24+
gltf.scene.position.set(0, 100, 0);
25+
gltf.scene.traverse((child) => {
26+
if (child.isObject3D) {
27+
child.receiveShadow = true;
28+
child.castShadow = true;
29+
}
30+
});
31+
this.mesh = gltf;
32+
res(true);
33+
},
34+
// called while loading is progressing
35+
(xhr) => {
36+
console.log((xhr.loaded / xhr.total) * 100 + '% loaded');
37+
},
38+
// called when loading has errors
39+
(error) => {
40+
console.log(error);
41+
console.log('An error happened');
42+
err(false);
43+
}
44+
);
45+
});
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { BoxBufferGeometry, BoxGeometry, Mesh, MeshPhongMaterial } from 'three';
2+
3+
export class Cloud {
4+
public geom: BoxGeometry;
5+
public mesh: Mesh;
6+
public material: MeshPhongMaterial;
7+
public nBlocs = 3 + Math.floor(Math.random() * 3);
8+
9+
constructor(colors: any) {
10+
this.mesh = new Mesh();
11+
this.mesh.name = 'cloud';
12+
// create the geometry (shape) of the cylinder;
13+
// the parameters are:
14+
// radius top, radius bottom, height, number of segments on the radius, number of segments vertically
15+
this.geom = new BoxBufferGeometry(20, 20, 20);
16+
this.material = new MeshPhongMaterial({
17+
color: colors.white,
18+
flatShading: true,
19+
});
20+
for (let i = 0; i < this.nBlocs; i++) {
21+
// create the mesh by cloning the geometry
22+
const m = new Mesh(this.geom, this.material);
23+
// set the position and the rotation of each cube randomly
24+
m.position.x = i * 15;
25+
m.position.y = Math.random() * 10;
26+
m.position.z = Math.random() * 10;
27+
m.rotation.z = Math.random() * Math.PI * 2;
28+
m.rotation.y = Math.random() * Math.PI * 2;
29+
// set the size of the cube randomly
30+
const s = 0.1 + Math.random() * 0.9;
31+
m.scale.set(s, s, s);
32+
// allow each cube to cast and to receive shadows
33+
m.castShadow = true;
34+
m.receiveShadow = true;
35+
// add the cube to the container we first created
36+
this.mesh.add(m);
37+
}
38+
}
39+
public rotate() {
40+
this.mesh.children.forEach((children, index) => {
41+
this.mesh.children[index].rotation.z +=
42+
Math.random() * 0.005 * (index + 1);
43+
this.mesh.children[index].rotation.y +=
44+
Math.random() * 0.002 * (index + 1);
45+
});
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {
2+
Mesh,
3+
MeshPhongMaterial,
4+
Object3D,
5+
TetrahedronBufferGeometry,
6+
} from 'three';
7+
import { ThreeObject } from '../../../models';
8+
9+
export class Ennemy implements ThreeObject {
10+
public geom: TetrahedronBufferGeometry;
11+
public mesh: Object3D;
12+
public material: MeshPhongMaterial;
13+
public angle: number;
14+
public dist: number;
15+
public color: any;
16+
constructor(color: any) {
17+
this.color = color;
18+
this.geom = new TetrahedronBufferGeometry();
19+
this.material = new MeshPhongMaterial({
20+
color: this.color,
21+
shininess: 0,
22+
specular: 0xffffff,
23+
flatShading: true,
24+
});
25+
this.mesh = new Mesh(this.geom, this.material);
26+
this.mesh.castShadow = true;
27+
this.angle = 0;
28+
this.dist = 0;
29+
}
30+
31+
public update(t: number): void {
32+
console.log('update');
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { AmbientLight, DirectionalLight, HemisphereLight } from 'three';
2+
import { ThreeObject } from '../../../models';
3+
4+
export class Light implements ThreeObject {
5+
public hemisphereLight: HemisphereLight;
6+
public shadowLight: DirectionalLight;
7+
public ambiantLight: AmbientLight;
8+
9+
constructor() {
10+
// A hemisphere light is a gradient colored light;
11+
// the first parameter is the sky color, the second parameter is the ground color,
12+
// the third parameter is the intensity of the light
13+
this.hemisphereLight = new HemisphereLight(0xaaaaaa, 0x000000, 0.9);
14+
15+
// A directional light shines from a specific direction.
16+
// It acts like the sun, that means that all the rays produced are parallel.
17+
this.shadowLight = new DirectionalLight(0xffffff, 0.9);
18+
19+
this.ambiantLight = new AmbientLight(0xdc8874, 0.5);
20+
// Set the direction of the light
21+
this.shadowLight.position.set(150, 350, 350);
22+
23+
// Allow shadow casting
24+
this.shadowLight.castShadow = true;
25+
26+
// define the visible area of the projected shadow
27+
this.shadowLight.shadow.camera.left = -400;
28+
this.shadowLight.shadow.camera.right = 400;
29+
this.shadowLight.shadow.camera.top = 400;
30+
this.shadowLight.shadow.camera.bottom = -400;
31+
this.shadowLight.shadow.camera.near = 1;
32+
this.shadowLight.shadow.camera.far = 1000;
33+
34+
// define the resolution of the shadow; the higher the better,
35+
// but also the more expensive and less performant
36+
this.shadowLight.shadow.mapSize.width = 2048;
37+
this.shadowLight.shadow.mapSize.height = 2048;
38+
}
39+
40+
public update(t: number) {
41+
// Nothing to do
42+
}
43+
}
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Object3D } from 'three';
2+
import { Cloud } from './Cloud';
3+
4+
export class Sky {
5+
public mesh: Object3D;
6+
public nClouds = 20;
7+
public stepAngle = (Math.PI * 2) / this.nClouds;
8+
public clouds: Cloud[] = [];
9+
10+
constructor(colors: any) {
11+
this.mesh = new Object3D();
12+
// create the clouds
13+
for (let i = 0; i < this.nClouds; i++) {
14+
const c = new Cloud(colors);
15+
// set the rotation and the position of each cloud;
16+
// for that we use a bit of trigonometry
17+
const a = this.stepAngle * i; // this is the final angle of the cloud
18+
const h = 750 + Math.random() * 200; // this is the distance between the center of the axis and the cloud itself
19+
// Trigonometry!!! I hope you remember what you've learned in Math :)
20+
// in case you don't:
21+
// we are simply converting polar coordinates (angle, distance) into Cartesian coordinates (x, y)
22+
c.mesh.position.y = Math.sin(a) * h;
23+
c.mesh.position.x = Math.cos(a) * h;
24+
// rotate the cloud according to its position
25+
c.mesh.rotation.z = a + Math.PI / 2;
26+
// for a better result, we position the clouds
27+
// at random depths inside of the scene
28+
c.mesh.position.z = -400 - Math.random() * 400;
29+
// we also set a random scale for each cloud
30+
const s = 1 + Math.random() * 2;
31+
c.mesh.scale.set(s, s, s);
32+
// do not forget to add the mesh of each cloud in the scene
33+
this.clouds.push(c);
34+
this.mesh.add(c.mesh);
35+
}
36+
}
37+
38+
public moveClouds() {
39+
this.clouds.forEach((cloud, index) => {
40+
this.clouds[index].rotate();
41+
});
42+
}
43+
}

0 commit comments

Comments
 (0)