如何在OpenGL ES 2中访问顶点着色器程序中的其他顶点?

6

我是一款安卓应用程序,我想根据该表面的其他顶点计算其法线。我不希望在“主”程序中执行此操作,因为这需要太长时间。实际上,对于每个顶点,我传递了4个浮点数组:

attribute vec3 a_bottom;
attribute vec3 a_left;
attribute vec3 a_right;
attribute vec3 a_top;

vec3 calculNormal( ) {
    return normalize( cross( (a_left - a_right) , ( a_bottom - a_top ) ) );
}

我知道这是非常非常非常糟糕的代码,所以我不想传递4个数组,我想这样做:

vec3 calculNormal( ) {
    vec3 a_left = CURRENT_FLOATBUFFER[ CURRENT_FLOAT_BUFFER_POSITION - 1 ];
    vec3 a_bottom = CURRENT_FLOATBUFFER[ CURRENT_FLOAT_BUFFER_POSITION - X ];
    ...
    return normalize( cross( (a_left - a_right) , ( a_bottom - a_top ) ) );
}

在顶点着色器程序中,能否访问当前的浮点缓冲区?是否有类似于currentFloat的特殊关键字?还是我错过了其他可能性?

2个回答

9
这的确不可能。顶点着色器只能访问当前处理的顶点及其属性。由于OpenGL ES没有“texture_buffer_object”扩展,因此您无法在着色器内部访问VBO的数据。因此,访问顶点的相邻点的唯一方法是将它们明确放入顶点属性中,就像您第一个示例中所做的那样。
但是,由于您的几何图形看起来是矩形模式,因此您也可以将其存储在纹理中(或者将其复制到纹理中,如果ES支持“pixel_buffer_object”扩展,这可能有所帮助)。在这种情况下,您可以使用经典的GPGPU片段着色器,为输出图像中的每个“像素”(在本例中是一个顶点)计算法线,该法线基于其相邻点的值(通过简单的纹理访问访问)。
但是我猜,考虑到额外的编程开销和/或内存复制操作,第一个和第二个选项都不会给您带来太多好处。计算顶点法线已经非常快了。您不必每帧都这样做,而且如果确实需要,那么这是因为您正在更新顶点位置,在这种情况下,您可以对法线数据使用相同的更新例程(无论是CPU还是GPGPU)。

5
我希望能根据这个面的其他顶点计算出其法向量。
错误的方式。应该计算出法向量并与顶点一起存储。
我不想在主程序中这样做,因为这会花费太多时间。
你不应该在每次渲染通行证中重新计算法向量。只需计算一次并存储即可。在顶点着色器中进行的计算是不免费的。而且在VS中计算法向量只是浪费处理能力。
计算它们,存储它们。

嗨,datenwolf。如果我想在运行时创建一个对象后对高度图进行采样,该怎么办?我应该通过着色器来采样高度图,转换顶点,然后发送回来,再上传另一个VBO吗?我认为在CPU上采样纹理并不是正确的方法,因为一方面纹理已经使用glTexImage上传了,而CPU并没有真正拥有它。 - Zebrafish
1
@TitoneMaurice:原始问题是关于通用网格的。但高度图是一种特殊情况,其中表面法线可以使用与正确内核(离散差分,又称梯度内核)的卷积来计算。使用textureGather(GLSL-4及更高版本),可以获取2×2个纹素的网格,这正是您所需要的。然而,我仍然建议预先计算法线,这为您提供了实际上是纹理的法线贴图 - datenwolf
1
@TitoneMaurice:应用想法:创建高分辨率的高度图,从中生成法线贴图,在片段着色器中使用全分辨率的法线贴图进行照明计算,并使用降采样的高度图进行顶点位移。更进一步的想法是:您可以存储完整分辨率的高度-法线贴图,并在顶点阶段访问较低分辨率的细节层次,并在片段着色器中使用完整分辨率和顶点高度值之间的差异作为视差映射的输入,以提高视觉质量。 - datenwolf

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