I spent the whole day really finding why my camera transitions are not working, I am all ears to here you nice solutions here is the code “The Animation is in the intro function”:
import React, { Suspense, useEffect, useRef, useState } from ‘react’;
import * as swipeAnimation from ‘./Swipe.json’;
import { Canvas, useFrame } from ‘@react-three/fiber’;
import { easeCubic } from ‘d3-ease’;
import {
Reflector,
useTexture,
PerspectiveCamera,
Text
} from ‘@react-three/drei’;
import { IntroDef } from “…/…/Avatars/IntroDef”;
import * as THREE from ‘three’;
import Lottie from “lottie-react”;
const cameraPositions = [
[0, 3, 100],
[20, 10, 80],
[-20, 5, 75],
[10, 12, 90]
];
const timings = [5000, 3000, 4000, 6000];
export default function IntroAvatar() {
const defaultOptions = {
loop: true,
autoplay: true,
animationData: swipeAnimation.default,
};
const characterRef = useRef();
const cameraRef = useRef(); // Declare a camera reference
const [cameraPosition, setCameraPosition] = useState({ x: 0, y: 3, z: 100 });
const [currentPosition, setCurrentPosition] = useState(0);
const handleTransition = () => {
let nextPosition = (currentPosition + 1);
setCurrentPosition(nextPosition);
setCameraPosition({x: cameraPositions[nextPosition][0],y: cameraPositions[nextPosition][1],z: cameraPositions[nextPosition][2]});
};
useEffect(() => {
if(currentPosition<timings.length) {
const interval = setTimeout(handleTransition, timings[currentPosition]);
console.log(currentPosition);
return () => clearTimeout(interval);
}
}, [currentPosition]);
return (
<div className={'intro-avatar-3d'}>
<div className="swipe-animation">
<Lottie options={defaultOptions} animationData={swipeAnimation.default} />
</div>
<Canvas concurrent gl={{ alpha: true }} pixelRatio={[1, 1.5]}>
<perspectiveCamera ref={cameraRef} position={cameraPosition} fov={15} />
<color attach="background" args={['black']} />
<fog attach="fog" args={['black', 15, 20]} />
<Suspense fallback={null}>
<group position={[0, -1, 0]}>
<IntroDef characterRef={characterRef} rotation={[0, 0, 0]} scale={[1, 1, 1]} />
<VideoText character={characterRef} position={[0, 1.3, -1]} />
<Ground />
</group>
<Intro cameraRef={cameraRef} targetPosition={cameraPosition} />
</Suspense>
</Canvas>
</div>
);
}
function Ground() {
const [floor, normal] = useTexture([‘/textures/reflect/wooden_diff.jpg’, ‘/textures/reflect/wooden_nordxl.jpg’]);
return (
<Reflector blur={[400, 100]} resolution={1024} args={[10, 10]} mirror={0.5} mixBlur={6} mixStrength={1.5} rotation={[-Math.PI / 2, 0, Math.PI / 2]}>
{(Material, props) => <Material color=“#a0a0a0” metalness={0.4} normalScale={[2, 2]} {…props} />}
);
}
function VideoText(props) {
const textRef = useRef();
const [distance, setDistance] = useState(100);
const [spacing, setSpacing] = useState(1);
function lerp(a, b, t) {
return a + t * (b - a);
}
useFrame(() => {
const characterPosition = props.character.current.position;
const newDistance = characterPosition.distanceTo(textRef.current.position);
const targetSpacing = newDistance < 2 ? 10 : 1;
const t = easeCubic(0.3);
const newSpacing = lerp(spacing, targetSpacing, t);
setSpacing(newSpacing);
setDistance(newDistance);
});
const renderedText = `WELCOME TO${' '.repeat(Math.round(spacing))}MY PORTFOLIO!`;
return (
<Text ref={textRef} font="/intro.ttf" fontSize={0.7} color={'#0e758f'} letterSpacing={0.1} {...props}>
{renderedText}
<meshBasicMaterial toneMapped={false} />
</Text>
);
}
function Intro(props) {
const { cameraRef, targetPosition } = props;
return useFrame(() => {
if (cameraRef.current) {
cameraRef.current.position.lerp(new THREE.Vector3(targetPosition.x, targetPosition.y, targetPosition.z), 0.05);
cameraRef.current.lookAt(0, 0, 0);
cameraRef.current.updateProjectionMatrix();
}
});
}