diff --git a/src/components/particule-background/index.ts b/src/components/particule-background/index.ts deleted file mode 100644 index d471766..0000000 --- a/src/components/particule-background/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import "./styles.css"; -import {animate, initCamera, initCanvas, initScene, initStage, renderer} from "./scene.ts"; -import {initBgObjects} from "./particules.ts"; - -//----------------------------------------------------------------------- - -export function animatedBackground() { - initStage(); - initScene(); - initCanvas(); - initCamera(); - initBgObjects(); - animate(); - - return renderer.domElement; -} \ No newline at end of file diff --git a/src/components/particule-background/particules.ts b/src/components/particule-background/particules.ts deleted file mode 100644 index 500f675..0000000 --- a/src/components/particule-background/particules.ts +++ /dev/null @@ -1,64 +0,0 @@ -import * as THREE from "three"; -import {scene, windowHeight, windowWidth} from "./scene.ts"; - - -//----------------------------------------------------------------------- - -export const initBgObjects = () => { - for (let i = 0; i < 1000; i++) { - createBgObject(); - } - - createCurvedPlane(); -} - - -//----------------------------------------------------------------------- - -const createBgObject = () => { - const size = Math.random() * 30 + 5; - const geometry = new THREE.IcosahedronGeometry(size, 1); - const material = new THREE.MeshBasicMaterial( { - color: 0xdddddd, - wireframe: true - } ); - const sphere = new THREE.Mesh( geometry, material ); - scene.add( sphere ); - const x = pointInMargins(); - const y = Math.random() * windowHeight * 15 - windowHeight * 7.5; - const z = Math.random() * -2000 - 200; - - sphere.userData.rotationSpeed = { - x: Math.random() * 0.02 - 0.01, - y: Math.random() * 0.02 - 0.01 - }; - - sphere.position.set(x, y, z); -} - - -const pointInMargins = () => { - const wrapper = 720; - let point: number; - - if (Math.random() < 0.5) { - point = Math.random() * (windowWidth / 2 - wrapper * 2) - windowWidth / 2; - } else { - point = Math.random() * (windowWidth / 2 - wrapper * 2) + windowWidth / 2 + wrapper; - } - - return point; -} - - -const createCurvedPlane = () => { - const geometry = new THREE.PlaneGeometry(windowWidth * 20, windowHeight * 20, 32, 32); - - const material = new THREE.MeshBasicMaterial({ color: 0x000000 }); - - const plane = new THREE.Mesh(geometry, material); - scene.add(plane); - plane.position.set(windowWidth, 0, -2000); // Position the plane in the far distance -}; - - diff --git a/src/components/three-background/animation-loop.ts b/src/components/three-background/animation-loop.ts new file mode 100644 index 0000000..f2d74f0 --- /dev/null +++ b/src/components/three-background/animation-loop.ts @@ -0,0 +1,15 @@ +import {updateBgObjects} from "./particules.ts"; +import {renderWithPostProcess} from "./post-process.ts"; +import {camera, cameraTarget} from "./scene.ts"; +import * as THREE from "three"; + +let cameraLookAt = new THREE.Vector3(0, 0, 0); + +export const animate = () => { + requestAnimationFrame(animate); + camera.position.lerp(cameraTarget, 0.2); + camera.lookAt(cameraLookAt); + + updateBgObjects(); + renderWithPostProcess(); +} diff --git a/src/components/three-background/index.ts b/src/components/three-background/index.ts new file mode 100644 index 0000000..2f1bff3 --- /dev/null +++ b/src/components/three-background/index.ts @@ -0,0 +1,19 @@ +import "./styles.css"; +import {initCamera, initCanvas, initScene, initStage, renderer} from "./scene.ts"; +import {initBgMeshes} from "./particules.ts"; +import {initPostProcess} from "./post-process.ts"; +import {animate} from "./animation-loop.ts"; + +//----------------------------------------------------------------------- + +export function animatedBackground() { + initStage(); + initScene(); + initCanvas(); + initCamera(); + initBgMeshes(); + initPostProcess(); + animate(); + + return renderer.domElement; +} \ No newline at end of file diff --git a/src/components/three-background/particules.ts b/src/components/three-background/particules.ts new file mode 100644 index 0000000..8d9dd1a --- /dev/null +++ b/src/components/three-background/particules.ts @@ -0,0 +1,110 @@ +import * as THREE from "three"; +import {scene, windowHeight, windowWidth} from "./scene.ts"; + + +const meshWhiteMaterial = new THREE.MeshStandardMaterial( { + color: 0xdddddd, + wireframe: true, + emissive: 0xdddddd, + emissiveIntensity: 0.5, +}); + +const meshBlueMaterial = new THREE.MeshStandardMaterial( { + color: 0x3BFFC5, + wireframe: false, + emissive: 0x3BFFC5, + emissiveIntensity: 0.5, +}); + + + +//----------------------------------------------------------------------- + +export const initBgMeshes = () => { + for (let i = 0; i < 1000; i++) { + const meshSize = Math.random() * 30 + 5; + createBgMeshInMargins( + new THREE.IcosahedronGeometry(meshSize, 0), + meshWhiteMaterial + ); + } + + for (let i = 0; i < 100; i++) { + const meshSize = Math.random() * 30 + 5; + createBgMeshInMargins( + new THREE.CylinderGeometry(meshSize, meshSize, 5, 32), + meshBlueMaterial + ); + } + + createGiantWireSphere(); + createBackdropPlane(); +} + +export const updateBgObjects = () => { + scene.children.forEach((child) => { + if (child instanceof THREE.Mesh && child.userData.rotationSpeed) { + child.rotation.x += child.userData.rotationSpeed.x; + child.rotation.y += child.userData.rotationSpeed.y; + } + }); +} + +//----------------------------------------------------------------------- + +const createBgMeshInMargins = ( + spawnMesh: THREE.CylinderGeometry | THREE.IcosahedronGeometry | THREE.TorusGeometry | THREE.BoxGeometry, + meshMaterial: THREE.MeshStandardMaterial +) => { + const x = pointInMargins(); + const y = Math.random() * windowHeight * 15 - windowHeight * 7.5; + const z = Math.random() * -2000 - 200; + + const mesh = new THREE.Mesh( spawnMesh, meshMaterial ); + + mesh.userData.rotationSpeed = { + x: Math.random() * 0.02 - 0.01, + y: Math.random() * 0.02 - 0.01 + }; + + scene.add( mesh ); + mesh.position.set(x, y, z); +} + + +const pointInMargins = () => { + const wrapper = 720; + let point: number; + + if (Math.random() < 0.5) { + point = Math.random() * (windowWidth / 2 - wrapper * 2) - windowWidth / 2; + } else { + point = Math.random() * (windowWidth / 2 - wrapper * 2) + windowWidth / 2 + wrapper; + } + + return point; +} + + +const createGiantWireSphere = () => { + const geometry = new THREE.IcosahedronGeometry(3250, 3); + const material = new THREE.MeshBasicMaterial( { + color: 0xdddddd, + wireframe: true, + } ); + + const sphere = new THREE.Mesh( geometry, material ); + scene.add(sphere); + sphere.position.set(0, 0, 0); +} + + +const createBackdropPlane = () => { + const geometry = new THREE.PlaneGeometry(windowWidth * 20, windowHeight * 20, 32, 32); + const material = new THREE.MeshBasicMaterial({ color: 0x555555 }); + const plane = new THREE.Mesh(geometry, material); + scene.add(plane); + plane.position.set(windowWidth, 0, -2000); +}; + + diff --git a/src/components/three-background/post-process.ts b/src/components/three-background/post-process.ts new file mode 100644 index 0000000..4a3ba7d --- /dev/null +++ b/src/components/three-background/post-process.ts @@ -0,0 +1,43 @@ +import { camera, renderer, scene, windowHeight, windowWidth } from "./scene.ts"; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; +import {Vector2} from "three"; + +let composer: EffectComposer; + +const postProcessConfigs = { + size: Vector2, + threshold: 0.05, + strength: 0.4, + radius: 0.35, + exposure: 0 +}; + + +export const initPostProcess = () => { + const renderScene = new RenderPass( scene, camera ); + + const bloomPass = new UnrealBloomPass( + new Vector2( windowWidth, windowHeight ), // size + postProcessConfigs.strength, // strength + postProcessConfigs.radius, // radius + postProcessConfigs.threshold // threshold + ); + + const outputPass = new OutputPass(); + + composer = new EffectComposer( renderer ); + composer.addPass( renderScene ); + composer.addPass( bloomPass ); + composer.addPass( outputPass ); +} + +export const resizeComposer = () => { + composer.setSize( windowWidth, windowHeight ); +} + +export const renderWithPostProcess = () => { + composer.render(); +} diff --git a/src/components/particule-background/scene.ts b/src/components/three-background/scene.ts similarity index 85% rename from src/components/particule-background/scene.ts rename to src/components/three-background/scene.ts index 432e966..413ab52 100644 --- a/src/components/particule-background/scene.ts +++ b/src/components/three-background/scene.ts @@ -1,12 +1,12 @@ import * as THREE from 'three'; - +import {resizeComposer} from "./post-process.ts"; export let renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.PerspectiveCamera, cameraTarget = new THREE.Vector3(0, 0 ,800), - windowWidth: number, - windowHeight: number; + windowWidth = window.innerWidth, + windowHeight = window.innerHeight; let graphicCanvas, canvasWidth = 240, @@ -14,8 +14,7 @@ let graphicCanvas, mouseX = 0, mouseY = 0, windowHalfWidth: number, - windowHalfHeight: number, - cameraLookAt = new THREE.Vector3(0, 0, 0); + windowHalfHeight: number; const mouseSensitivity = 0.1; const cameraTilt = 35; @@ -32,6 +31,7 @@ export const initStage = () => { export const initScene = () => { scene = new THREE.Scene(); scene.fog = new THREE.Fog(0x010102, 1, 3000); + scene.add( new THREE.AmbientLight( 0xcccccc ) ); renderer = new THREE.WebGLRenderer({ @@ -62,23 +62,15 @@ export const initCanvas = () => { graphicCanvas.height = canvasHeight; } -export const setWindowSize = () => { +//----------------------------------------------------------------------- + +const setWindowSize = () => { windowWidth = window.innerWidth; windowHeight = window.innerHeight; windowHalfWidth = windowWidth / 2; windowHalfHeight = windowHeight / 2; } -export const animate = () => { - requestAnimationFrame(animate); - camera.position.lerp(cameraTarget, 0.2); - camera.lookAt(cameraLookAt); - - render(); -} - -//----------------------------------------------------------------------- - const onMouseMove = (event: MouseEvent) => { mouseX = (event.clientX - windowHalfWidth); mouseY = (event.clientY - windowHalfHeight); @@ -93,13 +85,11 @@ const onMouseMove = (event: MouseEvent) => { const onWindowResize = () => { setWindowSize(); + resizeComposer(); camera.aspect = windowWidth / windowHeight; camera.updateProjectionMatrix(); renderer.setSize(windowWidth, windowHeight); + renderer.toneMapping = THREE.ReinhardToneMapping; } - -const render = () => { - renderer.render(scene, camera); -} \ No newline at end of file diff --git a/src/components/particule-background/styles.css b/src/components/three-background/styles.css similarity index 100% rename from src/components/particule-background/styles.css rename to src/components/three-background/styles.css diff --git a/src/views/utils/backgrounds-utils.ts b/src/views/utils/backgrounds-utils.ts index f878ed0..098ff95 100644 --- a/src/views/utils/backgrounds-utils.ts +++ b/src/views/utils/backgrounds-utils.ts @@ -1,4 +1,4 @@ -import {animatedBackground} from "../../components/particule-background"; +import {animatedBackground} from "../../components/three-background"; export function createBackground() {