Untitled
unknown
typescript
2 years ago
8.7 kB
6
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...