three.js - 使用 Three.js 中的自定义顶点着色器对点云进行光线追踪

标签 three.js webgl

如何使用 Three.js 中的自定义顶点着色器对点云进行光线追踪。

这是我的顶点着色器

void main() {
  vUvP = vec2( position.x / (width*2.0), position.y / (height*2.0)+0.5 );
  colorP = vec2( position.x / (width*2.0)+0.5 , position.y / (height*2.0)  );
  vec4 pos = vec4(0.0,0.0,0.0,0.0);
  depthVariance = 0.0;
  if ( (vUvP.x<0.0)|| (vUvP.x>0.5) || (vUvP.y<0.5) || (vUvP.y>0.0)) {
     vec2 smp = decodeDepth(vec2(position.x, position.y));
     float depth = smp.x;
     depthVariance = smp.y; 
     float z = -depth;
     pos = vec4(( position.x / width - 0.5 ) * z * (1000.0/focallength) * -1.0,( position.y / height - 0.5 ) * z * (1000.0/focallength),(- z + zOffset / 1000.0) * 2.0,1.0);
     vec2 maskP = vec2( position.x / (width*2.0), position.y / (height*2.0)  );
     vec4 maskColor = texture2D( map, maskP );
     maskVal = ( maskColor.r + maskColor.g + maskColor.b ) / 3.0 ;
  }
  gl_PointSize = pointSize;
  gl_Position = projectionMatrix * modelViewMatrix * pos;
}

在Points类中,光线追踪的实现如下:

function testPoint( point, index ) {
    var rayPointDistanceSq = ray.distanceSqToPoint( point );
    if ( rayPointDistanceSq < localThresholdSq ) {
      var intersectPoint = ray.closestPointToPoint( point );
      intersectPoint.applyMatrix4( matrixWorld );
      var distance = raycaster.ray.origin.distanceTo( intersectPoint );
      if ( distance < raycaster.near || distance > raycaster.far ) return;
      intersects.push( {
          distance: distance,
          distanceToRay: Math.sqrt( rayPointDistanceSq ),
          point: intersectPoint.clone(),
          index: index,
          face: null,
          object: object
       } );
    }
 }

var vertices = geometry.vertices;
for ( var i = 0, l = vertices.length; i < l; i ++ ) {
       testPoint( vertices[ i ], i );
}

但是,由于我使用的是顶点着色器,geometry.vertices 与屏幕上的顶点不匹配,这导致光线追踪无法工作。

我们可以从顶点着色器取回点吗?

最佳答案

我没有深入研究你的顶点着色器实际上做了什么,我认为你有充分的理由在着色器中这样做,所以在进行光线转换时在 JavaScript 中重做计算可能是不可行的.

一种方法可能是对点的位置进行某种估计,将其用于预选择,并对最接近射线的点进行一些更复杂的计算。

如果这不起作用,最好的选择是渲染场景的查找图,其中颜色值是在坐标处渲染的点的 ID(这也称为 GPU-选择,示例 herehere 甚至一些库 here 尽管这并不能真正满足您的需要)。

为此,您需要渲染场景两次:在第一遍中创建查找映射,并在第二遍中定期渲染它。查找图将为每个像素存储在那里渲染的粒子。

要获取该信息,您需要设置一个 THREE.RenderTarget (这可能会缩小到宽度/高度的一半以获得更好的性能)和不同的 Material 。顶点着色器保持原样,但片段着色器只会为每个粒子(或可用于识别它们的任何内容)输出一个唯一的颜色值。然后将场景(或者更好:仅应该是光线转换目标的部分)渲染到 renderTarget 中:

var size = renderer.getSize();
var renderTarget = new THREE.WebGLRenderTarget(size.width / 2, size.height / 2);
renderer.render(pickingScene, camera, renderTarget);

渲染完成后,可以使用renderer.readRenderTargetPixels获取该lookup-texture的内容-方法:

var pixelData = new Uint8Array(width * height * 4);
renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, pixelData);

(此处 PixelData 的布局与常规 Canvas imageData.data 相同)

一旦有了这个,光线转换器将只需要查找单个坐标,读取颜色值并将其解释为对象 ID,并用它做一些事情。

关于three.js - 使用 Three.js 中的自定义顶点着色器对点云进行光线追踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40334473/

相关文章:

WebGL 等距投影

webgl - 使用Oculus Rift显示Web应用程序输出

javascript - 与 MeshBasicMaterial 相比,ThreeJS MeshStandardMaterial 在移动设备上太慢

javascript - 让基于 HTML 5 的 VR 应用在 Daydream 中显示

javascript - 创建跟随光源的日/夜着色器

javascript - 在three.js中Mipmap一个行星?

javascript - 如何在 WebGL 中沿 x 轴移动纹理?

javascript - Three.js 天空盒纹理问题

javascript - ThreeJS隐藏纹理

javascript - mtlLoader模块 "does not provide an export named ' MTLLoader'错误