How to pass the text behind a 3D object in Three JS - three.js

Hello everyone I would like to pass the text behind my 3D object
Here is the result I currently have
demo
Here is the code of the text components
TextHelper.js
import { Html } from "#react-three/drei";
import React from "react";
const TextHelper = ({ position, text, rotation }) => {
return (
<Html
transform
position={position}
rotation={rotation}
>
<div className="label">{text}</div>
</Html>
);
};
export default TextHelper;
App.js
<TextHelper
position={[280, 0, 0]}
text="BACK"
rotation={[-Math.PI / 2, 0, -Math.PI / 2]}
/>
<TextHelper
position={[-280, 0, 0]}
text="FRONT"
rotation={[-Math.PI / 2, 0, Math.PI / 2]}
/>
<TextHelper
position={[0, 0, 280]}
text="LEFT"
rotation={[Math.PI / 2, Math.PI, 0]}
/>
<TextHelper
position={[0, 0, -280]}
text="RIGHT"
rotation={[-Math.PI / 2, 0, 0]}
/>

Related

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;

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} />;
};

How to pan the camera by code in react-three/fiber and react-three/drei

I can pan the the camera from default position [0,0,0] to [100,100,0] using the mouse with OrbitControls. However still fail to do the panning by code.
<Canvas
camera={{
position: [0, 0, 100],
up: [0, 0, 1],
}}
>
<OrbitControls />
<ambientLight />
<FakeSphere position={[0, 0, 0]} color="red" />
<FakeSphere position={[100, 100, 0]} color="blue" />
</Canvas>
Any idea please.
We need to move the camera to [100,100,100] and look at to [100,100,0]
useEffect(() => {
if (!controls || !camera) return;
camera.position.set(100, 100, 100);
controls.target.set(100, 100, 0);
}, [camera, controls]);

Unable to use Pointer Lock with PerspectiveCamera and PointerLockControls

I like react-three and I am trying to make an FPV character with a body:
https://codesandbox.io/s/fpv-player-ers63
So the goal is that the camera is placed at the head level and the character moves around like in original example https://codesandbox.io/s/minecraft-vkgi6 by Paul Henschel
drcmda
I have added PerspectiveCamera to change the camera position but now PointerLockControls doesn't work any more and I do not understand why and how to handle it.
Thank you
PerspectiveCamera usage
export const Player = (props) => {
const axe = useRef()
const [ref, api] = useSphere(() => ({ mass: 1, type: "Dynamic", position: [0, 10, 0], ...props }))
const { forward, backward, left, right, jump } = usePlayerControls()
const { camera } = useThree()
const velocity = useRef([0, 0, 0])
useEffect(() => api.velocity.subscribe((v) => (velocity.current = v)), [])
useFrame((state) => {
ref.current.getWorldPosition(camera.position)
frontVector.set(0, 0, Number(backward) - Number(forward))
sideVector.set(Number(left) - Number(right), 0, 0)
direction.subVectors(frontVector, sideVector).normalize().multiplyScalar(SPEED).applyEuler(camera.rotation)
speed.fromArray(velocity.current)
axe.current.children[0].rotation.x = THREE.MathUtils.lerp(
axe.current.children[0].rotation.x,
Math.sin((speed.length() > 1) * state.clock.elapsedTime * 10) / 20,
0.01,
)
axe.current.rotation.copy(camera.rotation)
axe.current.position.copy(camera.position).add(camera.getWorldDirection(rotation).multiplyScalar(1))
api.velocity.set(direction.x, velocity.current[1], direction.z)
if (jump && Math.abs(velocity.current[1].toFixed(2)) < 0.05) api.velocity.set(velocity.current[0], 10, velocity.current[2])
})
return (
<>
<mesh ref={ref} />
<group ref={axe} onPointerMissed={(e) => (axe.current.children[0].rotation.x = -0.5)}>
<group position={[0, 7, 0]}>
<PerspectiveCamera makeDefault={true} fov={75}>
<Body position={[0, -4, 1]} />
</PerspectiveCamera>
</group>
</group>
</>
)
}
PointerLockControls usage
export default function App() {
return (
<Canvas
shadows
gl={{ alpha: false }}
camera={{ fov: 45 }}
raycaster={{
computeOffsets: (e) => ({ offsetX: e.target.width / 2, offsetY: e.target.height / 2 }),
}}>
<Sky sunPosition={[100, 20, 100]} />
<ambientLight intensity={0.3} />
<pointLight castShadow intensity={0.8} position={[100, 100, 100]} />
<Physics gravity={[0, -30, 0]}>
<Ground />
<Player />
<Reflector
blur={[0, 0]} // Blur ground reflections (width, heigt), 0 skips blur
mixBlur={0.1} // How much blur mixes with surface roughness
mixStrength={0.25} // Strength of the reflections
resolution={1024} // Off-buffer resolution, lower=faster, higher=better quality
args={[10, 30]} // PlaneBufferGeometry arguments
position={[0, 0, -20]}
rotation={[0, 0, 2 * Math.PI]}
mirror={0.5} // Mirror environment, 0 = texture colors, 1 = pick up env colors
minDepthThreshold={0.25}
maxDepthThreshold={1}
depthScale={50}>
{(Material, props) => <Material metalness={0} roughness={0} {...props} />}
</Reflector>
</Physics>
<PointerLockControls />
</Canvas>
)
}
Browser: Firefox 94.0.2 (64-bit), macOS Monterey
"dependencies": {
"#pmndrs/branding": "0.0.8",
"#react-three/cannon": "4.0.1",
"#react-three/drei": "7.17.2",
"#react-three/fiber": "7.0.17",
"#types/three": "0.133.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-scripts": "4.0.3",
"simplex-noise": "3.0.0",
"three": "0.133.1",
"zustand": "3.6.1"
},
https://codesandbox.io/s/fpv-player-ers63
Well, I found that it is sufficient to offset the camera in useFrame update
https://codesandbox.io/s/fpv-player-ers63
export const Player = (props) => {
const axe = useRef()
const [ref, api] = useSphere(() => ({ args: [1], mass: 1, type: "Dynamic", position: [0, 10, 0], ...props }))
const { forward, backward, left, right, jump } = usePlayerControls()
const { camera } = useThree()
const velocity = useRef([0, 0, 0])
useEffect(() => api.velocity.subscribe((v) => (velocity.current = v)), [])
useFrame((state) => {
ref.current.getWorldPosition(camera.position)
frontVector.set(0, 0, Number(backward) - Number(forward))
sideVector.set(Number(left) - Number(right), 0, 0)
direction.subVectors(frontVector, sideVector).normalize().multiplyScalar(SPEED).applyEuler(camera.rotation)
speed.fromArray(velocity.current)
axe.current.children[0].rotation.x = THREE.MathUtils.lerp(
axe.current.children[0].rotation.x,
Math.sin((speed.length() > 1) * state.clock.elapsedTime * 10) / 10,
0.1,
)
axe.current.rotation.copy(camera.rotation)
axe.current.position.copy(camera.position).add(camera.getWorldDirection(rotation).multiplyScalar(1))
camera.position.setY(camera.position.y + 8)
api.velocity.set(direction.x, velocity.current[1], direction.z)
if (jump && Math.abs(velocity.current[1].toFixed(2)) < 0.05) api.velocity.set(velocity.current[0], 10, velocity.current[2])
})
return (
<>
<mesh ref={ref} />
<group ref={axe} onPointerMissed={(e) => (axe.current.children[0].rotation.x = -0.5)}>
<Body position={[0, 4, 0]} />
</group>
</>
)
}

Sphere not respecting gravity outside plane geometry

I have this simple environment with a sphere and a plane. Both of the objects are wrapped within a Physics component and the physics work, if I remove the plane the sphere will fall. But when I run the sphere outside the plane, the sphere does not fall. I don't know if I have misunderstood something trivial, maybe the plane is wider than what it looks like for example?
I don't think there is a way to set the width/depth of the mesh, so I assume it is the width/depth of the planeBufferGeometry that counts?
main.js:
import { Canvas } from '#react-three/fiber'
import { Sky, PointerLockControls } from '#react-three/drei'
import { Physics } from '#react-three/cannon'
import { Ground, Sphere } from '../components/'
export default function Game(props) {
return (
<>
<Canvas shadows colorManagement camera={{ fov: 45 }}>
<Sky sunPosition={[100, 10, 100]} />
<ambientLight intensity={0.3} />
<pointLight castShadow intensity={2.8} position={[100, 100, 100]} />
<Physics gravity={[0, -106, 0]}>
<Ground />
<Sphere />
</Physics>
<PointerLockControls />
</Canvas>
</>
)
}
Ground.js:
import { usePlane } from '#react-three/cannon'
import { useNormalTexture } from '#react-three/drei'
export default function Ground(props) {
const [ref] = usePlane(() => ({ rotation: [-Math.PI / 2, 0, 0], ...props }))
const [normalMap] = useNormalTexture(32, {
offset: [0, 0],
repeat: [100, 100],
anisotropy: 8
})
return (
<mesh ref={ref} receiveShadow>
<planeBufferGeometry attach="geometry" args={[50, 50]} />
<meshStandardMaterial
attach="material"
normalMap={normalMap}
color="#dadb84"
/>
</mesh>
)
}

Resources