Raycasting 방식
3.js 자체 사용 입니다. Raycaster를 사용하여 객체를 선택하는 것은 매우 간단합니다. 코드는 다음과 같습니다:
var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); function onMouseMove(event) { // 计算鼠标所在位置的设备坐标 // 三个坐标分量都是-1到1 mouse.x = event.clientX / window.innerWidth * 2 - 1; mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; } function pick() { // 使用相机和鼠标位置更新选取光线 raycaster.setFromCamera(mouse, camera); // 计算与选取光线相交的物体 var intersects = raycaster.intersectObjects(scene.children); }
[관련 강좌 권장 사항: JavaScript 비디오 튜토리얼]
투영된 광선이 각 삼각형 표면 요소와 교차하는지 여부를 계산하기 위해 경계 상자 필터링을 사용하여 구현됩니다.
하지만 모델이 매우 큰 경우(예: 400,000개의 면이 있는 경우) 객체를 선택하고 순회를 통해 충돌 지점의 위치를 계산하는 것이 매우 느리고 사용자 경험이 좋지 않습니다.
하지만 GPU를 사용하여 개체를 선택하면 이 문제가 발생하지 않습니다. 장면과 모델의 크기에 관계없이 객체의 위치와 마우스 지점의 교차점을 한 프레임 내에서 얻을 수 있습니다.
GPU를 사용하여 개체 선택
구현 방법은 매우 간단합니다.
1 선택 자료를 만듭니다. 그리고 장면에 추가하세요. 각 모델의 재질을 다른 색상으로 교체하세요.
2. 마우스 위치의 픽셀 색상을 읽고 이를 기준으로 마우스 위치에 있는 개체를 결정합니다.
특정 구현 코드:
1. 선택한 재질을 생성하고 장면을 순회하며 장면의 각 모델을 다른 색상으로 바꿉니다.
let maxHexColor = 1;// 更换选取材质 scene.traverseVisible(n => { if (!(n instanceof THREE.Mesh)) { return; } n.oldMaterial = n.material; if (n.pickMaterial) { // 已经创建过选取材质了 n.material = n.pickMaterial; return; } let material = new THREE.ShaderMaterial({ vertexShader: PickVertexShader, fragmentShader: PickFragmentShader, uniforms: { pickColor: { value: new THREE.Color(maxHexColor) } } }); n.pickColor = maxHexColor; maxHexColor++; n.material = n.pickMaterial = material; }); PickVertexShader: void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } PickFragmentShader: uniform vec3 pickColor;void main() { gl_FragColor = vec4(pickColor, 1.0); }
2. WebGLRenderTarget에 장면을 그리고 마우스 위치의 색상을 읽고 선택한 개체를 결정합니다.
let renderTarget = new THREE.WebGLRenderTarget(width, height); let pixel = new Uint8Array(4);// 绘制并读取像素 renderer.setRenderTarget(renderTarget); renderer.clear(); renderer.render(scene, camera); renderer.readRenderTargetPixels(renderTarget, offsetX, height - offsetY, 1, 1, pixel); // 读取鼠标所在位置颜色 // 还原原来材质,并获取选中物体 const currentColor = pixel[0] * 0xffff + pixel[1] * 0xff + pixel[2]; let selected = null; scene.traverseVisible(n => { if (!(n instanceof THREE.Mesh)) { return; } if (n.pickMaterial && n.pickColor === currentColor) { // 颜色相同 selected = n; // 鼠标所在位置的物体 } if (n.oldMaterial) { n.material = n.oldMaterial; delete n.oldMaterial; } });
설명: offsetX 및 offsetY는 마우스 위치이고 높이는 캔버스 높이입니다. readRenderTargetPixels 라인의 의미는 너비 1, 높이 1로 마우스 위치(offsetX, height - offsetY)에서 픽셀 색상을 선택하는 것입니다.
pixel은 Uint8Array(4)이며, 각각 rgba 색상의 4개 채널을 저장합니다. 각 채널의 값 범위는 0~255입니다.
전체 구현 코드: https://gitee.com/tengge1/ShadowEditor/blob/master/ShadowEditor.Web/src/event/GPUPickEvent.js
#🎜🎜 #GPU를 사용하여 교차 위치 얻기
구현 방법도 매우 간단합니다. 1 깊이 셰이더 재료를 만들고 장면 깊이를 WebGLRenderTarget. 2. 마우스 위치의 깊이를 계산하고 마우스 위치와 깊이를 기준으로 교차 위치를 계산합니다. 특정 구현 코드: 1. 깊이 셰이더 재질을 생성하고 특정 방식으로 깊이 정보를 인코딩한 후 WebGLRenderTarget에 렌더링합니다. 에디토리얼 카메라로Far. 셰이더 가변 변수는 보간을 위해 직접 사용될 수 있습니다. b. gl_Position.z /far를 사용하는 이유는 색상으로 쉽게 출력할 수 있도록 값을 0~1 범위로 변환하기 위함입니다. c. 원근 투영 후에는 깊이가 -1~1이 되며 대부분 1에 매우 가깝고(0.9 이상) 선형이 아닙니다. 거의 변하지 않습니다. 출력 색상이 거의 일정하고 매우 부정확합니다. d. 프래그먼트 셰이더에서 깊이 방법을 얻습니다. 카메라 공간 깊이는 gl_FragCoord.z이고 화면 공간 깊이는 gl_FragCoord.z / gl_FragCoord.w입니다. e 위의 설명은 모두 원근 투영에 대한 것입니다. 직교 투영에서는 gl_Position.w가 1이고 카메라 공간과 화면 공간 깊이가 동일합니다. f. 깊이를 최대한 정확하게 출력하기 위해 RGB의 세 가지 구성 요소를 사용하여 깊이를 출력합니다. gl_Position.z/far 범위는 0~1에 0xffffff를 곱하여 rgb 색상 값으로 변환됩니다. r 구성 요소 1은 65535, g 구성 요소 1은 255, b 구성 요소 1은 1을 나타냅니다. 전체 구현 코드: https://gitee.com/tengge1/ShadowEditor/blob/master/ShadowEditor.Web/src/event/GPUPickEvent.js2 읽기. 마우스 위치의 색상을 구하고 읽은 색상 값을 카메라 공간 깊이 값으로 복원합니다. a. WebGLRenderTarget에 "암호화된" 깊이를 그립니다. 색상 방법 읽기const depthMaterial = new THREE.ShaderMaterial({ vertexShader: DepthVertexShader, fragmentShader: DepthFragmentShader, uniforms: { far: { value: camera.far } } }); DepthVertexShader: precision highp float; uniform float far; varying float depth;void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); depth = gl_Position.z / far; } DepthFragmentShader: precision highp float; varying float depth;void main() { float hex = abs(depth) * 16777215.0; // 0xffffff float r = floor(hex / 65535.0); float g = floor((hex - r * 65535.0) / 255.0); float b = floor(hex - r * 65535.0 - g * 255.0); float a = sign(depth) >= 0.0 ? 1.0 : 0.0; // depth大于等于0,为1.0;小于0,为0.0。 gl_FragColor = vec4(r / 255.0, g / 255.0, b / 255.0, a); }
let renderTarget = new THREE.WebGLRenderTarget(width, height); let pixel = new Uint8Array(4); scene.overrideMaterial = this.depthMaterial; renderer.setRenderTarget(renderTarget); renderer.clear(); renderer.render(scene, camera); renderer.readRenderTargetPixels(renderTarget, offsetX, height - offsetY, 1, 1, pixel);
if (pixel[2] !== 0 || pixel[1] !== 0 || pixel[0] !== 0) { let hex = (this.pixel[0] * 65535 + this.pixel[1] * 255 + this.pixel[2]) / 0xffffff; if (this.pixel[3] === 0) { hex = -hex; } cameraDepth = -hex * camera.far; // 相机坐标系中鼠标所在点的深度(注意:相机坐标系中的深度值为负值)}
GPU를 사용하여 객체를 선택하고 교차 위치를 계산하는데, 이는 매우 높은 성능이 필요할 때 주로 사용됩니다. 예:
1. 마우스를 3D 모델로 이동할 때 나타나는 호버 효과입니다.
2. 모델을 추가할 때 모델이 마우스로 움직이며 장면에 모델을 배치하는 효과를 실시간으로 미리 볼 수 있습니다. 3. 거리 측정, 면적 측정 등의 도구 평면 위에서 마우스를 움직이면 선과 다각형을 실시간으로 미리 볼 수 있고 길이와 면적을 계산할 수 있습니다.
4. 장면과 모델이 매우 크고 레이 캐스팅 방식을 선택하는 속도가 매우 느리며 사용자 경험이 매우 나쁩니다.
여기는 GPU를 사용하여 개체를 선택하고 마우스 호버 효과를 얻는 사진입니다. 빨간색 테두리는 선택 효과이고 노란색 반투명 효과는 마우스 호버 효과입니다.
이해가 안 되시나요? 어쩌면 당신은 three.js의 다양한 프로젝션 작업에 익숙하지 않을 수도 있습니다. three.js의 투영 연산 공식은 다음과 같습니다.
three.js
1. modelViewMatrix = Camera.matrixWorldInverse * object.matrixWorld
2. modelMatrix = object.matrixWorldInverse
3. 4 ( Camera.matrixWorldInverse ).applyMatrix4( Camera.projectionMatrix )
5. unproject = applyMatrix4( Camera.projectionMatrixInverse ).applyMatrix4( Camera.matrixWorld )
6. gl_Position =projectionMatrix * modelViewMatrix * position
camera.matrixWorldInverse * MatrixWorld * 위치 + > three.js 기반의 소스 3D 장면 편집기: https://github.com/tengge1/ShadowEditor
3. 셰이더를 사용하여 OpenGL에서 깊이 값 그리기: https:/ /stackoverflow.com /questions/6408851/draw-the-length-value-in-opengl-using-shaders
4 glsl에서 실제 조각 셰이더 깊이 값을 가져옵니다: https://gamedev.stackexchange.com/questions / 93055/getting-the-real-fragment-length-in-glsl
이 기사는
js tutorial칼럼에서 가져온 것입니다. 배우신 것을 환영합니다!
위 내용은 three.js는 GPU를 사용하여 객체를 선택하고 교차 위치를 계산합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!