일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 블록체인
- ps4
- 투자
- Three
- loopback
- threejs
- 부동산
- Games
- 이더리움
- 탈중앙화
- 스마트 컨트랙트
- 거래
- 주식
- PC
- 쿠버네티스
- 리뷰
- angular
- 보안
- 암호화폐
- 비트코인
- kubernetes
- 게임
- review
- 스마트 계약
- strongloop
- Linux
- Docker
- 젤다 왕눈
- game
- 시장
- Today
- Total
BaeBox
Picking(raycasting) 본문
Picking : 사용자가 터치하거나 클릭한 객체를 파악하는 프로세스.
내가 고른 객체 데이터를 가져오는 방법이라고 생각하자.
처음보면 저걸 어떻게하나 어려워 보이는데, Three.js에서 기본적으로 제공해주는 RayCasting 기능을 사용하면 굉장히 쉽게 구현이 가능하다.
아래 코드는 공식 문서에서 긁어왔다.
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onMouseMove( event ) {
// calculate mouse position in normalized device coordinates
// (-1 to +1) for both components
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function render() {
// update the picking ray with the camera and mouse position
raycaster.setFromCamera( mouse, camera );
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
intersects[ i ].object.material.color.set( 0xff0000 );
}
renderer.render( scene, camera );
}
window.addEventListener( 'mousemove', onMouseMove, false );
window.requestAnimationFrame(render);
위에는 귀여운 예제였다.
이제 아래를 보자.
하나의 mesh(object)에 texture로 중앙이 빵꾸난 png 텍스쳐를 입혔다고 생각해보자.
근데 그렇다고 가운데 텅 빈 부분을 관통해서 뒤에 있는 놈이 선택이 될까?
중앙이 텅 빈 텍스처를 씌웠건 말았건, 빛이 가리키는 것은 제일 앞에 위치한 Mesh(Object)이다.
자바스크립트는 얘가 텅 비었는지 아닌지 구분을 못한다.
그렇다면 중앙을 텅 빈놈을 관통해 뒤에 있는 친구를 선택하고 싶다면 어떻게 해야 하느냐.
CPU를 기반으로하면 각 mesh가 뚫려있는지 구분이 불가능하므로, GPU를 기반으로하여 picking을 한다.
대강 요런짓을 한다.
Scene을 복제한 pickingScene을 새로 생성한 다음, pickingScene과 내용물의 색상을 모두 검은색(0)으로 설정한다.
이 때, pickingScene의 내용물이 되는 Mesh들의 emissive(외부로 보이는 색)의 값을 유니크한 값으로 설정해준다.
그리고 아래 코드의 pick 함수가, id 값을 받아오는데 이 값은 위에서 유니크하게 설정한 emissive 값이 된다.
이제 그걸 기반으로 Mesh 속성을 조정하면 된다.
class GPUPickHelper {
constructor() {
// create a 1x1 pixel render target
this.pickingTexture = new THREE.WebGLRenderTarget(1, 1);
this.pixelBuffer = new Uint8Array(4);
this.pickedObject = null;
this.pickedObjectSavedColor = 0;
}
pick(cssPosition, scene, camera, time) {
const {pickingTexture, pixelBuffer} = this;
// restore the color if there is a picked object
if (this.pickedObject) {
this.pickedObject.material.emissive.setHex(this.pickedObjectSavedColor);
this.pickedObject = undefined;
}
// set the view offset to represent just a single pixel under the mouse
const pixelRatio = renderer.getPixelRatio();
camera.setViewOffset(
renderer.getContext().drawingBufferWidth, // full width
renderer.getContext().drawingBufferHeight, // full top
cssPosition.x * pixelRatio | 0, // rect x
cssPosition.y * pixelRatio | 0, // rect y
1, // rect width
1, // rect height
);
// render the scene
renderer.setRenderTarget(pickingTexture);
renderer.render(scene, camera);
renderer.setRenderTarget(null);
// clear the view offset so rendering returns to normal
camera.clearViewOffset();
//read the pixel
renderer.readRenderTargetPixels(
pickingTexture,
0, // x
0, // y
1, // width
1, // height
pixelBuffer);
const id =
(pixelBuffer[0] << 16) |
(pixelBuffer[1] << 8) |
(pixelBuffer[2] );
const intersectedObject = idToObject[id];
if (intersectedObject) {
// pick the first object. It's the closest one
this.pickedObject = intersectedObject;
// save its color
this.pickedObjectSavedColor = this.pickedObject.material.emissive.getHex();
// set its emissive color to flashing red/yellow
this.pickedObject.material.emissive.setHex((time * 8) % 2 > 1 ? 0xFFFF00 : 0xFF0000);
}
}
}
끗.
아래 공식문서에서 다양한 예제를 제공하고, 그 아래엔 threejs 블로그인데, picking을 쉽게 하기 위한 클래스 및 다양한 방법을 소개한다.
https://threejs.org/docs/index.html#api/en/core/Raycaster
https://threejsfundamentals.org/threejs/lessons/threejs-indexed-textures.html
https://threejsfundamentals.org/threejs/lessons/threejs-picking.html
https://threejsfundamentals.org/threejs/lessons/threejs-align-html-elements-to-3d.html
'개발 관련' 카테고리의 다른 글
WebGL (0) | 2020.07.01 |
---|---|
Globe( 지구본 ) (0) | 2020.06.21 |
Web developer roadmap 2020 (0) | 2020.06.21 |
Git README.md 작성법 (0) | 2020.04.25 |
QuickSort(퀵정렬) with JavaScript (0) | 2020.04.21 |