기본 Three.js 세팅
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const renderer = new THREE.WebGLRenderer({canvas:canvas, antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
//THREE.PerspectiveCamera의 생성자는 두개의 인자를 받음
//-> 1. 시야각(FOV) 2. 카메라의 비율(Aspect Ratio) -> 일반적으로 창의 크기에 따라 동적으로 조절됨
const camera = new THREE.PerspectiveCamera(35, window.innerWidth/window.innerHeight);
const scene = new THREE.Scene();
scene.background = new THREE.Color("hsl(255, 50%, 40%)")
const loader = new GLTFLoader();
loader.load("/gltf/scene/scene-1.glb", (gltf) => {
scene.add(gltf.scene);
render();
})
//화면 렌더링 -> 매 프레임마다 화면을 갱신하고 업데이트
function render () {
requestAnimationFrame(render); //애니메이션 프레임 요청, 브라우저에게 현재 화면의 업데이트 주기에 맞춰 다음 프레임을 그려달라고 요청
renderer.render(scene, camera) //Three.js의 렌더러를 사용하여 3D 장면을 카메라의 시점에서 렌더링함
}
카메라의 정보를 Cinema 4D에서 작업한 camera와 연동하기
const loader = new GLTFLoader();
loader.load("/gltf/scene/scene-1.glb", (gltf) => {
scene.add(gltf.scene);
//Cinema 4D에서 작업한 첫 번째 Main camera의 위치값과 회전값 연동 by copy method
camera.position.copy(gltf.cameras[0].position);
camera.rotation.copy(gltf.cameras[0].rotation)
}
결과 -> 검은색으로 나타남
원인
- Material -> metalness 확인하기, 1인 경우에 주변 배경이 기본적으로 환경 맵이 검정색으로 설정되어 있어서 검은색을 전체 반사 시켜서 물체의 고유색이 나타나지 않음
- 주변 조명 세팅이 없어서
//traverse method를 사용해서 scene 안에 있는 모든 Obejct들 Mesh Object들만 불러오기
gltf.scene.traverse(child => {
if(child.isMesh){
console.log(child.material) //모든 Mesh Object에 붙어있는 Material의 목록을 볼 수 있음
child.material.metalness = 0;
}
}) -> 원인 1 해결
const ambientLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(ambientLight); ->원인2 해결
결과 -> 모델링 성공. 그러나 Contrast가 굉장히 진하고 채도가 높게 모델링 되었음 -> renderer의 설정을 통해 조정
모델링 색보정 by renderer + orbitControl 설정
const renderer = new THREE.WebGLRenderer({canvas:canvas, antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.outputEncoding = THREE.sRGBEncoding; //모델링 색보정 -> Contrast가 강한 렌더링 방식에서 밝게 만들어줌
renderer.toneMapping = THREE.ReinhardToneMapping; //화면 위에 다른 색상 교정 filter를 씌움, Contrast도 낮아지고 밝기도 낮아짐
renderer.toneMappingExposure = 4; //밝게하기
//Orbitcontrol -> 현재 카메라의 위치를 기반으로 조정됨, 따라서 최근에 위치와 회전값이 조정된 상태에서 orbitControl 설정하기
controls = new OrbitControls(camera, canvas);
Cinema 4D에서 설정해줬던 애니메이션 플레이시키기 by mixer, action
mixer = new THREE.AnimationMixer(gltf.scene);
action = mixer.clipAction(gltf.animations[0]) //animation 1개 만듦. 따라서 1개만 actino에 적용하기
action.play();
const clock = new THREE.Clock();
//화면 렌더링 -> 매 프레임마다 화면을 갱신하고 업데이트
function render () {
requestAnimationFrame(render); //애니메이션 프레임 요청, 브라우저에게 현재 화면의 업데이트 주기에 맞춰 다음 프레임을 그려달라고 요청
renderer.render(scene, camera) //Three.js의 렌더러를 사용하여 3D 장면을 카메라의 시점에서 렌더링함
mixer.update(clock.getDelta);
}
클릭했을 때, 애니메이션 플레이 시키기 -> 클릭 인터랙션 부여 by addEventListener
- 처음 로드 되었을 때 애니메이션 시간 0초로 고정시키기
- 조건문을 통해 mixer.update를 조정하기
- 클릭시 play가 true로 되게끔 addEventListener 부여하기
mixer = new THREE.AnimationMixer(gltf.scene);
action = mixer.clipAction(gltf.animations[0]) //animation 1개 만듦. 따라서 1개만 actino에 적용하기
action.loop = THREE.LoopOnce;
action.play();
action.time=0; //animtaion time은 0으로 고정
mixer.update(0); //mixer의 update를 0으로 만들어 줌으로써 시간이 흐르지 앟게끔 고정 -> 1번
//조건문을 통해 바로 Animation이 실행되지 않도록하기 -> 2번
if(play == true) mixer.update(clock.getDelta())
//3
addEventListener("click", (event) => {
play = true;
})
플레이 버튼을 클릭했을 때만 애니메이션 실행시키기 -> RayCaster : three.js에서 클릭을 통해서 Object와 소통할 수 있는 방법
- raycaster 선언
- mouse x,y의 좌표를 -1~1로 변환하기
- raycaster와 mouse 좌표 연동하기
- click할때마다 애니메이션 실행시키
addEventListener("click", (event) => {
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
mouse.x = (event.clientX/window.innerWidth - 0.5) *2; //x는 0~1 -> -1~1, threejs에서는 좌표를 인식할 때 정가운데가 원점(0,0)임
mouse.y = -1*((event.clientY/window.innerHeight - 0.5) *2);
raycaster.setFromCamera(mouse, camera);
//해당 광선과 겹치는 모든 mesh 목록 받아오기
const intersects = raycaster.intersectObjects(gltf.scene.children, true);
// console.log(intersects)
//button name: play_171
if(intersects.length > 0 && intersects[0].object.name === "play_171"){
play = true;
action.reset(); //클릭할 때마다 애니메이션 플레이시키기
}
})
+ 창을 늘리고 줄일때마다 canvas 크기 변하게 하기
addEventListener("resize", (event) =>{
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
})
3D Scene 모델링 결과
'3D Project > 3D 인터랙티브 웹' 카테고리의 다른 글
3D Animation scroll Web (0) | 2025.01.19 |
---|---|
[3D 인터랙티브 웹] 3D Scene - 2 렌더링 (1) | 2024.01.15 |
[3D 인터랙티브 웹] 파티클 시스템/애니메이션 만들기 by Three.js (1) | 2024.01.14 |
[3D 인터랙티브 웹] 스크롤 인터랙션/애니메이션 적용하기 (1) | 2024.01.14 |
[3D 인터랙티브 웹] Three.js에서 회전 애니메이션 적용시키기 - 3D 시계 모델링 (0) | 2024.01.14 |