Assistance with help on making controls and drag rotation for Virtual Gallery

Hie Dev, I’m trying to build a Virtual Gallery like Infinity - Interactive Gallery
I’m facing an issue with managing the controls:

  1. WASD
  2. Rotation (Drag mouse)
  3. Click on the ground and lerp camera
  4. Mobile controls joystick

The issue im currently facing is that the drei camera-controls and keyboard-controls seem to be pulling on the camera as the same time. I’m planning on using react-three/fiber for the same but so far no luck.

Reference:

App.js

import { Canvas, useThree, useFrame, extend } from "@react-three/fiber"
import * as THREE from "three"
import { Sky,KeyboardControls, CameraControls } from "@react-three/drei"
import { Physics } from "@react-three/rapier"
import { Ground } from "./Ground"
import { Player } from "./Player"
import { Cube, Cubes } from "./Cube"
import { useEffect, useRef, useState } from "react"

function CustomCameraControls({ position, setPosition, pos = new THREE.Vector3(), look = new THREE.Vector3() }) {
  const cameraControlsRef = useRef()
  useEffect(() => {
    cameraControlsRef.current.azimuthRotateSpeed = -0.3 // negative value to invert rotation direction
    cameraControlsRef.current.polarRotateSpeed = -0.3 // negative value to invert rotation direction
  })

  useEffect(() => {
    console.log(position)
    if (position !== null) {
      console.log(position)
      pos.set(position.x, 1.24, position.z + 0.2)
      console.log(pos)
      look.set(position.x, 1.24, position.z - 0.2)
      console.log(look)
    }
  }, [position])

  useFrame((state, delta) => {
    if (position !== null) {
      console.log("LERP")
      state.camera.position.lerp(pos, 0.5)
      state.camera.updateProjectionMatrix()
      cameraControlsRef.current.setLookAt(state.camera.position.x, state.camera.position.y, state.camera.position.z, look.x, look.y, look.z, true)
      cameraControlsRef.current.update(delta)
      setTimeout(() => {
        setPosition(null)
        console.log(position)
      }, "5000")
      // setPosition(null)
    }
    console.log(cameraControlsRef.current.getPosition())
    console.log(cameraControlsRef.current.getTarget())
    console.log(state.camera.position)
    state.camera.updateProjectionMatrix()

    cameraControlsRef.current.update(delta)
  })

  return <CameraControls enabled={true} ref={cameraControlsRef} />
}

export default function App() {
  const [pos, setPos] = useState(null)
  return (
    <KeyboardControls
      map={[
        { name: "forward", keys: ["ArrowUp", "w", "W"] },
        { name: "backward", keys: ["ArrowDown", "s", "S"] },
        { name: "left", keys: ["ArrowLeft", "a", "A"] },
        { name: "right", keys: ["ArrowRight", "d", "D"] },
      ]}>
      <Canvas shadows camera={{ fov: 45, position: [0, 0, 0.5] }}>
        <Sky sunPosition={[100, 20, 100]} />
        <ambientLight intensity={0.3} />
        <pointLight castShadow intensity={0.8} position={[100, 100, 100]} />
        <Physics gravity={[0, -30, 0]}>
          <Ground pos={pos} setPos={setPos} />
          <Player pos={pos} />
          <Cube position={[0, 0.5, -10]} />
          <Cubes />
        </Physics>
        {pos !== null && <CustomCameraControls position={pos} setPosition={setPos} />}
      </Canvas>
    </KeyboardControls>
  )
}

Player.js

import * as THREE from "three"
import { useRef } from "react"
import { useFrame } from "@react-three/fiber"
import { useKeyboardControls } from "@react-three/drei"
import { CapsuleCollider, RigidBody } from "@react-three/rapier"


const SPEED = 5
const direction = new THREE.Vector3()
const frontVector = new THREE.Vector3()
const sideVector = new THREE.Vector3()

export function Player({ pos }) {
  const ref = useRef()

  const [, get] = useKeyboardControls()
  useFrame((state) => {
    const { forward, backward, left, right, jump } = get()
    const velocity = ref.current.linvel()
    console.log(pos)
    console.log(state.camera.position)
    // update camera
    state.camera.position.set(...ref.current.translation())

    // movement
    frontVector.set(0, 0, backward - forward)
    sideVector.set(left - right, 0, 0)
    direction.subVectors(frontVector, sideVector).normalize().multiplyScalar(SPEED).applyEuler(state.camera.rotation)
    ref.current.setLinvel({ x: direction.x, y: velocity.y, z: direction.z })
  })
  return (
    <>
      <RigidBody ref={ref} colliders={false} mass={1} type="dynamic" position={[0, 0, 0]} enabledRotations={[false, false, false]}>
        <CapsuleCollider args={[0.75, 0.5]} />
      </RigidBody>
    </>
  )
}

Any assistance is much appreciated.

The question is, do you need custom controls? If you’re using r3f and drei ecctrl were just published…

I mean, I’m not sure because It needs to be in first person and i’m trying to get tap on ground to move over there type of camera animation.

Let me check out the lib, thanks

Edit: I checked it out. It’s character based and thats a third person view. The app uses pointerlockevents, which is not something I want for the metaverse gallery I’m supposed to build.

So I think yes, I would need to pull on the camera.