-
Notifications
You must be signed in to change notification settings - Fork 0
/
ThreeBackground.js
156 lines (131 loc) · 5.47 KB
/
ThreeBackground.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import React, { useEffect, useRef, forwardRef } from 'react';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass';
const ThreeBackground = forwardRef((props, ref) => {
const rendererRef = useRef(null);
const mixerRef = useRef(null); // Ref to hold the animation mixer
const lastMousePosition = useRef({ x: window.innerWidth / 2, y: window.innerHeight / 2 });
const cameraRotation = useRef({ x: 0, y: 0 });
useEffect(() => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({
canvas: rendererRef.current,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
camera.position.setZ(30);
camera.position.setX(-3);
// Lighting setup
const pointLight = new THREE.PointLight(0xffffff);
pointLight.position.set(5, 5, 5);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4); // Modified ambient light intensity
scene.add(pointLight, ambientLight);
// Postprocessing setup
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
bloomPass.threshold = 0.21;
bloomPass.strength = 1.12;
bloomPass.radius = 0.55;
composer.addPass(bloomPass);
// Torus geometry
const torusGeometry = new THREE.TorusGeometry(10, 3, 16, 100);
const torusMaterial = new THREE.MeshStandardMaterial({ color: 0xff6347 });
const torus = new THREE.Mesh(torusGeometry, torusMaterial);
// scene.add(torus);
// Star generation function
function addStar() {
const starGeometry = new THREE.SphereGeometry(0.25, 24, 24);
const starMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
const star = new THREE.Mesh(starGeometry, starMaterial);
const [x, y, z] = Array(3).fill().map(() => THREE.MathUtils.randFloatSpread(100));
star.position.set(x, y, z);
scene.add(star);
}
Array(200).fill().forEach(addStar);
// Background texture
const spaceTexture = new THREE.TextureLoader().load('space.jpg');
scene.background = spaceTexture;
// GLTF model loading
const loader = new GLTFLoader();
loader.load('blue_dragon/scene.gltf', (gltf) => {
const dragon = gltf.scene;
dragon.scale.set(100, 100, 100); // Scale up the dragon
scene.add(dragon);
// Animation Mixer for dragon
mixerRef.current = new THREE.AnimationMixer(dragon);
if (gltf.animations.length > 1) {
const action = mixerRef.current.clipAction(gltf.animations[1]);
action.play();
} else {
console.error("Insufficient animations in GLTF model.");
}
}, undefined, function (error) {
console.error('An error happened loading the GLTF model:', error);
});
loader.load('/portal/scene.gltf', (gltf) => {
scene.add(gltf.scene);
gltf.scene.scale.set(0.1, 0.1, 0.1);
gltf.scene.position.set(0, -80, -300);
gltf.scene.rotation.y = Math.PI / 2.2;
if (gltf.animations && gltf.animations.length) {
const portalMixer = new THREE.AnimationMixer(gltf.scene);
gltf.animations.forEach((clip) => {
const action = portalMixer.clipAction(clip);
action.play();
});
//mixers.push(portalMixer);
}
});
// Mouse movement listener
function onMouseMove(event) {
const deltaX = event.clientX - lastMousePosition.current.x;
const deltaY = event.clientY - lastMousePosition.current.y;
lastMousePosition.current.x = event.clientX;
lastMousePosition.current.y = event.clientY;
// Update camera rotation incrementally
cameraRotation.current.y -= deltaX * 0.002;
cameraRotation.current.x -= deltaY * 0.002;
camera.rotation.y = cameraRotation.current.y;
camera.rotation.x = cameraRotation.current.x;
}
window.addEventListener('mousemove', onMouseMove);
// Scroll-based camera movement
function moveCamera() {
const t = document.body.getBoundingClientRect().top;
camera.position.z = t * -0.01;
camera.position.x = t * -0.0002;
// Optional: adjust camera rotation based on scroll if desired
}
document.body.onscroll = moveCamera;
moveCamera();
// Animation loop
const clock = new THREE.Clock();
const animate = () => {
requestAnimationFrame(animate);
torus.rotation.x += 0.01;
torus.rotation.y += 0.005;
torus.rotation.z += 0.01;
// Update the animation mixer every frame
if (mixerRef.current) {
const delta = clock.getDelta();
mixerRef.current.update(delta);
}
// Use composer instead of renderer to render the scene
composer.render();
};
animate();
return () => {
window.removeEventListener('mousemove', onMouseMove);
if (mixerRef.current) mixerRef.current.stopAllAction();
renderer.dispose(); // Cleanup WebGL resources
};
}, []);
return <canvas ref={rendererRef} {...props} />;
});
export default ThreeBackground;