由于缺乏对纹理坐标的理解,场景体素化不起作用
Scene voxelization not working due to lack of comprehension of texture coordinates
目标是采用任意几何体并创建包含场景的体素近似值的 3D 纹理。但是现在我们只有立方体。
场景如下:
这些场景最重要的两个方面如下:
场景中的每个立方体都应该对应于 3D 纹理中的一个体素。场景几何体随着高度的增加而变小(类似于金字塔)。场景几何体是空心的(也就是说,如果你进入这些山丘之一,内部没有立方体,只有轮廓有)。
为了对场景进行体素化,我们逐层渲染如下:
glViewport(0, 0, 7*16, 7*16);
glBindFramebuffer(GL_FRAMEBUFFER, FBOs[FBO_TEXTURE]);
for(int i=0; i<4*16; i++)
{
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D,
vMap->textureID, 0, i);
glClearColor(0.f, 0.f, 0.f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
load_uniform((float)i, "level");
draw();
}
其中"level"对应当前图层
然后在顶点着色器中,我们尝试创建一个单层,如下所示;
#version 450
layout(location = 0) in vec3 position; //(x,y,z) coordinates of a vertex
layout(std430, binding = 3) buffer instance_buffer
{
vec4 cubes_info[];//first 3 values are position of object
};
out vec3 normalized_pos;
out float test;
uniform float width = 128;
uniform float depth = 128;
uniform float height = 128;
uniform float voxel_size = 1;
uniform float level=0;
void main()
{
vec4 pos = (vec4(position, 1.0) + vec4(vec3(cubes_info[gl_InstanceID]),0));
pos.x = (2.f*pos.x-width)/(width);
pos.y = (2.f*pos.y-depth)/(depth);
pos.z = floor(pos.z);
test = pos.z;
pos.z -= level;
gl_Position = pos;
}
最后是片段着色器:
#version 450
in vec3 normalized_pos;
in float l;
in float test;
out vec4 outColor;//Final color of the pixel
void main()
{
outColor = vec4(vec3(test)/10.f, 1.0);
}
我使用 renderdoc 截取了一些结果纹理的截图:
第 0 层:
第 2 层:
眼前的两个值得注意的问题是:
一个图层不应该有多个灰色调,只有一个(因为每个图层对应不同的高度,所以不应该将多个高度渲染到同一图层)
第 2 层最暗的部分看起来像第 0 层应该看起来的样子(即没有 "holes" 的填充形状)。所以我不仅在同一层上渲染了多个高度,而且在渲染时我的偏移量似乎也为 2,这不应该发生。
有人知道问题出在哪里吗?
编辑:
如果有人想知道立方体的尺寸为 [1,1,1] 并且它们的坐标系与纹理对齐。即第一个立方体的左下角和前角位于 (0,0,0)
编辑 2:
改变
pos.z = floor(pos.z);
收件人:
pos.z = 楼层数(pos.z)+0.1;
部分解决了问题。最低层现在是正确的,但是现在有 2 个而不是 3 个不同的颜色(高度值)。
编辑 3:
问题似乎出在多次绘制几何体上。
即我实际的抽签看起来像:
for(uint i=0; i<render_queue.size(); i++)
{
Object_3D *render_data = render_queue[i];
//Render multiple instances of the current object
multi_render(render_data->VAO, &(render_data->VBOs),
&(render_data->types), render_data->layouts,
render_data->mesh_indices, render_data->render_instances);
}
void Renderer::multi_render(GLuint VAO, vector<GLuint> *VBOs,
vector<GLuint> *buffer_types, GLuint layout_num,
GLuint index_num, GLuint instances)
{
//error check
if(VBOs->size() != buffer_types->size())
{
cerr << "Mismatching VBOs's and buffer_types sizes" << endl;
return;
}
//Bind Vertex array object and rendering rpogram
glBindVertexArray(VAO);
glUseProgram(current_program);
//enable shader layouts
for(int i=0; i<layout_num;i++)
glEnableVertexAttribArray(i);
//Bind VBO's storing rendering data
for(uint i=0; i<buffer_types->size(); i++)
{
if((*buffer_types)[i]==GL_SHADER_STORAGE_BUFFER)
{
glBindBuffer((*buffer_types)[i], (*VBOs)[i]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, (*VBOs)[i]);
}
}
//Draw call
glDrawElementsInstanced(GL_TRIANGLES, index_num, GL_UNSIGNED_INT, (void*)0, instances);
}
似乎由于一次渲染场景的多个子集,我最终在 2 个不同的绘制调用中将不同的立方体映射到同一体素。
我找到问题了
由于我的几何体与体素网格 1 比 1 匹配。不同的层可以映射到相同的体素,导致它们在同一层重叠。
修改片段着色器如下:
#version 450
layout(location = 0) in vec3 position; //(x,y,z) coordinates of a vertex
layout(std430, binding = 3) buffer instance_buffer
{
vec4 cubes_info[];//first 3 values are position of object
};
out vec3 normalized_pos;
out float test;
uniform float width = 128;
uniform float depth = 128;
uniform float height = 128;
uniform float voxel_size = 1;
uniform float level=0;
void main()
{
vec4 pos = (vec4(position, 1.0) + vec4(vec3(cubes_info[gl_InstanceID]),0));
pos.x = (2.f*pos.x-width)/(width);
pos.y = (2.f*pos.y-depth)/(depth);
pos.z = cubes_info[gl_InstanceID].z;
test = pos.z + 1;
pos.z -= level;
if(pos.z >=0 && pos.z < 0.999f)
pos.z = 1;
else
pos.z = 2;
gl_Position = pos;
normalized_pos = vec3(pos);
}
修复了问题。
if 语句检查保证丢弃可能映射到当前层的不同层的几何图形。
可能有更好的方法来做到这一点。所以我会接受任何以更优雅的方式产生等效结果的答案。
这是第 0 层现在的样子:
这是第 2 层的样子:
目标是采用任意几何体并创建包含场景的体素近似值的 3D 纹理。但是现在我们只有立方体。
场景如下:
这些场景最重要的两个方面如下:
场景中的每个立方体都应该对应于 3D 纹理中的一个体素。场景几何体随着高度的增加而变小(类似于金字塔)。场景几何体是空心的(也就是说,如果你进入这些山丘之一,内部没有立方体,只有轮廓有)。
为了对场景进行体素化,我们逐层渲染如下:
glViewport(0, 0, 7*16, 7*16);
glBindFramebuffer(GL_FRAMEBUFFER, FBOs[FBO_TEXTURE]);
for(int i=0; i<4*16; i++)
{
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D,
vMap->textureID, 0, i);
glClearColor(0.f, 0.f, 0.f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
load_uniform((float)i, "level");
draw();
}
其中"level"对应当前图层
然后在顶点着色器中,我们尝试创建一个单层,如下所示;
#version 450
layout(location = 0) in vec3 position; //(x,y,z) coordinates of a vertex
layout(std430, binding = 3) buffer instance_buffer
{
vec4 cubes_info[];//first 3 values are position of object
};
out vec3 normalized_pos;
out float test;
uniform float width = 128;
uniform float depth = 128;
uniform float height = 128;
uniform float voxel_size = 1;
uniform float level=0;
void main()
{
vec4 pos = (vec4(position, 1.0) + vec4(vec3(cubes_info[gl_InstanceID]),0));
pos.x = (2.f*pos.x-width)/(width);
pos.y = (2.f*pos.y-depth)/(depth);
pos.z = floor(pos.z);
test = pos.z;
pos.z -= level;
gl_Position = pos;
}
最后是片段着色器:
#version 450
in vec3 normalized_pos;
in float l;
in float test;
out vec4 outColor;//Final color of the pixel
void main()
{
outColor = vec4(vec3(test)/10.f, 1.0);
}
我使用 renderdoc 截取了一些结果纹理的截图:
第 0 层:
第 2 层:
眼前的两个值得注意的问题是:
一个图层不应该有多个灰色调,只有一个(因为每个图层对应不同的高度,所以不应该将多个高度渲染到同一图层)
第 2 层最暗的部分看起来像第 0 层应该看起来的样子(即没有 "holes" 的填充形状)。所以我不仅在同一层上渲染了多个高度,而且在渲染时我的偏移量似乎也为 2,这不应该发生。
有人知道问题出在哪里吗?
编辑:
如果有人想知道立方体的尺寸为 [1,1,1] 并且它们的坐标系与纹理对齐。即第一个立方体的左下角和前角位于 (0,0,0)
编辑 2:
改变
pos.z = floor(pos.z);
收件人: pos.z = 楼层数(pos.z)+0.1;
部分解决了问题。最低层现在是正确的,但是现在有 2 个而不是 3 个不同的颜色(高度值)。
编辑 3:
问题似乎出在多次绘制几何体上。 即我实际的抽签看起来像:
for(uint i=0; i<render_queue.size(); i++)
{
Object_3D *render_data = render_queue[i];
//Render multiple instances of the current object
multi_render(render_data->VAO, &(render_data->VBOs),
&(render_data->types), render_data->layouts,
render_data->mesh_indices, render_data->render_instances);
}
void Renderer::multi_render(GLuint VAO, vector<GLuint> *VBOs,
vector<GLuint> *buffer_types, GLuint layout_num,
GLuint index_num, GLuint instances)
{
//error check
if(VBOs->size() != buffer_types->size())
{
cerr << "Mismatching VBOs's and buffer_types sizes" << endl;
return;
}
//Bind Vertex array object and rendering rpogram
glBindVertexArray(VAO);
glUseProgram(current_program);
//enable shader layouts
for(int i=0; i<layout_num;i++)
glEnableVertexAttribArray(i);
//Bind VBO's storing rendering data
for(uint i=0; i<buffer_types->size(); i++)
{
if((*buffer_types)[i]==GL_SHADER_STORAGE_BUFFER)
{
glBindBuffer((*buffer_types)[i], (*VBOs)[i]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, (*VBOs)[i]);
}
}
//Draw call
glDrawElementsInstanced(GL_TRIANGLES, index_num, GL_UNSIGNED_INT, (void*)0, instances);
}
似乎由于一次渲染场景的多个子集,我最终在 2 个不同的绘制调用中将不同的立方体映射到同一体素。
我找到问题了
由于我的几何体与体素网格 1 比 1 匹配。不同的层可以映射到相同的体素,导致它们在同一层重叠。
修改片段着色器如下:
#version 450
layout(location = 0) in vec3 position; //(x,y,z) coordinates of a vertex
layout(std430, binding = 3) buffer instance_buffer
{
vec4 cubes_info[];//first 3 values are position of object
};
out vec3 normalized_pos;
out float test;
uniform float width = 128;
uniform float depth = 128;
uniform float height = 128;
uniform float voxel_size = 1;
uniform float level=0;
void main()
{
vec4 pos = (vec4(position, 1.0) + vec4(vec3(cubes_info[gl_InstanceID]),0));
pos.x = (2.f*pos.x-width)/(width);
pos.y = (2.f*pos.y-depth)/(depth);
pos.z = cubes_info[gl_InstanceID].z;
test = pos.z + 1;
pos.z -= level;
if(pos.z >=0 && pos.z < 0.999f)
pos.z = 1;
else
pos.z = 2;
gl_Position = pos;
normalized_pos = vec3(pos);
}
修复了问题。
if 语句检查保证丢弃可能映射到当前层的不同层的几何图形。
可能有更好的方法来做到这一点。所以我会接受任何以更优雅的方式产生等效结果的答案。
这是第 0 层现在的样子:
这是第 2 层的样子: