Untitled
unknown
typescript
2 years ago
8.7 kB
10
Indexable
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';
import {IUniform} from 'three/src/renderers/shaders/UniformsLib';
const vertexShader: string = `
uniform float amplitude;
attribute vec3 color;
varying vec4 varColor;
void main()
{
varColor = vec4(color, 1.0);
vec4 pos = vec4(position, 1.0);
pos.z *= amplitude;
vec4 mvPosition = modelViewMatrix * pos;
gl_PointSize = 1.0;
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader: string = `
varying vec4 varColor;
void main()
{
gl_FragColor = varColor;
}
`;
@Component({
selector: 'photo-welcome',
templateUrl: './photo.component.html',
})
export class PhotoComponent implements OnInit {
image = '/assets/szyszki.jpg';
startZoom = 3000;
imageData?: Uint8ClampedArray;
imageWidth = 0;
imageHeight = 0;
uniforms: { [uniform: string]: IUniform } = {
amplitude: {
value: 0,
},
};
animationTime = 0;
animationDelta = 0.53;
controls!: OrbitControls;
clock = new THREE.Clock();
renderer!: THREE.WebGLRenderer;
scene = new THREE.Scene();
camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(
20,
window.innerWidth / window.innerHeight,
1,
10000
);
v = 0.5;
weights = [0.1126, 0.2152, 10.7722];
// stopTime = 0;
// isReturningToStartZoom = false;
// lastZoomChangeTime?: number;
// playing = true;
@ViewChild('container')
private containerRef: ElementRef | undefined;
ngOnInit() {
this.createScene();
}
private error(message: string): void {
throw new Error(message);
}
private createScene() {
const container = document.getElementById('container');
if (!container) {
this.error('createScene - missing container');
return;
}
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
this.scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 0.5);
pointLight.position.x = 0;
pointLight.position.y = 0;
pointLight.position.z = 0;
this.scene.add(pointLight);
this.renderer = new THREE.WebGLRenderer({
canvas: container,
antialias: true,
});
const canvasSizes = {
width: window.innerWidth,
height: window.innerHeight,
};
this.camera.position.z = this.startZoom;
this.camera.position.x = 0;
this.camera.position.y = 0;
this.camera.lookAt(this.scene.position);
this.scene.add(this.camera);
this.renderer.setClearColor(0x000000, 1);
this.renderer.setSize(canvasSizes.width, canvasSizes.height);
window.addEventListener('resize', () => {
if (!this.renderer || !this.camera || !this.scene) {
this.error(
'createScene.addEventListener - missing container or scene or camera'
);
return;
}
canvasSizes.width = window.innerWidth;
canvasSizes.height = window.innerHeight;
this.camera.aspect = canvasSizes.width / canvasSizes.height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(canvasSizes.width, canvasSizes.height);
this.renderer.render(this.scene, this.camera);
});
// window.addEventListener('keyup', (e) => {
// if (e.code === 'Space') {
// this.playing = !this.playing;
// }
// })
this.createControls();
}
private createControls() {
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.rotateSpeed = 1;
this.controls.zoomSpeed = 1;
this.controls.panSpeed = 0.5;
this.controls.enableZoom = true;
this.controls.enablePan = true;
this.controls.enableRotate = true;
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.55;
// this.controls.addEventListener('change', () => {
// if (!this.isReturningToStartZoom) {
// this.lastZoomChangeTime = Date.now();
// }
// });
this.createPixelData();
}
private tick() {
const run = () => {
// Render
const elapsedTime = this.clock.getElapsedTime();
this.uniforms['amplitude'].value = Math.min(0, Math.sin(elapsedTime) / 5) * -1;
this.animationTime += this.animationDelta;
// this.addRestorePosition();
this.controls.update();
this.renderer.render(this.scene, this.camera);
// Call tick again on the next frame
window.requestAnimationFrame(run);
};
run();
}
// addRestorePosition() {
// if (!this.camera) {
// this.error('addRestorePosition - missing camera');
// return;
// }
//
// // Jeśli od ostatniej zmiany zoomu minęły 3 sekundy
// if (
// !!this.lastZoomChangeTime &&
// Date.now() - this.lastZoomChangeTime > 1000
// ) {
// // Rozpoczyna proces powrotu do początkowego zoomu
// this.isReturningToStartZoom = true;
//
// this.camera.position.z += (this.startZoom - this.camera.position.z) * 0.1;
// this.camera.position.x += -this.camera.position.x * 0.1;
// this.camera.position.y += -this.camera.position.y * 0.1;
//
// if (Math.abs(this.camera.position.z - this.startZoom) < 0.1) {
// this.camera.position.z = this.startZoom;
// this.isReturningToStartZoom = false; // Kończy proces powrotu do początkowego zoomu
// this.lastZoomChangeTime = undefined;
// this.camera.position.y = 0;
// this.camera.position.x = 0;
// console.log('Finish');
// }
// }
// }
private createPixelData() {
const image = document.createElement('img');
const canvas = document.createElement('canvas');
if (!canvas) {
this.error('createPixelData - missing canvas');
return;
}
const context = canvas.getContext('2d');
if (!context) {
this.error('createPixelData - missing context');
return;
}
image.crossOrigin = 'Anonymous';
image.onload = () => {
this.imageWidth = canvas.width = image.width;
this.imageHeight = canvas.height = image.height;
const pattern = context.createPattern(image, 'no-repeat');
if (pattern instanceof CanvasPattern) {
context.fillStyle = pattern;
context.fillRect(0, 0, this.imageWidth, this.imageHeight);
this.imageData = context.getImageData(
0,
0,
this.imageWidth,
this.imageHeight
).data;
this.createParticles();
this.tick();
}
};
image.src = this.image;
}
private createParticles() {
if (!this.imageData) {
this.error('createParticles - missing imageData');
return;
}
let c = 0;
let x, y;
const zRange = 1000;
const geometry = new THREE.BufferGeometry();
x = this.imageWidth * -this.v;
y = this.imageHeight * this.v;
const vertices = [];
const colors = [];
if (!vertexShader || !fragmentShader) {
this.error(
'createParticles - missing vertexShader or fragmentShader'
);
return;
}
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: this.uniforms,
vertexShader,
fragmentShader,
});
for (let i = 0; i < this.imageHeight; i++) {
for (let j = 0; j < this.imageWidth; j++) {
const color = new THREE.Color();
color.setRGB(
this.imageData[c] / 255,
this.imageData[c + 1] / 255,
this.imageData[c + 2] / 255
);
colors.push(color.r, color.g, color.b);
const weight =
color.r * this.weights[0] +
color.g * this.weights[1] +
color.b * this.weights[2];
const vertex = new THREE.Vector3();
vertex.x = x;
vertex.y = y;
vertex.z = zRange * -this.v + zRange * weight;
vertices.push(vertex.x, vertex.y, vertex.z);
c += 4;
x++;
}
x = this.imageWidth * -this.v;
y--;
}
geometry.setAttribute(
'position',
new THREE.Float32BufferAttribute(vertices, 3)
);
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
const particleSystem = new THREE.Points(geometry, shaderMaterial);
this.scene.add(particleSystem);
}
}
Editor is loading...