I’ve tried all sorts of things, but nothing works.
I need to create an animation that smoothly transitions the camera’s focus to the platform’s target using GSAP here:
const SceneContent = ({ clouds, platforms, currentPlatformIndex, handlePlaneStop, handlePlaneAcceleration }) => {
const planeRef = useRef(); // linked to plane
useFrame(({ camera }) => {
if (currentPlatformIndex !== null) {
const target = platforms[currentPlatformIndex].cameraTarget;
camera.lookAt(new THREE.Vector3(…target)); //turn camera to platform target
} else if (planeRef.current) {
const forward = new THREE.Vector3(0, 0, -1);
forward.applyQuaternion(planeRef.current.quaternion); //apply plane orientation
camera.position.copy(planeRef.current.position).add(forward.clone().multiplyScalar(-10)); // camera forward the plane
camera.lookAt(planeRef.current.position.clone().add(forward.multiplyScalar(10)));
}
});
Full code of component
import React, { Suspense, useState, useRef } from “react”;
import { Canvas, useFrame } from “@react-three/fiber”;
import { useLocation } from “react-router-dom”;
import * as THREE from “three”;
import BackgroundModel from “./BackgroundModel”;
import Navbar from “…/navbar/NavbarDemo”;
import Cloud from “./Cloud”;
import FloatingIsland from “./FloatingIsland”;
import AnimatedFloatingIsland from “./AnimatedFloatingIsland”;
import ControlledPlane from “./ControlledPlane”;
import Board from “./Board”;
import GlowingPlatform from ‘./GlowingPlatform’;
import cloud1 from “…/…/assets/model/cloud1.glb”;
import cloud2 from “…/…/assets/model/cloud2.glb”;
import cloud3 from “…/…/assets/model/cloud3.glb”;
import cloud4 from “…/…/assets/model/cloud4.glb”;
import islandModel1 from “…/…/assets/model/island1.glb”;
import islandModel2 from “…/…/assets/model/island2.glb”;
import islandModel3 from “…/…/assets/model/island3.glb”;
import islandModel4 from “…/…/assets/model/island4.glb”;
import islandModel5 from “…/…/assets/model/island5.glb”;
import islandModel7 from “…/…/assets/model/island7.glb”;
import boardModel from “…/…/assets/model/board.glb”;
import img1 from ‘…/…/assets/img/screen1.jpg’;
import img2 from ‘…/…/assets/img/aboutMe.jpg’;
const Demo = ({ handleOnclick }) => {
const location = useLocation();
const platforms = [
{ position: [-3.5, 0, -7.8], cameraTarget: [-4.6, -0.1, -9.8] }, // walking girl
{ position: [ 15.5, 1.4, -22.8], cameraTarget: [17, 1.9, -24] }, // dinosaur
{ position: [101, 1110, 110], cameraTarget: [0, 0, 0] }
];
const [currentPlatformIndex, setCurrentPlatformIndex] = useState(null);
const handlePlaneStop = (index) => {
setCurrentPlatformIndex(index);
};
const handlePlaneAcceleration = () => {
setCurrentPlatformIndex(null);
};
const [clouds] = useState([
{
modelPath: cloud1,
position: [0, -20, -20],
scale: [0.05, 0.05, 0.05],
materialProps: { color: new THREE.Color(“rgb(255, 192, 203)”) },
},
{
modelPath: cloud2,
position: [20, 0, -55],
scale: [3.5, 3.5, 3.5],
materialProps: { color: new THREE.Color(“rgb(255, 192, 203)”) },
},
{
modelPath: cloud3,
position: [-30, 0, -30],
scale: [8.5, 8.5, 8.5],
materialProps: { color: new THREE.Color(“rgb(255, 192, 203)”) },
},
{
modelPath: cloud4,
position: [20, -5, 30],
scale: [8.5, 8.5, 8.5],
materialProps: { color: new THREE.Color(“rgb(255, 192, 203)”) },
},
]);
return (
<>
<Canvas
style={{ height: “100vh” }}
shadows={{ type: THREE.PCFSoftShadowMap }}
camera={{ position: [0, 5, 20], fov: 50 }}
>
<directionalLight
position={[-250, 0, -100]}
intensity={1}
color={new THREE.Color(“rgb(255, 182, 193)”)}
castShadow={true} // Enable shadow casting
/>
</>
);
};
const SceneContent = ({ clouds, platforms, currentPlatformIndex, handlePlaneStop, handlePlaneAcceleration }) => {
const planeRef = useRef(); // linked to plane
useFrame(({ camera }) => {
if (currentPlatformIndex !== null) {
const target = platforms[currentPlatformIndex].cameraTarget;
camera.lookAt(new THREE.Vector3(…target)); //turn camera to platform target
} else if (planeRef.current) {
const forward = new THREE.Vector3(0, 0, -1);
forward.applyQuaternion(planeRef.current.quaternion); //apply plane orientation
camera.position.copy(planeRef.current.position).add(forward.clone().multiplyScalar(-10)); // camera forward the plane
camera.lookAt(planeRef.current.position.clone().add(forward.multiplyScalar(10)));
}
});
return (
<>
{clouds.map((cloud, index) => (
))}
{platforms.map((platform, index) => (
<GlowingPlatform
key={index}
position={platform.position}
scale={[10, 10, 10]}
/>
))}
{/* walking girl */}
<AnimatedFloatingIsland
modelPath={islandModel1}
position={[-5, 0, -10]}
scale={[1, 1, 1]}
rotation={[0, Math.PI / 10, 0]}
/>
<Board
modelPath={boardModel}
texturePath={img1}
position={[-4.6, -0.1, -9.8]}
scale={[0.5, 0.5, 0.5]}
rotation={[0, Math.PI / 5, 0]}
url="https://example.com"
/>
{/* sakura waterfall */}
<FloatingIsland
modelPath={islandModel2}
position={[0, -3, -30]}
scale={[0.006, 0.006, 0.006]}
rotation={[0, Math.PI / 25, 0]}
/>
{/* dinosaur */}
<FloatingIsland
modelPath={islandModel3}
position={[20, 0, -26]}
scale={[0.6, 0.6, 0.6]}
rotation={[0, Math.PI / -3, 0]}
/>
<Board
modelPath={boardModel}
texturePath={img2}
position={[17, 1.4, -24]}
scale={[0.5, 0.5, 0.5]}
rotation={[0, Math.PI / -3, 0]}
url="https://example.com"
/>
{/* nihon */}
<FloatingIsland
modelPath={islandModel4}
position={[10, -2, 10]}
scale={[0.6, 0.6, 0.6]}
rotation={[0, Math.PI / -1.1, 0]}
/>
{/* floating house island */}
<FloatingIsland
modelPath={islandModel5}
position={[-20, 0, 1]}
scale={[0.4, 0.4, 0.4]}
rotation={[0, Math.PI / 2, 0]}
/>
{/* greeting girl */}
<AnimatedFloatingIsland
modelPath={islandModel7}
position={[15, 0, -5]}
scale={[1, 1, 1]}
rotation={[0, Math.PI / -2, 0]}
/>
{/* Controlled Plane with additional logic */}
<ControlledPlane
scale={[0.3, 0.3, 0.3]}
initialRotationX={Math.PI / 9}
initialRotationY={Math.PI / 0.9}
initialRotationZ={Math.PI / 20}
onStop={(index) => handlePlaneStop(index)} // Triggered when plane stops on the platform
onAccelerate={handlePlaneAcceleration} // Triggered when plane accelerates
platforms={platforms}
/>
</>
);
};
export default Demo;