How to use PointerLockControls with useFrame - three.js

I will implement an effect that I can move camera around an object.
Error example is this and I need to fix it. The difference between this and the latter is that this can update camera position to a 3D object in a model. This example eventually can move camera around a 3D object after updating camera position. But if I follow general use case, i.e. the latter, it can't function correctly. I wonder what's difference between this and the latter.
function Button(props) {
const vec = new THREE.Vector3(0, 3, 5);
const { x, y, z } = props.position;
if (x && y && z) {
vec.set(x, y, z);
}
useFrame((state) => {
const step = 0.1;
state.camera.position.lerp(vec, step);
state.camera.lookAt(0, 0, 0);
state.camera.updateProjectionMatrix();
});
return null;
}
const ModelCanvas = (props) => {
return (
<div className="center">
<Canvas
shadowMap
style={{ background: "#ffffff" }}
camera={{ position: [0, 3, 10], fov: 100 }}
gl={{ antialias: false, logarithmicDepthBuffer: true }}
id="my-canvas"
>
<ambientLight intensity={0.5} />
<pointLight position={[0, 60, -100]} intensity={20} />
<pointLight position={[-50, 0, -50]} intensity={2} />
<spotLight
castShadow
intensity={8}
angle={Math.PI / 10}
position={[10, 10, 10]}
shadow-mapSize-width={2048}
shadow-mapSize-height={2048}
/>
<Suspense fallback={null}>
<Model url={"/compressed.glb"} />
</Suspense>
{/* <PointerLockControls /> */}
<Button position={props.value} />
<PointerLockControls />
</Canvas>
</div>
);
};
And this example functions correctly.
const ModelCanvas = (props) => {
return (
<div className="center">
<Canvas
shadowMap
style={{ background: "#ffffff" }}
camera={{ position: [0, 3, 10], fov: 100 }}
gl={{ antialias: false, logarithmicDepthBuffer: true }}
id="my-canvas"
>
<ambientLight intensity={0.5} />
<pointLight position={[0, 60, -100]} intensity={20} />
<pointLight position={[-50, 0, -50]} intensity={2} />
<spotLight
castShadow
intensity={8}
angle={Math.PI / 10}
position={[10, 10, 10]}
shadow-mapSize-width={2048}
shadow-mapSize-height={2048}
/>
<Suspense fallback={null}>
<Model url={"/compressed.glb"} />
</Suspense>
{/* <PointerLockControls /> */}
{/* <Button position={props.value} /> */}
<PointerLockControls />
</Canvas>
</div>
);
};

Related

react-three-fiber: click with orthographic camera problem

clicks work well with the perspective camera, but don't work with the orthographic camera. If the orthographic camera is enabled, then dead zones appear in which the click does not work. How to make click work correctly with orthographic camera?
https://codesandbox.io/s/damp-water-2oqlvn?file=/src/index.js
function Thing() {
return (
<mesh
onClick={(e) => {
console.log('click')
}}>
<boxGeometry args={[10, 10, 10]} />
<meshNormalMaterial />
</mesh>
)
}
const App = () => {
return (
<Canvas
dpr={window.devicePixelRatio}
gl={{
antialias: true
}}
camera={{
far: Number.MAX_SAFE_INTEGER,
position: [0, 1, 0],
zoom: 10
}}
orthographic>
<Grid infiniteGrid sectionColor="#fff" fadeDistance={100} sectionThickness={0.5} sectionSize={10} />
<Thing />
<CameraControls />
</Canvas>
)
}

react/threejs-how to create curvy version of rectAreaLight in react three fiber

Hi, I managed to make rectangle shape of lighting effect as shown in A. But, how to make a similar lighting effect in B?
I could not find a curvy version of light API code provided by threeJs/react-three-fibre.
What I currently have in mind is stacking up rectAreaLight by manually adjusting the angle. However, I think this could make the lighting effect ugly and occupy lots of memory spaces.
It would be better if I can somehow make the rectAreaLight 'curvy', but I do not know how to do it or whether it can be done or not.
CodeSandbox: https://codesandbox.io/s/condescending-wiles-oev8pn?file=/src/App.js
Below I attached the codes.
import { Canvas } from '#react-three/fiber';
import { Suspense } from 'react';
import * as THREE from 'three';
import { OrbitControls, PerspectiveCamera } from '#react-three/drei';
const angleToRadians = (angleInDeg: number): number =>
(Math.PI / 180) * angleInDeg;
function App() {
return (
<Canvas
id='three-canvas-container'
style={{ height: '100vh', width: '100vw' }}
shadows
>
<Suspense fallback='loading'>
<PerspectiveCamera makeDefault position={[0, 2, 5]} zoom={1} />
<OrbitControls enableDamping={false} rotateSpeed={0.5} zoomSpeed={1} />
<ambientLight args={['#ffffff', 1]} />
<pointLight args={['#ffffff', 30, 10, 10]} position={[0, 0, 0]} />
<mesh //left wall
rotation={[0, angleToRadians(90), 0]}
position={[-3, 0, 2]}
>
<planeGeometry args={[4, 4]} />
<meshStandardMaterial color={'#091945'} side={THREE.DoubleSide} />
</mesh>
<mesh //right wall
rotation={[0, angleToRadians(90), 0]}
position={[3, 0, 2]}
>
<planeGeometry args={[4, 4]} />
<meshStandardMaterial color={'purple'} side={THREE.DoubleSide} />
</mesh>
<mesh //top ceiling
rotation={[angleToRadians(90), 0, 0]}
position={[0, 2, 2]}
>
<planeGeometry args={[7, 11]} />
<meshStandardMaterial color={'#091940'} side={THREE.FrontSide} />
</mesh>
<mesh //bottom floor
rotation={[angleToRadians(90), 0, 0]}
position={[0, -2, 2]}
>
<planeGeometry args={[7, 11]} />
<meshStandardMaterial color={'#091940'} side={THREE.DoubleSide} />
</mesh>
<mesh //middle curve wall
rotation={[
angleToRadians(90),
angleToRadians(90),
angleToRadians(-90),
]}
position={[0, -0.02, 0]}
>
<cylinderGeometry args={[3, 3, 4, 50, 1, true, 0, Math.PI]} />
<meshStandardMaterial color={'#320945'} side={THREE.DoubleSide} />
</mesh>
<group //lighting on rect
position={[-2.8, 1, 2]}
>
<mesh
rotation={[0, angleToRadians(90), 0]}
// position={[-2, 3.9 + Y_OFFSET, -0]}
>
<boxBufferGeometry args={[1, 0.2, 0.1]} />
<meshStandardMaterial color={'#091945'} side={THREE.DoubleSide} />
</mesh>
<rectAreaLight
args={['#50339b', 50, 1, 0.1]}
// position={[-2, 3.9 + Y_OFFSET, -0]}
rotation={[
angleToRadians(0),
angleToRadians(90),
angleToRadians(0),
]}
/>
</group>
<group //lighting on curve
position={[0, 0, -1]}
scale={0.5}
>
<mesh
rotation={[
angleToRadians(90),
angleToRadians(90),
angleToRadians(-90),
]}
>
<cylinderGeometry args={[3.95, 3.95, 1, 50, 1, true, 0, Math.PI]} />
<meshStandardMaterial
// color={new THREE.Color(0xffffff)} //bottom line is the original color. change to white for better visibility
color={new THREE.Color(0x320945)}
side={THREE.DoubleSide}
/>
</mesh>
{/* light code */}
</group>
</Suspense>
</Canvas>
);
}
export default App;

export 'Sparkles' (imported as 'Sparkles') was not found in '#react-three/drei'

Anyone knows if Sparkles particle has been removed or not in react-three/drei ? Didn't find anything in migration report of the package. It's giving error while importing.
I used the component like this:
<Canvas style={{ height: '100vh' }} >
<Environment>
<Stars radius={300} depth={60} count={5000} factor={20} saturation={1} fade />
<Cloud
opacity={0.1}
speed={0.1} // Rotation speed
width={20} // Width of the full cloud
depth={2} // Z-dir depth
segments={20} // Number of particles
/>
<pointLight position={[5, 5, 5]} intensity={.3} />
<ambientLight intensity={.3} />
<Box position={[0, 0, 0]} />
<OrbitControls autoRotate autoRotateSpeed={.5} ref={orbitRef} onChange={() => onOrbitChange() } />
</Environment>
</Canvas>
and the box component is:
<mesh
{...props}
ref={mesh}
// scale={active ? 1.5 : 1}
// onClick={(event) => setFlag(true) }
// onPointerOver={(event) => setHover(true)}
// onPointerOut={(event) => setHover(false)}
>
<boxBufferGeometry attach="geometry" args={[3, 3, 3 ]} />
<Sparkles count speed opacity color size scale noise />
</mesh>
I want to use Sparkles in Boxbuffergeometry.

How to get OrbitControls ref

I am trying to access OrbitControls ref as follow:
const controlsRef = useRef<any>();
return (
<>
<Canvas
camera={{
position: [0, 0, 100],
up: [0, 0, 1],
}}
>
<OrbitControls makeDefault ref={controlsRef} />
<ambientLight />
<FakeSphere position={[0, 0, 0]} color="red" />
<FakeSphere position={[100, 100, 0]} color="blue" />
<Nav controls={controlsRef.current} />
</Canvas>
</>
);
Code:
https://codesandbox.io/s/cool-flower-f5qr0?file=/src/App.tsx:949-962
The ref is undefined. Any idea please?
Found a hint hehe (https://github.com/pmndrs/drei/issues/718). Cant get ref from outside Canvas.
For now, add a wrapper over OrbitControls to capture the ref. Not sure if any better solution or not.
const MyControls = (props: any) => {
const { setControls } = props;
const ref = useRef<any>();
useEffect(() => {
if (!ref.current) return;
setControls(ref.current);
}, ref.current);
return <OrbitControls makeDefault ref={ref} />;
};

Objects don't overlap when rotating

I'm trying to reproduce this animation (see below) with react-three-fiber. I'm still very new to this package and to three-js.
http://makesportmakebook.com/livres/.
I've been able to do create book shapes with meshLambertMaterial, as such:
function Book(props) {
const mesh = useRef();
useFrame(() => {
mesh.current.rotation.x = mesh.current.rotation.y += 0.01
})
const bookCover = useLoader(TextureLoader, bookCoverImg)
const bookSpine = useLoader(TextureLoader, bookSpineImg)
const bookBack = useLoader(TextureLoader, bookBackImg)
const bookPages = useLoader(TextureLoader, bookPagesImg)
const bookPagesTexture = useLoader(TextureLoader, bookPagesTextureImg)
const bookPagesTopBottomTexture = useLoader(TextureLoader, bookPagesTopBottomTextureImg)
return (
<mesh
position={props.position}
ref={mesh}>
<boxBufferGeometry attach="geometry" args={
[
7, 10, 1.2, 4, 4, 1
]
} />
<meshLambertMaterial color={"0xffffff"} map={bookCover} />
<meshLambertMaterial map={bookSpine} />
<meshLambertMaterial map={bookBack} />
<meshLambertMaterial map={bookPages} />
<meshLambertMaterial map={texture_5} />
<meshLambertMaterial map={texture_6} />
</mesh>
)
};
Here's a code sandbox of my code so far: https://codesandbox.io/s/cocky-fast-61ndj
My question is: how can I avoid the overlap of these you can see here (below) but still keep the same parallel position we can see in the first example?
There are two ways that you could handle this. The first is to move the camera instead of the books. The second is that instead of moving the books separately, move them as a group. I suspect that this second method is what you want to do.
This was quick and dirty, but it works.
Create a function to house the two books. Put the two books in a group and rotate the group.
import React, { useRef, Suspense } from "react";
import { Canvas, useFrame, extend, useLoader } from "react-three-fiber";
import { OrbitControls, StandardEffects, draco } from "drei";
import { TextureLoader } from "three/src/loaders/TextureLoader.js";
extend({ OrbitControls });
function Bookshelf(props) {
const mesh = useRef();
useFrame(() => {
mesh.current.rotation.x = mesh.current.rotation.y += 0.01;
});
return (
<group ref={mesh} position={[0, 0, 0]}>
<Suspense fallback={null}><Book position={[3, 0, 3]} /></Suspense>
<Suspense fallback={null}><Book position={[-3, 0, 0]} /></Suspense>
</group>
)
}
function Book(props) {
const bookCover = useLoader(
TextureLoader,
"https://res.cloudinary.com/www-c-t-l-k-com/image/upload/v1607732427/HEAD_PUBLISHING/book-cover.jpg"
);
const bookSpine = useLoader(
TextureLoader,
"https://res.cloudinary.com/www-c-t-l-k-com/image/upload/v1607732420/HEAD_PUBLISHING/book-back.jpg"
);
const bookBack = useLoader(
TextureLoader,
"https://res.cloudinary.com/www-c-t-l-k-com/image/upload/v1607732421/HEAD_PUBLISHING/book-side.jpg"
);
const bookPages = useLoader(
TextureLoader,
"https://res.cloudinary.com/www-c-t-l-k-com/image/upload/v1607732421/HEAD_PUBLISHING/book-side.jpg"
);
const texture_5 = useLoader(
TextureLoader,
"https://res.cloudinary.com/www-c-t-l-k-com/image/upload/v1607732427/HEAD_PUBLISHING/book-cover.jpg"
);
const texture_6 = useLoader(
TextureLoader,
"https://res.cloudinary.com/www-c-t-l-k-com/image/upload/v1607732421/HEAD_PUBLISHING/book-spine.jpg"
);
return (
<mesh position={props.position} >
<boxBufferGeometry attach="geometry" args={[7, 10, 1.2, 4, 4, 1]} />
<meshLambertMaterial color={"0xffffff"} map={bookCover} />
<meshLambertMaterial map={bookSpine} />
<meshLambertMaterial map={bookBack} />
<meshLambertMaterial map={bookPages} />
<meshLambertMaterial map={texture_5} />
<meshLambertMaterial map={texture_6} />
</mesh>
);
}
export default function App() {
let styling = {
width: "100vw",
height: "100vh",
position: "relative"
};
return (
<div style={{ position: "relative" }}>
<Canvas camera={{ position: [0, 0, 20] }} style={styling}>
<ambientLight intensity={0.3} />
<directionalLight intensity={1} />
<Suspense fallback={null}>
<Bookshelf>
</Bookshelf>
</Suspense>
<OrbitControls enableZoom={false} />
</Canvas>
</div>
);
}

Resources