마우스 이벤트 추가
const mouse = new THREE.Vector2();
/* 이벤트 */
window.addEventListener("resize", setSize);
canvas.addEventListener("click", (e) => {
console.log("📢 [ex02_eventClick.js:85]", e);
});
// 이벤트 콘솔 결과
PointerEvent {
clientX: 300,
clientY : 200
}
마우스로 클릭한 위치 표시 - clientX, clientY
threejs에 맞게 좌표를 변환해야 한다.
/* 2D 화면상의 마우스 위치 만들기 */
const mouse = new THREE.Vector2();
/* 이벤트 */
window.addEventListener("resize", setSize);
canvas.addEventListener("click", (e) => {
console.log("📢 [ex02_eventClick.js:85]", e);
// threejs에 맞게 3차원 좌표로 변환
// 실제 클릭한 좌표의 위치 : e.clientX, e.clientY
mouse.x = (e.clientX / canvas.clientWidth) * 2 - 1;
mouse.y = -((e.clientY / canvas.clientHeight) * 2 - 1);
console.log("📢 [ex02_eventClick.js:89]", mouse);
- Three.js에서 화면상의 2D 좌표 (clientX, clientY)를 WebGL의 3D 공간에 맞는 좌표로 변환해야 한다.
- ThreeJS는 가운데가 0이어야 한다.
- e.clientX는 클릭한 위치의 좌표이다.
3차원 좌표로 변환하는 계산법
- X좌표 변환:
- e.clientX는 클릭한 위치의 X 좌표이다.
- canvas.clientWidth는 캔버스의 가로길이이다.
- (e.clientX / canvas.clientWidth)는 클릭한 위치가 화면에서 차지하는 비율을 구한다.
- 값은 0에서 1 사이이다.
- * 2 - 1을 통해 비율을 1에서 1 범위로 변환한다.
- mouse.x = (e.clientX / canvas.clientWidth) * 2 - 1;
- Y좌표 변환:
- e.clientY는 클릭한 위치의 Y 좌표이다.
- canvas.clientHeight는 캔버스의 세로 길이이다.
- (e.clientY / canvas.clientHeight)는 클릭 위치의 비율을 구한다.
- * 2 - 1로 NDC의 범위에 맞춘 후 -를 붙여 Y축 방향을 반전한다.
- mouse.y = **-**((e.clientY / canvas.clientHeight) * 2 - 1);
- 전체 길이를 두 배로 늘려서 -1에서 1 사이의 값으로 만드는 과정
- 0에서 1 사이 값
- 클릭 위치 비율이 0일 때는 0이고, 1일 때는 1이다.
- 두 배로 확장
- 여기에 * 2를 하면,
- 0은 여전히 0 * 2 = 0.
- 1은 1 * 2 = 2로 2배로 늘어난다.
- 범위 이동
- 이 값을 - 1을 해주어 -1에서 1 사이로 이동시킨다.
- 0은 0 * 2 - 1 = -1로 변환된다.
- 0.5는 0.5 * 2 - 1 = 0으로 변환된다.
- 1은 1 * 2 - 1 = 1로 변환된다.
- 이렇게 함으로써, 화면상의 0~1 비율이 NDC 좌표계의 -1~1 범위로 매핑되게 된다.
- 0에서 1 사이 값
마우스가 클릭되면 광선 위치 카메라 시점으로 세팅하기
/* 광선 만들기 */
const raycaster = new THREE.Raycaster();
function checkIntersects() {
// 카메라와 마우스 위치를 사용해 Raycaster 업데이트
raycaster.setFromCamera(mouse, camera);
// 마우스 위치와 교차하는 객체 확인
const intersects = raycaster.intersectObjects(meshes);
for (const item of intersects) {
console.log(item.object.name);
}
}
/* 이벤트 */
window.addEventListener("resize", setSize);
canvas.addEventListener("click", (e) => {
// threejs에 맞게 3차원 좌표로 변환
mouse.x = (e.clientX / canvas.clientWidth) * 2 - 1; // 실제 클릭한 X의 위치 : e.clientX
mouse.y = -((e.clientY / canvas.clientHeight) * 2 - 1); // 실제 클릭한 Y의 위치 : e.clientY
checkIntersects();
});
- setFromCamera
- Three.js의 Raycaster 클래스에서 사용되는 메서드이다.
- 2D 화면상의 마우스 위치를 3D 공간의 광선(Ray)으로 변환하는 데 사용한다.
- Raycaster의 방향과 시작 위치를 카메라를 기준으로 설정한다.
- 이때 mouse 위치를 기준으로 화면을 향하는 3D 광선이 생성된다.
- 자동으로 카메라 위치를 origin으로 잡아서 마우스 클릭한 지점으로 광선이 세팅된다.
클릭한 물체 색상 변경
function checkIntersects() {
// 카메라와 마우스 위치를 사용해 Raycaster 업데이트
raycaster.setFromCamera(mouse, camera);
// 마우스 위치와 교차하는 객체 확인
const intersects = raycaster.intersectObjects(meshes);
for (const item of intersects) {
console.log(item.object.name);
// 광선이 관통하면 색상이 변경되도록 설정
item.object.material.color.set("red");
break; // 첫 번째 물체만 작동하기 위해 break 작동시킴
}
}
- for ... of 사용해 원소를 돌면서 아이템이라는 이름으로 세팅하기
- 물체를 관통을 하기 때문에 클릭 시 두 물체가 있으면 다 잡힌다.
- 처음 잡힌 물체만 선택되길 원한다면 break를 추가해 주면 된다.
재클릭해 원래 색상으로 변경
// 객체 초기화 시 원래 색상을 저장
for (const mesh of meshes) {
mesh.originalColor = mesh.material.color.clone();
}
function checkIntersects() {
// 카메라와 마우스 위치를 사용해 Raycaster 업데이트
raycaster.setFromCamera(mouse, camera);
// 마우스 위치와 교차하는 객체 확인
const intersects = raycaster.intersectObjects(meshes);
for (const item of intersects) {
// 색상이 이미 빨간색인지 확인
if (item.object.material.color.equals(new THREE.Color("red"))) {
// 빨간색이면 원래 색상으로 변경
item.object.material.color.copy(item.object.originalColor);
} else {
// 원래 색상이면 빨간색으로 변경
item.object.material.color.set("red");
}
break; // 첫 번째 교차한 객체만 처리
}
}
'Frontend > Three.js' 카테고리의 다른 글
Raycaster, 특정 방향의 광선(Ray)에 맞은 Mesh 판별하기 (0) | 2024.11.12 |
---|---|
Raycaster, 동작 원리 (0) | 2024.11.12 |
조명, RectAreaLight_직사각형 모양으로 균일한 빛을 방사하는 조명 효과 (0) | 2024.11.11 |
조명, HemisphereLight_하늘과 땅을 기반으로 빛을 조절하는 조명 효과 (0) | 2024.11.11 |
조명, SpotLight_스포트라이트 효과_무대 조명이나 손전등과 같은 빛을 표현 (0) | 2024.11.10 |