์น์์ 3d๋ฅผ ๊ตฌํํ ์ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
Three.js ๋ฅผ ์ฌ์ฉํ ํ์ด์ง https://github.com/home ๊นํ๋ธ https://eyes.nasa.gov/apps/mars2020/#/home ๋์ฌ https://www.midwam.com/en midwam
์น์์ 3d๋ฅผ ๊ตฌํํ์ผ๋ฉด ๋ชจ๋ Three.js๋ฅผ ์ฌ์ฉํ ๊ฒ
https://threejs.org/ ์์ ๋๋ง์ three.js๋ฅผ ์ฌ์ฉํ ํ์ด์ง๋ค์ ๋ณผ ์ ์์ต๋๋ค.
-
๋ฆฌ์กํธ ํ๋ก์ ํธ ์์ฑ create-react-app
npx create-react-app 3d-app -
๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
npm install threeThree.jsnpm install @react-three/fiberReact์์ Three.js๋ฅผ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํ Libnpm install use-cannon๋ฌผ๋ฆฌ์์ง Lib
import * as THREE from "three";three.js์์ 3d ์ค๋ธ์ ํธ๋ฅผ ํ์ํ๋ ค๋ฉด 3๊ฐ์ง ์์๊ฐ ํ์ํฉ๋๋ค.
- scene
- camera
- renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();camera์ ์์ฑ์์ ๋ค์ด๊ฐ๋ 4๊ฐ์ง ์์ฑ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- FOV(์์ผ๊ฐ) : ํด๋น ์์ ์ ํ๋ฉด์ด ๋ณด์ฌ์ง๋ ์ ๋. ๊ฐ๋๋ก ๊ฐ์ ์ค์ ํฉ๋๋ค.
- aspect ratio(์ข ํก๋น) : ๋๋ถ๋ถ ์์์ ๋์ด์ ๋๋น์ ๋ง์ถ์ด ํ์ํ๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด ์์ด๋ ์คํฌ๋ฆฐ์ ์๋ ์ํ๋ฅผ ํธ๋ ๊ฒ์ฒ๋ผ ์ด๋ฏธ์ง๊ฐ ํ์ด์ง๋๋ค.
- near : ์ด ๊ฐ๋ณด๋ค ๊ฐ๊น์ด ์๋ ์ค๋ธ์ ํธ๋ ๋ ๋๋ง ๋์ง ์์
- far : ์ด ๊ฐ๋ณด๋ค ๋ฉ๋ฆฌ ์๋ ์ค๋ธ์ ํธ๋ ๋ ๋๋ง ๋์ง ์์
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.innerHTML = "";
document.body.appendChild(renderer.domElement);๋ค์์ผ๋ก ๋ ๋๋ง ํ ๊ณณ์ ํฌ๊ธฐ๋ฅผ ์ค์ ํด์ฃผ๊ณ HTML ๋ฌธ์์ ์ถ๊ฐํด์ค์ผ ํฉ๋๋ค. ์ผ๋จ ๋์ด์ ๋๋น๋ฅผ ๊ฐ๊ฐ ์๋์ฐ์ ํฌ๊ธฐ๋ก ์ค์ ํ์์ต๋๋ค.document.body.innerHTML = ""๋ renderer๋ง ํ๋ฉด์ ํ์ํ๊ธฐ ์ํด์์
๋๋ค. renderer๋ <canvas> ์๋ฆฌ๋จผํธ๋ก HTML ๋ฌธ์์ ์ถ๊ฐ๋ฉ๋๋ค.
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({
color: "blue"
});
camera.position.z = 5;
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);Three.js ์์ 3d ์ค๋ธ์ ํธ๋ mesh๋ผ ๋ถ๋ฆ
๋๋ค. mesh๋ 2๊ฐ์ง ์์๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
- geometry : ๊ธฐํํ์ ํํ, ๋ผ๋๋ฅผ ๋ด๋นํ๋ ๋ถ๋ถ
- material : ์ง๊ฐ, ์, ๋ฐ์ฌ์จ ๋ฑ ๋ฌผ์ฒด์ ํ๋ฉด
2๊ฐ์ง ์์ฑ์ผ๋ก cube๋ผ๋ mesh๋ฅผ ๋ง๋ค๊ณ scene์ ์ถ๊ฐํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ธฐ๋ณธ ์ค์ ์ scene.add()๋ก ๋ฌผ์ฒด๋ฅผ ์ถ๊ฐํ๋ฉด (0,0,0)์ ์์น๋ฅผ ๊ฐ์ต๋๋ค. ์ด๋ ๊ฒ ๋๋ฉด camera์ cube๊ฐ ๋์ผํ ์์น์ ๊ฒน์ณ์ ์ ๋๋ก ๋ณด์ด์ง ์์ ๊ฒ์
๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ camera์ ์์น๋ฅผ ์ฝ๊ฐ ๋ณ๊ฒฝํ์์ต๋๋ค.
์์ง ํ๋ฉด์๋ ์๋ฌด๊ฒ๋ ๋์ค์ง ์์ ๊ฒ์
๋๋ค. ์๋ฌด๊ฒ๋ ๋ ๋๋งํ์ง ์์๊ธฐ ๋๋ฌธ์
๋๋ค. ํ๋ฉด์ cube๋ฅผ ๋ ๋๋งํ๊ณ ํ์ ์ํค๊ธฐ ์ํ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();1์ด์ 60๋ฒ ๋ ๋๋ง(60fps) ํ ๊ฒ์ด๊ณ ๊ทธ๋ด ๋๋ง๋ค x ๋ฐฉํฅ์ผ๋ก 0.01, y ๋ฐฉํฅ์ผ๋ก 0.01๋งํผ ํ์ ํ ๊ฒ์ ๋๋ค.
์ด๋ฏธ ๋ฉ์ง๊ฒ cube๊ฐ ๋ ๋๋ง๋๊ณ ํ์ ํ๊ณ ์๊ฒ ์ง๋ง ์ฐฝ ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ์ ๋ ๋น์จ์ด ๋ญ๊ฒ์ง๋๊ฒ ๋ณด์
๋๋ค. ์๋ํ๋ฉด renderer์ camera์ ์ค์ ์ด ์ฒ์ ์ฐฝ์ ์ผฐ์ ๋์ ์๋์ฐ ์ฌ์ด์ฆ๋ก ๊ณ ์ ๋์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค. addEventListener๋ฅผ ํตํด ์ฐฝ์ด resize๋ ๋๋ง๋ค renderer์ camera์ ์ค์ ์ ๋ฐ๊ฟ์ค์๋ค.
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});import * as THREE from "three";
import "./App.css";
function App() {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.innerHTML = "";
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({
color: "blue"
});
camera.position.z = 5;
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
return null;
}
export default App;์ฌ์ค @react-three/fiber๋ฅผ ํ์ฉํ๋ฉด ํจ์ฌ ์ฝ๊ฒ ๊ฐ๋จํ scene์ ๋ง๋ค ์ ์์ต๋๋ค.
import { Canvas, useFrame } from "@react-three/fiber";return (
<div style={{ width: "100vw", height: "100vh" }}>
<Canvas style={{ background: "black" }}>
<Box />
</Canvas>
</div>
);Canvas๋ฅผ ๋ง๋ค๋ฉด scene, camera, renderer๋ฅผ ๋ฐ๋ก ๋ง๋คํ์๊ฐ ์์ต๋๋ค. Canvas์ ์คํ์ผ์ ๋ค๋ฅธ HTML ํ๊ทธ๋ค ์ฒ๋ผ style์์ฑ์ผ๋ก ์ง์ ํ ์ ์์ต๋๋ค.
Canvas์์ ๋ ๋๋ง๋ Box๋ ๋ฐ๋ก ์ปดํฌ๋ํธ๋ก ๋นผ์ ๋ง๋ค์์ต๋๋ค.
const Box = () => {
const ref = useRef();
useFrame((state) => {
ref.current.rotation.x += 0.01;
ref.current.rotation.y += 0.01;
});
return (
<mesh ref={ref}>
<boxBufferGeometry />
<meshBasicMaterial color="blue" />
</mesh>
);
};Canvas์์๋ mesh๋ฅผ ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค. mesh๋ ์์ geometry, material ์์ฑ์ ๊ฐ์ ธ์ผ ํฉ๋๋ค. boxBufferGeometry, meshBasicMaterial๋ ๊ฐ๊ฐ presetting๋ ๊ธฐ๋ณธ ์์ geometry, ๊ธฐ๋ณธ material ์
๋๋ค.
mesh์ useRef๋ฅผ ์ฐ๊ฒฐํฉ๋๋ค. ๋งค ํ๋ ์๋ง๋ค ๋์ํ๋ useFrame ํ
์์ ref๋ฅผ ์กฐ์ํด mesh๋ฅผ ํ์ ์ํต๋๋ค.
import { Canvas, useFrame } from "@react-three/fiber";
import { useRef } from "react";
const Box = () => {
const ref = useRef();
useFrame((state) => {
ref.current.rotation.x += 0.01;
ref.current.rotation.y += 0.01;
});
return (
<mesh ref={ref}>
<boxBufferGeometry />
<meshBasicMaterial color="blue" />
</mesh>
);
};
function App() {
return (
<div style={{ width: "100vw", height: "100vh" }}>
<Canvas style={{ background: "black" }}>
<Box />
</Canvas>
</div>
);
}
export default App;๊ธฐ๋ณธ three.js๋ง ์ฌ์ฉํด์ scene์ ๋ง๋ค ๋๋ณด๋ค ์ฝ๋๊ฐ ํจ์ฌ ์งง๊ณ ๊ฐ๋จํด์ง ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ดํ ๋ด์ฉ๋ค์ ์ ๋ถ @react-three/fiber๋ฅผ ํ์ฉํ ์ฝ๋์
๋๋ค.

canvas์์ axesHelper๋ฅผ ์ถ๊ฐํด์ฃผ๋ฉด ๋ฉ๋๋ค.
<Canvas style={{ background: "black" }} camera={{ position: [3, 3, 3] }}>
<Box />
<axesHelper args={[5]} />
</Canvas>camera={{ position: [3, 3, 3] }} ๊ธฐ์กด ์นด๋ฉ๋ผ ์์น๊ฐ [0,0,5]์ฌ์ x, y์ถ ๋ฐ์ ์๋ณด์ด๊ธฐ ๋๋ฌธ์ ์นด๋ฉ๋ผ์ ์์น๋ฅผ ๋ฐ๊ฟ์ฃผ์์ต๋๋ค
axesHelper์ args๋ ์ฌ์ด์ฆ๋ฅผ ๋ํ๋
๋๋ค.
Orbit Controls๋ ์นด๋ฉ๋ผ(ํ๋ฉด)์ ๊ฐ๋๋ฅผ ๋๋ฆฌ๊ฑฐ๋ ํ๋ํ๊ฑฐ๋ ์ด๋ํ ์ ์๋ ์ปจํธ๋กค๋ฌ ์ ๋๋ค.
- ํ์ : ์ขํด๋ฆญ ํ ๋๋๊ทธ
- ํ๋/์ถ์ : ์คํฌ๋กค
- ์ด๋ : ์ฐํฌ๋ฆญ ํ ๋๋๊ทธ
import { Canvas, useFrame, extend, useThree } from "@react-three/fiber";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
extend({ OrbitControls });Orbit Controls๋ฅผ jsx ํํ๋ก ์ฌ์ฉํ๋ ค๋ฉด three.js์์ import ํ ๋ค react-three/fiber๋ก extendํด์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
const Orbit = () => {
const { camera, gl } = useThree();
return <orbitControls args={[camera, gl.domElement]} />;
};orbitControls ์์ฑ์๋ camera๊ฐ์ฒด์ ์ด๋ฒคํธ ๋ฆฌ์ค๋์ ์ฌ์ฉ๋๋ HTML ์๋ฆฌ๋จผํธ๊ฐ ํ์ํฉ๋๋ค. ์ฐ๋ฆฌ๋ react-three/fiber์์ ์ ๊ณตํ๋ useThree()๋ฅผ ๊ฐ์ฒด ๊ตฌ์กฐ ๋ถํดํด์ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
<Canvas style={{ background: "black" }} camera={{ position: [3, 3, 3] }}>
<Box />
<axesHelper args={[5]} />
<Orbit />
</Canvas>์ง๊ธ์ ๋น์ด ์๋ ์ํ์ง๋ง ํ๋ทฐ๊ฐ ์ ๋ณด์
๋๋ค. ๊ทธ ์ด์ ๋ meshBasicMaterial์ ๋น์ ์ํฅ์ ๋ฐ์ง ์๋ material์ด๊ธฐ ๋๋ฌธ์ ๊ทธ ์์ฒด์ ์์ ๋ด๊ณ ์๋ ๊ฒ์
๋๋ค. ๋น์ ์ํฅ์ ๋ฐ๋ material์ ์ ์ฉ์์ผ ๋ณด๊ฒ ์ต๋๋ค.
<mesh ref={ref} {...props}>
<boxBufferGeometry />
<meshPhysicalMaterial color="blue" />
</mesh>meshBasicMaterial๋์ meshPhysicalMaterial์ ์ฌ์ฉํ๋ ๋์ด์ ํ๋ธ๊ฐ ๋ณด์ด์ง ์์ต๋๋ค. ์ด์ ๋น์ ์ถ๊ฐํด๋ด
์๋ค.
ambientLight๋ ๋ชจ๋ mesh๊ฐ ๋ชจ๋ ๊ฐ๋์์ ๋์ผํ ์์ ๋ฐ๊ฒํ๋ ๋น์
๋๋ค. ๋น์ฐํ ๊ทธ๋ฆผ์๋ ์๊ธฐ์ง ์์ต๋๋ค.
<ambientLight intensity={0.2} />canvas์์ ์ถ๊ฐํด ์ค์๋ค. intensity๋ก ๋น์ ์ธ๊ธฐ๋ฅผ ์ ํ ์ ์์ต๋๋ค.
pointLight๋ ํ ์ ์์ ๋์ค๋ ๋น์
๋๋ค. ๊ฑฐ๋ฆฌ์ ๋ฐ๋ผ ๋น์ ์์ด ์ค์ด๋ค๊ณ ๊ฐ๋์ ๋ฐ๋ผ ๋น์ ๋ฐ์ง ๋ชปํ ์ ์๋ ํํ ์ฐ๋ฆฌ๊ฐ ์๋ ๋น์
๋๋ค. ๋ค๋ง ๋น ์์ฒด๋ ๊ด์ธก๋์ง ์๊ณ ๋น์ ๋ฐ๋ mesh๋ค์๊ฒ ์ํฅ์ ์ค ๋ฟ์
๋๋ค.
<pointLight />canvas์์ ์ถ๊ฐํด ์ค์๋ค.

์ง๊ธ๊น์ง๋ ๋น ์์ฒด๋ ๊ด์ธกํ ์ ์์์ต๋๋ค. ํ์ง๋ง ์ค์ ์ธ์์์๋ ํ์๊ณผ ๊ฐ์ด ๋น์ ๋ถ์ถํ๋ ์ค๋ธ์ ํธ๊ฐ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ meshPhongMaterial์์ pointLight๋ฅผ ๋ฃ์์ผ๋ก์จ ํ์ ๋น์ทํ mesh๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
meshPhongMaterial์ ๋น์ ๋ฐ์ฌ์์ผ ํ๋ฉด์ด ๋น๋๋ material์
๋๋ค.
const Sun = (props) => {
return (
<mesh {...props}>
<pointLight castShadow />
<sphereBufferGeometry args={[0.3]} />
<meshPhongMaterial emissive="yellow" />
</mesh>
);
};๊ทธ๋์์ ๊ณ์ boxBufferGeometry๋ฅผ ์ฌ์ฉํ๋๋ฐ ๊ตฌ๋ฅผ ๋ง๋ค๊ธฐ ์ํด์ sphereBufferGeometry๋ฅผ ์ฌ์ฉํ์ต๋๋ค. args๋ ๋ฐ์ง๋ฆ์ ๊ธธ์ด ์
๋๋ค.
meshPhongMaterial์์ emissive๋ก ๋น์ด ๋ฐ์ฌ๋๋ ์์ ์ ํ ์ ์์ต๋๋ค.
<Sun position={[0, 3, 0]} />๋ถ๋ช ๋ฐฉํฅ์ ๊ฑฐ๋ฆฌ๊ฐ ์ ํจํ ๋น์ ๋ง๋ค์๋๋ฐ ๊ทธ๋ฆผ์๊ฐ ์๊ธฐ์ง ์์ต๋๋ค. ๊ทธ๋ฆผ์๋ฅผ ๋ง๋ค๋ ค๋ฉด ์ถ๊ฐ์ ์ธ ์ค์ ์ด ํ์ํฉ๋๋ค.
Canvas์ shadows์์ฑ์ ์ถ๊ฐํ๋ฉด ๊ทธ๋ฆผ์๋ฅผ ๊ทธ๋ฆด ์ ์๋ Canvas๊ฐ ๋ฉ๋๋ค.
<Canvas
shadows
style={{ background: "black" }}
camera={{ position: [3, 3, 3] }}
>
Sun์ ๊ทธ๋ฆผ์๋ฅผ ๊ทธ๋ฆฌ๋ ์ค๋ธ์ ํธ์ด๊ณ ๋ฐ๋ฅ์ธ Floor๋ ๊ทธ๋ฆผ์๊ฐ ๊ทธ๋ ค์ง๋ ์ค๋ธ์ ํธ ์
๋๋ค.
๊ฐ๊ฐ castShadow ์ receiveShadow๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
const Sun = (props) => {
return (
<mesh {...props}>
<pointLight castShadow />
...const Floor = (props) => {
return (
<mesh {...props} receiveShadow>
...Box๋ ์ด๋จ๊น์? Box๋ ๊ทธ๋ฆผ์๋ฅผ Floor์ ๊ทธ๋ฆฌ๊ธฐ๋ ํ์ง๋ง Sun์ด ๋ง๋๋ ๊ทธ๋ฆผ์๋ฅผ ์์ ์๊ฒ ๊ทธ๋ฆฌ๊ธฐ๋ ํฉ๋๋ค. castShadow ์ receiveShadow ๋๋ค ์ถ๊ฐํด์ค๋๋ค.
const Box = (props) => {
...
return (
<mesh ref={ref} {...props} castShadow receiveShadow>
...meshMaterial์์ ๋ช๊ฐ์ง ์์ฃผ ์ฌ์ฉํ๋ ์์ฑ๋ค์ ํ์ด๋ณด๋ ค๊ณ ํฉ๋๋ค.
opacity๋ ๋ถํฌ๋ช
๋์
๋๋ค. 1์ด๋ฉด ์์ ํ ๋ถํฌ๋ช
์ด๊ณ 0์ด๋ฉด ์์ ํ ํฌ๋ช
์
๋๋ค. ํ์ง๋ง opacity๋ง์ผ๋ก๋ mesh๊ฐ ์ค์ ๋ก ํฌ๋ช
ํด์ง์ง ์์ต๋๋ค. transparent ์์ฑ์ด true์ผ ๋๋ง opacity์์ฑ์ด ์๋ํฉ๋๋ค. material ์์ฑ์ ์ ํ์ธํ๊ธฐ ์ํด์ ํ๋ธ์ ์์น๋ฅผ ๋ณ๊ฒฝํ์์ต๋๋ค.
<meshPhysicalMaterial
color="blue"
opacity={0.3}
transparent
/>mesh์ ํ๋ ์๋ง ๋์ค๊ฒ ํ๋ ์์ฑ์
๋๋ค. ํ๋ ์์ ์์ color์์ฑ์ผ๋ก ์ ์ฉ๋ฉ๋๋ค.
<meshPhysicalMaterial
color="blue"
opacity={0.3}
transparent
wireframe
/>metalness๋ ๊ธ์ ์ฌ์ง์ ๋ง๋ค์ด ์ฃผ๊ณ 1์ด๋ฉด ์์ ํ ๊ธ์์
๋๋ค. roughness๋ ํ๋ฉด์ ๊ฑฐ์น ๊ธฐ๋ฅผ ๋ปํ๊ณ 0์ด๋ฉด ๋น์ ๊ทธ๋๋ก ๋ฐ์ฌํฉ๋๋ค. metalness์ default ๋ 0, roughness๋ 1์
๋๋ค.
<meshPhysicalMaterial
color="blue"
metalness={1}
roughness={0}
/>
roughness๊ฐ 0์ด๊ธฐ ๋๋ฌธ์ ํ๋ฉด์์ ํ์ ์ผ๋ก ๋น์ ๊ทธ๋๋ก ๋ฐ์ฌํ๋ ๊ฒ์ด ๋ณด์
๋๋ค.
๋ ๋ง์ ์์ฑ๋ค์ https://threejs.org/docs/index.html?q=mater#api/en/materials/Material ์์ ์ถ๊ฐ๋ก ํ์ธํ์ค ์ ์์ต๋๋ค.
ํ
์ค์ณ๋ฅผ ์ ์ฉ์ํค๋ ๋ฒ๋ ๊ฐ๋จํฉ๋๋ค. ๋จผ์ ํ
์ค์ณ ์ฌ์ง์ ์ค๋นํด์ ์์
ํด๋์ ๋ฃ์ด์ค๋๋ค.
const Box = (props) => {
...
const texture = useLoader(THREE.TextureLoader, "/assets/wood.jpg");
...
return (
<mesh ref={ref} {...props} castShadow>
<boxBufferGeometry />
<meshPhysicalMaterial map={texture} />
</mesh>
);
};@react-three/fiber์ ํ
useLoader๋ก ์ด๋ฏธ์ง๋ฅผ ํ์ฉํด ํ
์ค์ณ๋ฅผ ๋ง๋ญ๋๋ค. meshMaterial์ map ์์ฑ์ผ๋ก ํ
์ค์ณ๋ฅผ ์ ์ฉ์ํต๋๋ค.
ํ์ง๋ง ์ด ์ํ๋ฉด texture๊ฐ ๋ก๋ฉ๋๊ธฐ ์ ์ ํ๋ฉด์ด ๋ ๋๋ง๋๊ธฐ ๋๋ฌธ์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. <Suspense>์์ Box๋ฅผ ๋ฃ์ด texture ๋ก๋ฉ์ด ์๋ฃ๋๋ฉด ๋ณด์ฌ์ฃผ๊ธฐ๋ก ํฉ์๋ค. Suspense๋ ๋ฆฌ์กํธ์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์
๋๋ค.
<Canvas
shadows
style={{ background: "black" }}
camera={{ position: [3, 3, 3] }}>
<Suspense fallback={null}>
<Box position={[0, 1, 0]} />
</Suspense>
...์ด๋ฒ์๋ ๋ฐฐ๊ฒฝ์ ํ ์ค์ณ๋ฅผ ๋ฃ์ด๋ณด๊ฒ ์ต๋๋ค. ๋ค๋ง 3d ๋ฐฐ๊ฒฝ์ ์ฌ์ฉํ๋ ค๋ฉด 360๋ ์ด๋ฏธ์ง(ํ๋๋ก๋ง)๊ฐ ํ์ํฉ๋๋ค.
https://cdn.pixabay.com/photo/2018/07/11/16/34/landscape-3531355_960_720.jpg ์ฌ์ฉํ ์ด๋ฏธ์ง
const BackGround = (props) => {
const texture = useLoader(THREE.TextureLoader, "/assets/back.jpg");
const { gl } = useThree();
const formatted = new THREE.WebGLCubeRenderTarget(
texture.image.height
).fromEquirectangularTexture(gl, texture);
return <primitive attach="background" object={formatted.texture} />;
};ํ
์ค์ณ๋ฅผ ๋ง๋๋๊ฑด ๊ธฐ์กด๊ณผ ๊ฐ์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ํ์ํ๊ธฐ ์ , ํ์ ์ฒ๋ฆฌ๋ฅผ ํ๋ WebGlRenderTarget์ ์ฌ์ฉํ ๊ฒ์
๋๋ค. WebGLCubeRenderTarget๋ ํ๋ธ ์นด๋ฉ๋ผ๋ก ์ดฌ์ํ 360๋ ์ด๋ฏธ์ง ์ฉ WebGlRenderTarget์
๋๋ค. ๊ทธ ์ค์์ fromEquirectangularTexture ๋ฉ์๋๋ ํ๋๋ก๋ง ์ด๋ฏธ์ง๋ฅผ 360๋ ํ๋ธ๋งต(3d ๋ฐฐ๊ฒฝ)์ผ๋ก ์ปจ๋ฒํ
ํด์ค๋๋ค.
<Suspense fallback={null}>
<BackGround />
</Suspense>BackGround๋ ํ
์ค์ณ ๋ก๋ฉ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ Suspense ์ฌ์ด์ ๊ปด์ Canvas์ ๋ฃ์ด์ค๋๋ค.







