Three.js 기본세팅
import { mode } from "mathjs";
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.setPixelRatio(window.devicePixelRatio); //현재 디바이스의 픽셀 비율 설정 -> 더 선명한 이미지
renderer.setSize(window.innerWidth, window.innerHeight);
const camera = new THREE.PerspectiveCamera(35, window.innerWidth/window.innerHeight);
const scene = new THREE.Scene();
scene.background= new THREE.Color("#5ddaa2");
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x000000, 1);
scene.add(hemiLight);
const loader = new GLTFLoader();
loader.load("/gltf/scene/scene-2.glb", gltf => {
const model = gltf.scene;
scene.add(model);
camera.position.copy(gltf.cameras[0].position);
const controls = new OrbitControls(camera, canvas);
controls.enableDamping = true;
//물체가 위에 있음 ->control의 target지점이 아래쪽에 있음 -> 카메라의 정면을 바라보게 하기 -> controls.target 치 변경
controls.target.set(0, camera.position.y, 0);
controls.update();
render();
})
function render() {
requestAnimationFrame(render);
renderer.render(scene,camera)
}
렌더링 결과 -> 검정색으로 나옴
Material의 metalness 변경하기
model.traverse(child =>{
if(child.isMesh){
child.material.metalness = 0;
}
})
로켓과 배경색 제외하고 전부 Lighting 영향 받지 않게하기 & tonemapping
model.traverse(child =>{
if(child.isMesh){
child.material.metalness = 0;
console.log(child.name);
if(child.name == "colorize" || child.name == "theme"){
} else {
child.material = new THREE.MeshBasicMaterial({
map: child.material.map, //조명(hemisLight)의 영향을 받지 않고 본연의 색만 나타냄.
})
}
}
})
const renderer = new THREE.WebGLRenderer({canvas:canvas, antialias:true});
renderer.setPixelRatio(window.devicePixelRatio); //현재 디바이스의 픽셀 비율 설정 -> 더 선명한 이미지
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.outputEncoding = THREE.sRGBEncoding; //모델링 색보정 -> Contrast가 강한 렌더링 방식에서 밝게 만들어줌
renderer.toneMapping = THREE.ReinhardToneMapping;
renderer.toneMappingExposure = 3; //밝게하기
모델링 되었을 때 처음 Scene 조정하기 using GUI
- 로켓의 색상과 팔레트의 색상 일치시키기 -> 색상 수집하기 by GUI
- day와 night object 중 하나 비활성화
- color 팔레트 생성하기
const gui = new GUI(); //우측 상단에 close controls 생성 -> control에 로켓의 색상과 테마의 색상 등록하기
const colors = {
white: 0xffffff,
blue: 0x11ff,
green: 0x13c200,
brown: 0xff2d00,
};
scene.getObjectByName("night").visible=false; //비활성
scene.getObjectByName("colorize").material.color.set(0xff2d00); //0x11ff -> 처음 Scene 조정
scene.getObjectByName("theme").material.color.set(0x13c200);
const color = {
color: 0xffffff,
};
// gui.addColor(scene.getObjectByName("colorize").material, "color"); //컬러 팔레트 생성(addColor), 색상 조정 가능
gui.addColor(color, "color").onChange((color) => {
scene.getObjectByName("colorize").material.color.set(color) //색상을 바꿀때마다 로켓색상도 같이 바뀜
});
클릭에 따라서 애니메이션 플레이시키기 using AnimationMixer
AnimationMixer : Three.js에서 애니메이션을 효과적으로 다룰 수 있도록 도와주는 클래스, 다음과 같은 기능을 제공함
- 애니메이션 트랙(Animation Tracks) 관리 - Mixer를 통해 애니메이션 트랙을 관리하고 여러 트랙을 조합할 수 있음. 각 트랙은 모델의 특정 속성(위치, 회전, 스케일, 뼈, 등)에 대한 애니메이션을 나타냄
- 애니메이션 블렌딩(Blending) - 애니메이션을 부드럽게 블렌딩하여 자연스러운 전환 효과를 생성함
- 애니메이션 업데이트 - 현재 프레임에 해당하는 애니메이션 상태를 업데이트
- 애니메이션 제어 - 애니메이션의 재생, 일시정지, 정지 등을 제어할 수 있음
1. 모델링의 이름에 따라서 애니메이션 나누기
//animation play
mixer = new THREE.AnimationMixer(gltf.scene);
// console.log(gltf.animations[0]) //tracks 내에 13개의 Track이 존재함 -> track 가져오기
const tracks = gltf.animations[0].tracks;
const animations = {}; //track을 가져와서 animations에 넣을거임
//track을 clip으로 바꿔주기
tracks.forEach((track)=>{
const name = track.name.split(".")[0];
if(!animations[name]){
animations[name] = [];
}
animations[name].push(track); //모델의 이름에 맞춰서 해당 애니메이션 KeyframeTrack들이 들어감
});
const clips = [];
Object.entries(animations).forEach(animation =>{
//Key 이름과 값을 분리하기
const name = animation[0];
const track = animation[1];
const clip = new THREE.AnimationClip(name, -1, track ) //duration은 무한인 새로운 clip 생성
clips.push(clip); //AnimtaionClip들이 모델링의 이름에 맞춰서 들어감
})
// console.log(clips)
gltf.animations = clips;
2. click 인터랙션에 따라 해당 Object의 애니메이션 플레이시키 using raycaster
addEventListener("click", (event) => {
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2()
mouse.x = (event.clientX / window.innerWidth - 0.5) * 2;
mouse.y = (event.clientY / window.innerHeight - 0.5) * -2;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(gltf.scene.children, true);
if(intersects.length > 0){
const name = intersects[0].object.name;
// console.log(name)//클릭했을 때 해당 object의 이름을 출력
playAnimation(name); //클릭시 해당 애니메이션 플레
}
})
function playAnimation(name) {
const clip = gltf.animations.find((animation ) => {
return animation.name === name;
})
if(clip) {
const action = mixer.clipAction(clip);
action.stop();
action.loop = THREE.LoopOnce;
action.clampWhenFinished = true;
action.play();
}
}
window.playAnimation = playAnimation; //console창에서 playAnimation 실행 가능
const clock = new THREE.Clock();
function render() {
requestAnimationFrame(render);
renderer.render(scene,camera)
mixer.update(clock.getDelta())
}
3. 화살표 버튼 클릭시 테마의 색상과 배경 색상 바꾸기
if(intersects.length > 0){
const name = intersects[0].object.name;
// console.log(name)//클릭했을 때 해당 object의 이름을 출력
playAnimation(name);
//팔레트 색상 선택시 로켓 색상 변경
if (name === "color_2") {
scene.getObjectByName("colorize").material.color.set(colors.white);
}
if (name === "color_3") {
scene.getObjectByName("colorize").material.color.set(colors.brown);
}
if (name === "color") {
scene.getObjectByName("colorize").material.color.set(colors.green);
}
if (name === "color_1") {
scene.getObjectByName("colorize").material.color.set(colors.blue);
}
//화살표 클릭세 테마 변경하기
if(name === "button_left" || name === "button_right") {
// if(isDay){
// isDay = false;
// } else {
// isDay = true;
// }
isDay = !isDay; //토글기능
if(isDay){
scene.getObjectByName("day").visible = true;
scene.getObjectByName("night").visible = false;
scene.getObjectByName("theme").material.color.set(colors.green);
} else {
scene.getObjectByName("day").visible = false;
scene.getObjectByName("night").visible = true;
scene.getObjectByName("theme").material.color.set(colors.blue);
}
}
'3D Project > 3D 인터랙티브 웹' 카테고리의 다른 글
3D Animation scroll Web (0) | 2025.01.19 |
---|---|
[3D 인터랙티브 웹] 3D Scene - 1(클릭 인터랙션) 렌더링 (1) | 2024.01.14 |
[3D 인터랙티브 웹] 파티클 시스템/애니메이션 만들기 by Three.js (1) | 2024.01.14 |
[3D 인터랙티브 웹] 스크롤 인터랙션/애니메이션 적용하기 (1) | 2024.01.14 |
[3D 인터랙티브 웹] Three.js에서 회전 애니메이션 적용시키기 - 3D 시계 모델링 (0) | 2024.01.14 |