3D模型体素化(Voxelization)过程实现与分析(二)

文章目录

  • 体素化方法
    • 原理展示
    • 实现过程
      • 使用Buffer
      • 着色器
      • 读取体素坐标
    • 实现代码
      • 顶点着色器
      • 片元着色器
      • CPU读取
      • 效果图

体素化方法

体素化能够对模型进行简化,得到均匀的网格,在求模型的测地线,求交等过程中有较好的应用。个人理解,把体素化分为基于CPU的方法和基于GPU渲染的方法。输入是三角面片,输出体素化格子。

直接使用三角形求交的方法见
3D模型体素化(Voxelization)过程实现与分析(一)

使用三角形求交的方法,体素化计算量与三角形的数量,体素分辨率直接相关。当三角形数量增多,分辨率增大时,计算量将急剧增加,计算十分缓慢。
本文介绍使用OpenGL快速计算体素化的方法,使用渲染管线中的片段着色器,将三角形与体素的求交转化为采样点与体素的求交。运用片元的并行性,快速得到体素化结果。

原理展示

3D模型体素化(Voxelization)过程实现与分析(二)_第1张图片

  1. 计算模型的包围盒
  2. 在包围盒外部设置相机,最好是用正交相机,进行投影
  3. 对于投影后的片元,计算每个片元的三维位置对应的体素【注意,深度测试前所有的片元都不会被丢弃】

实现过程

使用Buffer

这里需要从着色器回传会体素占用信息,使用一个一维的数组来展开三维的体素位置。uniform对于着色器是只读的。因此使用Buffer,着色器是可读写的,同时Buffer也允许使用较大的空间。

着色器

  1. 由于着色器是并行的,使用原子操作来实现同步。
  2. 所有从顶点着色器到片元着色器中的变量都会被插值,因此可以直接从顶点着色器计算三维坐标,传入到片元着色器。
  3. 片元着色器根据坐标位置,直接计算体素坐标,写入到数组中。

读取体素坐标

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 core

out 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);			

效果图

3D模型体素化(Voxelization)过程实现与分析(二)_第2张图片

3D模型体素化(Voxelization)过程实现与分析(二)_第3张图片

如有错误,欢迎指出~

你可能感兴趣的:(图形学)