Moncef Grey
Moncef Grey

Reputation: 33

First person perspective in threejs

I've created this example from a GLTF file of Dragonball animation on scroll, but i couldn't achieve my goal which is the user should feel like he is the one riding the car ( 1st person perspective ), How can i do that?

Also i have a question, when the model first appear, it shows the world as a sphere the the camera change its focus to the car, How can focus the camera on 1st person perspective from the beginning?

Here is the example i'm working on:

https://codesandbox.io/s/dbz-snake-path-ecz8ul

import * as THREE from "three";
import { Suspense, useEffect } from "react";
import { Canvas, useFrame, useLoader } from "@react-three/fiber";
import {
  ScrollControls,
  useScroll,
  useAnimations,
  Stage
} from "@react-three/drei";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

const Model = ({ ...props }) => {
  // This hook gives you offets, ranges and other useful things
  const scroll = useScroll();

  const { scene, animations } = useLoader(GLTFLoader, "/model/scene.gltf");

  const { actions } = useAnimations(animations, scene);

  let car = scene.getObjectByName("car");

  useEffect(() => {
    actions["Take 001"].play().paused = true;
  }, [actions]);

  useFrame((state, delta) => {
    // Animate on scroll
    const action = actions["Take 001"];
    const offset = scroll.offset;
    action.time = THREE.MathUtils.damp(
      action.time,
      action.getClip().duration * offset,
      100,
      delta
    );

    // Camera to follow car element
    let position = new THREE.Vector3(0, 0, 0);
    position.setFromMatrixPosition(car.matrixWorld);

    let wDir = new THREE.Vector3(0, 0, 1);

    wDir.normalize();

    let cameraPosition = position
      .clone()
      .add(wDir.clone().multiplyScalar(1).add(new THREE.Vector3(0, 0.3, 0)));

    wDir.add(new THREE.Vector3(0, 0.2, 0));
    state.camera.position.copy(cameraPosition);
    state.camera.lookAt(position);
  });

  return <primitive object={scene} {...props} />;
};

const App = () => {
  return (
    <>
      <Suspense fallback={null}>
        <Canvas>
          <Stage environment={null}>
            <ScrollControls pages={10}>
              <Model scale={1} />
            </ScrollControls>
          </Stage>
        </Canvas>
      </Suspense>
    </>
  );
};

export default App;

Upvotes: 1

Views: 633

Answers (1)

M -
M -

Reputation: 28472

You should simply add the camera as a child Object of the car. That way when you move the car forward, the camera will immediately follow.

// Add camera as child of car
car.add(camera);

// Now the camera will move and rotate with the car
car.position.set(x, y, z);
car.rotation.y = angle;

You might need to adjust the camera's position at first so it's placed behind the character, or maybe above, that's up to you.

Upvotes: 1

Related Questions