在THREE.js中检索顶点数据

7

我正在使用自定义着色器创建一个网格。在顶点着色器中,我修改了几何体顶点的原始位置。然后,我需要从着色器外部访问这些新顶点的位置,我该如何实现?

1个回答

9

由于WebGL 1.0不支持变换反馈,您需要使用一个经过的片段着色器和浮点纹理(这需要加载扩展OES_texture_float)来代替。这是在WebGL中生成顶点缓冲区的唯一方法。WebGL也不支持像素缓冲对象,因此读取输出数据将非常低效。

尽管如此,以下是您可以完成此操作的方法:

这将是一个粗略的概述,重点是OpenGL而不是任何特定于Three.js的内容。

首先,按以下方式对您的顶点数组进行编码(添加第4个索引组件):

Vec4 pos_idx  :  xyz = Vertex Position,  w = Vertex Index (0.0 through NumVerts-1.0)

将顶点索引存储为w组件是必要的,因为OpenGL ES 2.0(WebGL 1.0)不支持gl_VertexID

接下来,您需要一个二维浮点纹理:

MaxTexSize = Query GL_MAX_TEXTURE_SIZE

Width  = MaxTexSize;
Height = min (NumVerts / MaxTexSize, 1);

创建一个具有这些尺寸的RGBA浮点纹理,并将其用作FBO颜色附件0。

顶点着色器:

#version 100

attribute vec4 pos_idx;

uniform int width;  // Width of floating-point texture
uniform int height; // Height of floating-point texture

varying vec4 vtx_out;

void main (void)
{
  float idx = pos_idx.w;

  // Position this vertex so that it occupies a unique pixel
  vec2 xy_idx = vec2 (float ((int (idx) % width)) / float (width),
                      floor (idx / float (width)) / float (height)) * vec2 (2.0) - vec2 (1.0);
  gl_Position = vec4 (xy_idx, 0.0f, 1.0f);


  //
  // Do all of your per-vertex calculations here, and output to vtx_out.xyz
  //


  // Store the index in the W component
  vtx_out.w = idx;
}

透传片元着色器:

#version 100

varying vec4 vtx_out;

void main (void)
{
  gl_FragData [0] = vtx_out;
}

绘制和读取:

// Draw your entire vertex array for processing (as `GL_POINTS`)
glDrawArrays (GL_POINTS, 0, NumVerts);

// Bind the FBO's color attachment 0 to `GL_TEXTURE_2D`

// Read the texture back and store its results in an array `verts`
glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, verts);

在Three.js中,可以找到大致符合您要求的一些代码here。它略有不同之处在于它始终将顶点保留在GPU上,但如果您检查此答案并将其作为一些示例代码,您应该能够组合出一些东西。 - Andon M. Coleman
非常感谢您提供如此详细的解释!所以我理解的唯一方法是使用片段着色器来检索纹理(基于顶点位置),然后再次将RGBA颜色从纹理转换为位置,对吗? - MickeyMouse
1
@MickeyMouse:是的,不过……如果你在 CPU 端不需要这些位置信息,实际上可以在另一个渲染通道的顶点着色器中进行纹理查找。如果你查看我列出的示例的源代码,它展示了如何做到这一点。我不确定你是否需要从 GPU 中获取顶点数据,而我所描述的答案是从 GPU 下载顶点数据。 - Andon M. Coleman
是的,我想我需要它们在CPU中。我正在尝试制作高斯模糊并将其应用于顶点位置(高度)值(而不是颜色)。为了优化这个过程,我分两步进行任务,水平和垂直(http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/)。也许对于这两个步骤,我不需要它们在CPU中(?)。第三步是规范化值,这意味着我必须迭代所有顶点,所以我发现我需要它们在CPU中进行最后一步。 - MickeyMouse
@MickeyMouse: 我真的不知道你如何将模糊滤镜应用于顶点数据。你可能可以得到一个点云,但按照我脑海中的想象,插入额外的顶点会导致失去三角形等结构。无论如何,如果您将顶点位置存储在纹理中,您可以在片段着色器中进行多次获取(您将不得不使用我之前链接的Three.js示例中的纹理坐标索引逻辑从正确的纹素中提取顶点),并可能在GPU上实现整个过程。 - Andon M. Coleman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接