由于缺乏对纹理坐标的理解,场景体素化不起作用

Posted

技术标签:

【中文标题】由于缺乏对纹理坐标的理解,场景体素化不起作用【英文标题】:Scene voxelization not working due to lack of comprehension of texture coordinates 【发布时间】:2018-03-07 22:05:20 【问题描述】:

目标是采用任意几何形状并创建包含场景体素近似值的 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();

其中“级别”对应于当前层。

然后在顶点着色器中我们尝试如下创建一个单层;

#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 个明显问题是:

一个图层不应该有多个灰色调,只有一个(因为每个图层对应不同的高度,所以不应将多个高度渲染到同一图层)

第 2 层的最暗部分看起来像第 0 层的样子(即没有“孔”的填充形状)。因此,我不仅似乎将多个高度渲染到同一层,而且在渲染时似乎我的偏移量为 2,这是不应该发生的。

有人知道问题可能是什么吗?

编辑:

如果有人想知道立方体的尺寸为 [1,1,1] 并且它们的坐标系与纹理对齐。即第一个立方体的底部,左侧,前角位于(0,0,0)

编辑 2:

变化

pos.z = floor(pos.z); 

到: pos.z = 地板(pos.z)+0.1;

部分解决了问题。最低层现在是正确的,但是现在不是 3 种不同的颜色(高度值),而是 2 种。

编辑 3:

问题似乎来自多次绘制几何图形。 即我的实际draw clal看起来像:

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 个不同的绘制调用中将不同的立方体映射到同一个体素。

【问题讨论】:

您的实际绘图调用是什么样的?我假设您正在调用 glDrawArrays|ElementsInstanced,因为您正在从顶点着色器中的 gl_InstanceID 读取数据? 没错,我的实际绘制调用是一个实例化绘制调用,它在不同位置呈现相同的立方体网格。我将添加一些我刚刚遇到的问题的信息。 @Jay 问题已解决,但我对我的回答不满意。如果您有更好的建议,我将不胜感激。 【参考方案1】:

我已经解决了问题。

由于我的几何图形与体素网格 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 层的样子:

【讨论】:

切换到非实例化渲染可能很有用,这样您就可以查看 RenderDoc 中的每个实例。 IE。调用 glDrawElements N 次而不是调用 glDrawElementsInstanced 一次,并使用手动更新的统一而不是 gl_InstanceID。这样您就可以在 RenderDoc 中查看每个单独的绘图。

以上是关于由于缺乏对纹理坐标的理解,场景体素化不起作用的主要内容,如果未能解决你的问题,请参考以下文章

LWJGL VBO 三角形纹理坐标不起作用

在 Vue 项目中使 axios 全局化不起作用

OpenGL VBO球体纹理加载不起作用

【PCL】VoxelGrid体素化网格滤波器

绘制到纹理不起作用 LWJGL

为啥我的 OpenGL 纹理不起作用?