3D模型体素化(Voxelization)过程实现与分析(二)
文章目录
- 体素化方法
- 原理展示
- 实现过程
- 使用Buffer
- 着色器
- 读取体素坐标
- 实现代码
- 顶点着色器
- 片元着色器
- CPU读取
- 效果图
体素化方法
体素化能够对模型进行简化,得到均匀的网格,在求模型的测地线,求交等过程中有较好的应用。个人理解,把体素化分为基于CPU的方法和基于GPU渲染的方法。输入是三角面片,输出体素化格子。
直接使用三角形求交的方法见
3D模型体素化(Voxelization)过程实现与分析(一)
使用三角形求交的方法,体素化计算量与三角形的数量,体素分辨率直接相关。当三角形数量增多,分辨率增大时,计算量将急剧增加,计算十分缓慢。
本文介绍使用OpenGL快速计算体素化的方法,使用渲染管线中的片段着色器,将三角形与体素的求交转化为采样点与体素的求交。运用片元的并行性,快速得到体素化结果。
原理展示

- 计算模型的包围盒
- 在包围盒外部设置相机,最好是用正交相机,进行投影
- 对于投影后的片元,计算每个片元的三维位置对应的体素【注意,深度测试前所有的片元都不会被丢弃】
实现过程
使用Buffer
这里需要从着色器回传会体素占用信息,使用一个一维的数组来展开三维的体素位置。uniform对于着色器是只读的。因此使用Buffer,着色器是可读写的,同时Buffer也允许使用较大的空间。
着色器
- 由于着色器是并行的,使用原子操作来实现同步。
- 所有从顶点着色器到片元着色器中的变量都会被插值,因此可以直接从顶点着色器计算三维坐标,传入到片元着色器。
- 片元着色器根据坐标位置,直接计算体素坐标,写入到数组中。
读取体素坐标
在CPU中读取Buffer数组,解析出体素化结果。
实现代码
顶点着色器
#version 430 core
layout (location=0) in vec3 aPos;
layout (location=1) in vec3 aNormal;
layout (location=2) in vec2 aTexture;out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{ FragPos = aPos; // 局部坐标gl_Position = projection *view *model *vec4(aPos,1.0);
}
片元着色器
#version 430 coreout vec4 FragColor;in vec3 FragPos;layout (std430, binding =0) buffer CountBuffer{int cnts[];
};uniform vec3 box_min;
uniform float interval; // 步长
uniform vec3 xyz; // 分辨率
uniform int pass;void main()
{if(pass ==0){ int x = int((FragPos.x-box_min.x)/interval);int y = int((FragPos.y-box_min.y)/interval);int z = int((FragPos.z-box_min.z)/interval);int idx = int(y *(xyz.z *xyz.x) + z *xyz.x + x); atomicAdd(cnts[idx], 1);}FragColor = vec4(1, 0, 0, 1);
}
CPU读取
glBindBuffer(GL_SHADER_STORAGE_BUFFER, cntBO); // 获取buffer指针
int * ptr = (int *)(glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY));
// cout << "error node: " << glGetError() << endl;
vector<glm::vec3> pos; // 体素位置
vector<glm::ivec3> idx; // 体素索引
if (ptr != NULL)
{for (int i = 0; i < cnts.size(); ++i){if (*(ptr + i)){int y1 = i / (x*z);int z1 = (i - y1 *x*z) / x;int x1 = (i - y1*x*z - z1*x);pos.push_back(box_min + glm::vec3(x1*width, y1*width, z1*width));idx.push_back(glm::ivec3(x1, y1, z1));}}
}
else
{Error("read buffer data error");
}
glUnmapBuffer(cntBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
效果图


如有错误,欢迎指出~
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
