利用 webGL 寻找边界框
Leveraging webGL to find bounding boxes
给定一些具有 xyz 坐标的顶点,很容易获得一个 xyz 对齐的边界框,只需从顶点中获取 min/max xyz 值。理想情况下,这些值只需找到一次,并且可以在任何渲染发生之前找到。
我的问题是:如果旋转、缩放或平移对象,计算绑定对象的新 xyz 值的最佳方法是什么?我是否必须在每次变换后遍历所有顶点并找到新的 min/max xyz 值?
给定 GLSL 代码
in vec4 a_position;
in vec4 a_color;
// transformation matrix
uniform mat4 u_matrix;
out vec4 v_color;
void main() {
gl_Position = u_matrix * a_position;
v_color = a_color;
}
我的想法:为边界框坐标添加新的 out
变量是否可行?或者有更好的方法吗?
in vec4 a_position;
in vec4 a_color;
// transformation matrix
uniform mat4 u_matrix;
out vec4 v_color;
out vec3 max_bounds;
out vec3 min_bounds;
void main() {
vec4 position = u_matrix * a_position;
if(position.x > max_bounds.x){
max_bounds.x = position.x;
}
if(position.y > max_bounds.y){
max_bounds.y = position.y;
}
if(position.z > max_bounds.z){
max_bounds.z = position.z;
}
// ...
gl_Position = position;
v_color = a_color;
}
你不能,因为你的顶点着色器代码(和所有其他着色器代码)是并行执行的,输出只进入下一阶段(在你的情况下是片段着色器)。
一个例外是变换反馈,其中顶点着色器的输出可以写入缓冲区,但是您只能将其用于 map 数据而不是 gather / reduce 它。 GPU 的 efficiency/performance 优势很大一部分是由于并行执行代码。在这些并行线程之间共享数据的能力非常有限,并且一开始就无法通过 WebGL 访问。
最重要的是,您的任务(在顶点数组中找到 min/max 范围)本质上是顺序的,因为它需要可用的共享数据(最小值和最大值)和 current至 所有 个线程。
由于 AABB 本质上是相当宽松的,一种(如果不是)常用方法是变换 AABB(未变换网格的)的 8 个角顶点并从中收集 AABB。
理论上说你可以将顶点位置存储在浮点纹理中,使用片段(而不是顶点)着色器转换它们,将其写回纹理,然后执行一堆收集通道,您可以在其中收集 X 大小(例如 64x64)的块的最小最大值,并将其写回一组越来越小的纹理,直到达到 1x1 像素纹理,然后读取您的使用 readPixels
的结果。也就是说,这根本不值得付出努力(对于顶点数较少的网格来说可能更慢)只是为了获得稍微更好的拟合 AABB,如果你真的需要,你宁愿创建一个由更好拟合的边界形状组成的复合体积和而不是从中收集一个组合的 AABB。
给定一些具有 xyz 坐标的顶点,很容易获得一个 xyz 对齐的边界框,只需从顶点中获取 min/max xyz 值。理想情况下,这些值只需找到一次,并且可以在任何渲染发生之前找到。
我的问题是:如果旋转、缩放或平移对象,计算绑定对象的新 xyz 值的最佳方法是什么?我是否必须在每次变换后遍历所有顶点并找到新的 min/max xyz 值?
给定 GLSL 代码
in vec4 a_position;
in vec4 a_color;
// transformation matrix
uniform mat4 u_matrix;
out vec4 v_color;
void main() {
gl_Position = u_matrix * a_position;
v_color = a_color;
}
我的想法:为边界框坐标添加新的 out
变量是否可行?或者有更好的方法吗?
in vec4 a_position;
in vec4 a_color;
// transformation matrix
uniform mat4 u_matrix;
out vec4 v_color;
out vec3 max_bounds;
out vec3 min_bounds;
void main() {
vec4 position = u_matrix * a_position;
if(position.x > max_bounds.x){
max_bounds.x = position.x;
}
if(position.y > max_bounds.y){
max_bounds.y = position.y;
}
if(position.z > max_bounds.z){
max_bounds.z = position.z;
}
// ...
gl_Position = position;
v_color = a_color;
}
你不能,因为你的顶点着色器代码(和所有其他着色器代码)是并行执行的,输出只进入下一阶段(在你的情况下是片段着色器)。 一个例外是变换反馈,其中顶点着色器的输出可以写入缓冲区,但是您只能将其用于 map 数据而不是 gather / reduce 它。 GPU 的 efficiency/performance 优势很大一部分是由于并行执行代码。在这些并行线程之间共享数据的能力非常有限,并且一开始就无法通过 WebGL 访问。 最重要的是,您的任务(在顶点数组中找到 min/max 范围)本质上是顺序的,因为它需要可用的共享数据(最小值和最大值)和 current至 所有 个线程。
由于 AABB 本质上是相当宽松的,一种(如果不是)常用方法是变换 AABB(未变换网格的)的 8 个角顶点并从中收集 AABB。
理论上说你可以将顶点位置存储在浮点纹理中,使用片段(而不是顶点)着色器转换它们,将其写回纹理,然后执行一堆收集通道,您可以在其中收集 X 大小(例如 64x64)的块的最小最大值,并将其写回一组越来越小的纹理,直到达到 1x1 像素纹理,然后读取您的使用 readPixels
的结果。也就是说,这根本不值得付出努力(对于顶点数较少的网格来说可能更慢)只是为了获得稍微更好的拟合 AABB,如果你真的需要,你宁愿创建一个由更好拟合的边界形状组成的复合体积和而不是从中收集一个组合的 AABB。