installed three js added test model to contact form section fixed issue with double render of useEffect that was causing it to show up twice once compiled. This was resolved using a boolean check to see if it is mounted first. n Next.js, when you navigate between pages, the entire React tree is unmounted and then remounted. This means that any component with a useEffect hook will run its cleanup function before being unmounted, and then its effect function again when it is remounted. This can cause the effect to run twice.
99 lines
3.3 KiB
JavaScript
99 lines
3.3 KiB
JavaScript
import React, { useRef, useEffect, useState } from 'react';
|
|
import * as THREE from 'three';
|
|
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
|
|
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
|
|
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
|
|
import { RGBShiftShader } from 'three/examples/jsm/shaders/RGBShiftShader.js';
|
|
import { DotScreenShader } from 'three/examples/jsm/shaders/DotScreenShader.js';
|
|
|
|
const ContactThreeJsComponent = React.memo(() => {
|
|
const [isMounted, setIsMounted] = useState(false);
|
|
const mountRef = useRef(null);
|
|
|
|
useEffect(() => {
|
|
setIsMounted(true);
|
|
|
|
if (isMounted) {
|
|
console.log("useEffect called");
|
|
let camera, renderer, composer;
|
|
let object;
|
|
|
|
function init() {
|
|
renderer = new THREE.WebGLRenderer();
|
|
renderer.setPixelRatio(window.devicePixelRatio);
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
mountRef.current.appendChild(renderer.domElement);
|
|
|
|
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
|
|
camera.position.z = 400;
|
|
|
|
const scene = new THREE.Scene();
|
|
scene.fog = new THREE.Fog(0x000000, 1, 1000);
|
|
|
|
object = new THREE.Object3D();
|
|
scene.add(object);
|
|
|
|
const geometry = new THREE.SphereGeometry(1, 4, 4);
|
|
const material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true });
|
|
|
|
for (let i = 0; i < 100; i++) {
|
|
const mesh = new THREE.Mesh(geometry, material);
|
|
mesh.position.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize();
|
|
mesh.position.multiplyScalar(Math.random() * 400);
|
|
mesh.rotation.set(Math.random() * 2, Math.random() * 2, Math.random() * 2);
|
|
mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 50;
|
|
object.add(mesh);
|
|
}
|
|
|
|
scene.add(new THREE.AmbientLight(0x222222));
|
|
|
|
const light = new THREE.DirectionalLight(0xffffff);
|
|
light.position.set(1, 1, 1);
|
|
scene.add(light);
|
|
|
|
composer = new EffectComposer(renderer);
|
|
composer.addPass(new RenderPass(scene, camera));
|
|
|
|
const effect1 = new ShaderPass(DotScreenShader);
|
|
effect1.uniforms['scale'].value = 4;
|
|
composer.addPass(effect1);
|
|
|
|
const effect2 = new ShaderPass(RGBShiftShader);
|
|
effect2.uniforms['amount'].value = 0.0015;
|
|
composer.addPass(effect2);
|
|
|
|
window.addEventListener('resize', onWindowResize);
|
|
}
|
|
|
|
function onWindowResize() {
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
camera.updateProjectionMatrix();
|
|
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
composer.setSize(window.innerWidth, window.innerHeight);
|
|
}
|
|
|
|
function animate() {
|
|
requestAnimationFrame(animate);
|
|
object.rotation.x += 0.005;
|
|
object.rotation.y += 0.01;
|
|
composer.render();
|
|
}
|
|
|
|
init();
|
|
animate();
|
|
|
|
return () => {
|
|
// cleanup logic
|
|
window.removeEventListener('resize', onWindowResize);
|
|
renderer.dispose();
|
|
composer.dispose();
|
|
};
|
|
}
|
|
}, [isMounted]);
|
|
|
|
return <div ref={mountRef} />;
|
|
});
|
|
|
|
export default ContactThreeJsComponent;
|