three.js: js 3d modeling 라이브러리
공식 홈페이지에서 한글 설명을 지원하기 때문에 다른 공식문서에 보기 편했다. 시작전 한번 살펴보고 오자!
npm install three
yarn add three
나는 설치하지 않고 examples에서 필요한 파일을 뽑아썼다.
위 그림을 간단하게 설명하면
장면을 만듦 👉 그 안에 3D 오브젝트를 넣음 👉 카메라로 비추고 renderer를 통해 html 파일에서 보여줌
scene
camera
renderer
코딩 전 먼저 sketchfab에서 사용하고자 하는 이미지를 찾는다. 라이센스를 확인하는걸 잊지말자!
이미지를 찾았으면 GLTF형식으로 다운로드를 받아준다.
짧은 코드지만 html과 js 파일을 분리해서 작성했다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./style.css" />
<script type="module" src="./main.js"></script>
</head>
<body>
<canvas id="c" width="700" height="600"></canvas>
</body>
</html>
import * as THREE from "../../build/three.module.js";
import { GLTFLoader } from "../../build/GLTFLoader.js";
import { OrbitControls } from "../../build/OrbitControls.js";
const canvas = document.querySelector("#c");
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); // antialias: true --> 계단 현상 방지
// 색상 인코딩 방식
renderer.outputEncoding = THREE.sRGBEncoding;
// THREE.PerspectiveCamera: 원근법 적용
//THREE.OrthographicCamera: 원근법 적용 ㄴㄴ
const camera = new THREE.PerspectiveCamera(
30,
window.innerWidth / window.innerHeight,
1,
10000
);
// 마우스 컨트롤
const controls = new OrbitControls(camera, renderer.domElement);
camera.position.set(0, 20, 90);
controls.update();
// 조명
// 1. PointLight: A light that gets emitted from a single point in all directions
const PointLight = new THREE.PointLight(0xffffff, 1);
scene.add(PointLight);
// 2. DirectionalLight: A light that gets emitted in a specific direction
const DirectionalLight = new THREE.DirectionalLight(0xffffff, 1);
scene.add(DirectionalLight);
// 3. AmbientLight: A light globally illuminates all objects in the scene equally
const AmbientLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(AmbientLight);
const loader = new GLTFLoader();
// gltf 파일 사용
loader.load("viking_room/scene.gltf", function (gltf) {
scene.add(gltf.scene);
renderer.render(scene, camera);
// 애니메이션
function animate() {
requestAnimationFrame(animate); // 초당 60번 실행
gltf.scene.rotation.y += 0.005; // y 축 회전
controls.update();
renderer.render(scene, camera);
}
animate();
});
위 코드의 renderer 부분으로 보면 WebGLRenderer라는 함수가 보인다
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer는 알겠는데 그럼 WebGL은 뭐지?
WebGL: Web Graphics Library
- 웹에서 2D 및 3D를 렌더링하기위한 JavaScript API
- OpenGL ES 2.0 기반으로 HTML5의 canvas 위에 그려짐
찾아보니까 장점이 많이 나오긴 하는데 솔직히 이해 못했다 ㅎㅎ
다음에 또 공부해서 기록해 두어야겠다
npm install @react-three/fiber
yarn add @react-three/fiber
.
├── App.tsx
├── components
│ └── Room.tsx
├── index.css
└── index.tsx
App.tsx
import { Canvas } from "@react-three/fiber";
import React from "react";
import Room from "./components/Room";
const color = 0xffffff;
const intensity = 1;
function App() {
return (
<Canvas
camera={{
fov: 30,
near: 1,
aspect: window.innerWidth / window.innerHeight,
far: 1000,
position: [0, 20, 90],
}}
>
<pointLight color={color} intensity={intensity} />
<directionalLight color={color} intensity={intensity} />
<ambientLight color={color} intensity={intensity} />
<Room />
</Canvas>
);
}
export default App;
Room.tsx
import React, { useRef, Suspense } from "react";
import * as THREE from "three";
import { useFrame } from "@react-three/fiber";
import { OrbitControls, useGLTF } from "@react-three/drei";
// npx gltfjsx scene.gltf로 생성(아래 링크 유튭 참조!)
function Model(props: any) {
const { nodes, materials }: any = useGLTF("/scene.gltf"); // 동작만 확인했기 때문에 일단 any로 둠
return (
<group {...props} dispose={null}>
<group rotation={[-Math.PI / 2, 0, 0]}>
<group rotation={[Math.PI / 2, 0, 0]}>
<mesh
geometry={nodes.mesh_all1_Texture1_0.geometry}
material={materials.Texture1}
/>
</group>
</group>
</group>
);
}
function Room() {
const object3d = useRef<THREE.Object3D>(null!);
useFrame((state, delta) => (object3d.current.rotation.y += 0.005));
return (
// object3D: 빈 지역 공간
<object3D ref={object3d}>
<OrbitControls />
<Suspense fallback={null}>
<Model />
</Suspense>
</object3D>
);
}
export default Room;
변환 자체는 react-three-fiber가 거의 다 해줘서 간단한데 GLTF 파일 경로때문에 몇시간을 삽질했다ㅠ
threeJS 아직은 잘 모르지만 신기하고 재미있었다! 이제 틈틈히 취미삼아 해봐야겠다 😎
참조
threejs 공식문서
코딩애플 - 웹 포트폴리오에 간지나게 3D 모델을 추가해보자(threeJS)
유튜브: https://www.youtube.com/watch?v=2jwqotdQmdQ&t=1476s
사진 출처: https://designbase.co.kr/threejs-03/