how to duplicate same model in react-three-fiber - javascript

import { Stats,OrbitControls,Circle } from '#react-three/drei'
import { Canvas,useLoader } from '#react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
export default function App() {
const gltf = useLoader(GLTFLoader,'./models/monkey.glb')
return (
<Canvas camera={{ position: [-0.5,1,2] }} shadows>
<directionalLight position={[3.3,1.0,4.4]} castShadow />
<primitive
object={gltf.scene}
position={[0,1,0]} />
<primitive
object={gltf.scene}
position={[0,1,0]} />
<Circle args={[10]} rotation-x={-Math.PI / 2} receiveShadow>
<meshStandardMaterial />
</Circle>
<OrbitControls target={[0,0,0]} />
<axesHelper args={[5]} />
<Stats />
</Canvas>
)
}
so I want to insert a model and want to copy it to 2, so I add 2 primitives but can't, is there any other way to duplicate the same model to 2?

Related

three js shadow is not showing on object

I'm a beginner at Three JS and have some issues with my code. My problem is I don't get the shadow properly in every object I attached. Here's the picture:
Here's my code in the sandbox:
https://codesandbox.io/s/threejs-code-3rlk8b
import React, { Suspense, useRef } from 'react';
import { Canvas, useFrame } from '#react-three/fiber';
import { ContactShadows, OrbitControls, useGLTF } from '#react-three/drei'
import './PartOne.css';
import { RoomOne } from '../assets/Room1';
import { Room2 } from '../assets/Room2';
import { Room3 } from '../assets/Room3';
import { Room4 } from '../assets/Room4';
import { Room5 } from '../assets/Room5';
import { Room6 } from '../assets/Room6';
import { Room7 } from '../assets/Room7';
import { Room8 } from '../assets/Room8';
const PartOne = () => {
return (
<div className='wrapper' >
<Canvas shadows camera={{ fov:70, position: [0,0,30] }} >
<Suspense fallback={null} >
<ambientLight intensity={0.3} />
<directionalLight castShadow receiveShadow intensity={2} position={[80,80,80]} />
{/* <spotLight castShadow receiveShadow intensity={2} position={[80,80,80]} /> */}
<RoomOne />
<Room2 />
<Room3 />
<Room4 />
<Room5 />
<Room6 />
<Room7 />
<Room8 />
<ContactShadows />
</Suspense>
<OrbitControls enablePan={true} enableZoom={true} enableRotate={true} />
</Canvas>
</div>
)
}
export default PartOne
Please help me with this problem. Or tell me if there is any solution to get rid of it.
The default setting of the orthographic shadow camera is -5 for left and bottom and 5 for right and top (see DirectionalLightShadow). This range is not big enough for your scene. You need to adjust the view volume of the orthographic shadow camera. e.g.:
<directionalLight
castShadow receiveShadow intensity={2} position={[80,80,80]}
shadow-normalBias={0.1}
shadow-camera-left={-12}
shadow-camera-right={12}
shadow-camera-top={12}
shadow-camera-bottom={-12}
shadow-camera-near={0.5}
shadow-camera-far={200}
/>

How to assign different click function to each face of the cube in react three fibre

Hi I have a simple Cube component made with react three fibre.
import {useState,useRef} from 'react';
import { useFrame } from '#react-three/fiber';
const Box = ({props}) =>{
const ref = useRef()
const [hovered, hover] = useState(false)
const boxClick = () =>{
alert('clicked the object')
}
return (
<mesh
{...props}
ref={ref}
onClick={boxClick}
scale={2}
onPointerOver={(event) => hover(true)}
onPointerOut={(event) => hover(false)}>
<boxGeometry args={[1.5, 1.5, 1.5]} />
<meshStandardMaterial color={hovered ? 'yellow' : 'orange'} />
</mesh>
)
}
export default Box;
I am importing the Box compoent in App.js and using it this way-
function App() {
const [boxes,setBoxes] = useState(0);
const box1Click = () =>{
setBoxes(() =>boxes+1)
alert(boxes)
}
return (
<Canvas className='main-canvas'>
<ambientLight intensity={0.5} />
<spotLight position={[5, 155, 10]} angle={0.15} penumbra={1} />
<pointLight position={[-100, -200, -100]} />
<Box position = {[0 ,0,0]} />
</Canvas>
);
}
export default App;
Right now I can click the cube and it runs the boxClick function properly. What I want to assign different click function to each face of the cube.
You can draw six planes and change the rotation or the position each time to construct a cube..
const Plane = (props) => {
const ref = useRef();
const texture = useLoader(THREE.TextureLoader, "/images/wood.png");
useFrame((state) => {
if (props.rotateX) ref.current.rotation.x = props.rotateX;
if (props.rotateY) ref.current.rotation.y = props.rotateY;
if (props.rotateZ) ref.current.rotation.z = props.rotateZ;
// ref.current.rotation.x += 0.01;
// ref.current.rotation.y += 0.01;
});
return (
<mesh ref={ref} {...props}>
<planeGeometry />
<meshBasicMaterial
color="red"
side={THREE.DoubleSide}
opacity={props.opacity}
transparent
visible={props.visible}
map={texture}
/>
</mesh>
);
};
And then add them to your scene
<Suspense fallback={null}>
<Box position={[3, 3, 0]} />
<Plane
args={[2, 2]}
position={[0.5, 0, 0.5]}
rotateX={Math.PI / 2}
opacity="0.5"
visible={true}
/>
<Plane
args={[2, 2]}
position={[0.5, 0.5, 1]}
opacity="0.8"
visible={true}
/>
<Plane
args={[2, 2]}
position={[0, 0.5, 0.5]}
rotateY={Math.PI / 2}
opacity="1"
visible={true}
/>
{/** ... */}
</Suspense>

How to Change OrbitControl target in React?

I have tried using react-three-fiber and react-drei to make a model but the target of the OrbitControl is making it appear to high
import React, { useRef, useState, Suspense, useEffect } from 'react'
import { Canvas, useFrame, useLoader, useThree} from '#react-three/fiber'
import { ContactShadows, Environment, useGLTF, OrbitControls, PerspectiveCamera } from "#react-three/drei"
import { proxy, useSnapshot } from 'valtio'
import {HexColorPicker} from "react-colorful"
...
export default function App() {
return (
<>
<Picker/>
<Canvas camera>
<PerspectiveCamera makeDefault position={[0.1, 0.9, 1.8]} fov={60} zoom={0.9}/>
<OrbitControls target={-0.061775 , 10, 0} />
<ambientLight intensity={1} />
<spotLight intensity={1} angle={0.1} penumbra={1} position={[10, 15, 10]} castShadow />
<Suspense fallback={null}>
<Bike />
<Environment preset="city" />
<ContactShadows rotation-x={Math.PI / 2} position={[0, -0.8, 0]} opacity={0.25} width={10} height={10} blur={1.5} far={0.8} />
</Suspense>
</Canvas>
</>
)
}
I have tried to change it using target variable in OrbitControls imported from #react-three/drei but the x and y axis is not working and z axis is nuts.
Should I use anothe OrbitControl for React.Please help.
In order to change the initial target for OrbitControls, you need to wrap the prop in an array like the following:
<OrbitControls target={[-0.061775 , 10, 0]} />
thanks to r3f "Set" shortcut
Alternatively, if you wanted to declare target.x, target.y, or target.z separately, you could use the following dashed syntax:
<OrbitControls target-x={-0.061775} />
thanks to r3f "Piercing into nested properties"

How to pass mouse events between overlapping components in ReactJS

I'm building a page with two overlapping components and i want to pass mouse events from the top component to the bottom one.
I'm using ReactJs and the code looks like this:
export default function App() {
return (
<>
<SkyBox className='Streetview' onClick={()=>console.log("you clicked STREETVIEW!")}/>
<Canvas className='Canvas' onClick={()=> console.log("you clicked THREEJS")}>
<Camera position={[0, 0, -20]} />
<ambientLight intensity={0.7} />
<spotLight position={[10, 10, 10]} angle={0.90} penumbra={1} />
<pointLight position={[-10, -10, -10]} />
<Suspense fallback={null}>
<Scene />
</Suspense>
</Canvas>
</>
);
}
so I want to get the mouse events from the Canvas component and pass them to the streetview SkyBox one so the user could navigate the streetview panorama and therefore the events i'm interested in is the mouseClick , mouseMove and mouseOut.
You can pass events as props like so:
import { useState } from 'react'
const Wrapper = () => {
const [event, setEvent] = useState(null)
return (
<div onClick={(e) => setEvent(e)}>
Lorem Ipsum
<Component event={event} />
</div>
)
}
const Component = (event) => {
console.log(event) // → event: SyntheticBaseEvent
return null
}
export default Wrapper
I'm not sure if you need the current state of the mouse-events but doesn't matter if state or the setters you can use context for this.
export const CanvasContext = createContext();
export default function App() {
const [mouseClicked, setMouseClicked] = useState(...);
const [mouseMoveState, setMouseMoveState] = useState(...);
const [mouseOut, setMouseOut] = useState(...);
return (
<CanvasContext.Provider value={{
mouseClicked,
setMouseClicked,
mouseMoveState,
setMouseMoveState,
mouseOut,
setMouseOut
}}>
<SkyBox
className="Streetview"
onClick={() => console.log("you clicked STREETVIEW!")}
/>
<Canvas
className="Canvas"
onClick={() => console.log("you clicked THREEJS")}
>
<Camera position={[0, 0, -20]} />
<ambientLight intensity={0.7} />
<spotLight position={[10, 10, 10]} angle={0.9} penumbra={1} />
<pointLight position={[-10, -10, -10]} />
<Suspense fallback={null}>
<Scene />
</Suspense>
</Canvas>
</CanvasContext.Provider>
);
}
then use inside Canvas/SkyBox/... the state/setter you need like this.
export default function Canvas() {
const {setMouseClicked, setMouseMoveState} = useContext(CanvasContext);
return (
<div>
.....
</div>
);
}

Suspended while rendering, but no fallback UI was specified when I used useLoader from react-three-fiber

I'm trying to use the texture for my ThreeJS object.
I'm getting error:
index.js:1 Error: Earth suspended while rendering, but no fallback UI was specified.
Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.
in Earth
Earth.js:
export const Earth = () => {
const texture = useLoader(THREE.TextureLoader, earthImg)
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<mesh>
<sphereBufferGeometry attach="geometry" args={[5, 32, 32]} />
<meshStandardMaterial attach="material" roughness={1} fog={false} />
</mesh>
</Suspense>
)
}
index.js:
export default function App() {
return (
<Canvas
style={{height:'100vh',width:'100vw'}}
camera={{
position: [0, window.innerWidth / window.innerHeight, 5]
}}
>
<ambientLight intensity={0.5} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
<pointLight position={[-10, -10, -10]} />
<Earth position={[-1.2, 0, 0]} />
</Canvas>
)
}
The component that useLoader() is called from (<Earth> in this case) needs to be wrapped in a <Suspense>, a suspense fallback cannot be specified from within the component.
Earth.js:
export const Earth = () => {
const texture = useLoader(THREE.TextureLoader, earthImg)
return (
<mesh>
<sphereBufferGeometry attach="geometry" args={[5, 32, 32]} />
<meshStandardMaterial attach="material" roughness={1} fog={false} />
</mesh>
)
}
index.js:
export default function App() {
return (
<Canvas
style={{height:'100vh',width:'100vw'}}
camera={{
position: [0, window.innerWidth / window.innerHeight, 5]
}}
>
<ambientLight intensity={0.5} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
<pointLight position={[-10, -10, -10]} />
<Suspense fallback={<h1>Loading profile...</h1>}>
<Earth position={[-1.2, 0, 0]} />
</Suspense>
</Canvas>
)
}

Categories

Resources