为啥正面剔除用 OpenGL 渲染立方体?

Posted

技术标签:

【中文标题】为啥正面剔除用 OpenGL 渲染立方体?【英文标题】:Why are the front faces culled rendering a cube with OpenGL?为什么正面剔除用 OpenGL 渲染立方体? 【发布时间】:2020-07-19 15:04:56 【问题描述】:

我正在编写一个显示一些图元的 OpenGL 3.3 程序。灯光很简单,只是漫反射和环境光。

立方体顶点着色器。

#version 440 core

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 a_normal;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec3 normal;
out vec3 fragpos;

void main(void)

    fragpos = vec3(model * vec4(position, 1.0));
    
    gl_Position = projection * view * vec4(fragpos, 1.0);
    normal = a_normal;

立方体片段着色器。

#version 440 core

out vec4 frag_color;

in vec3 normal;
in vec3 fragpos; 

uniform vec4 color;

struct light_source

    vec3 position;
    vec3 color;
    bool enable;
;

uniform light_source light0;

vec3 calc_diffuse_light(vec3 light_position, vec3 light_color)

    // ambient
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * light_color;
    
    // diffuse 
    vec3 norm = normalize(normal);
    vec3 light_dir = normalize(light_position - fragpos);
    float diff = max(dot(norm, light_dir), 0.0);
    vec3 diffuse = diff * light_color;
            
    return (ambient + diffuse) * color.xyz;


void main(void)

    vec3 result = vec3(0.0);
    if (light0.enable)
        result += calc_diffuse_light(light0.position, light0.color);
    
    frag_color = vec4(result, 1.0);

立方体设置。

#include "gl_cube_model.h"
#include "gl_lights.h"


cube_model::cube_model(float size, const glm::vec3& position, const glm::vec4& color) :
    model_base(position),
    m_color(color)

    float halfwidth = size / 2.0f;
    float vertices[] =
    
        //  Three position components + normals.

        // front face
        -halfwidth, -halfwidth, halfwidth, 0.0f, 0.0f, 1.0f, // front bottom left
        -halfwidth,  halfwidth, halfwidth, 0.0f, 0.0f, 1.0f, // front top left
         halfwidth,  halfwidth, halfwidth, 0.0f, 0.0f, 1.0f, // front top right
         halfwidth, -halfwidth, halfwidth, 0.0f, 0.0f, 1.0f, // front bottom right
        -halfwidth, -halfwidth, halfwidth, 0.0f, 0.0f, 1.0f, // front bottom left
         halfwidth,  halfwidth, halfwidth, 0.0f, 0.0f, 1.0f, // front top right

        // back face
        -halfwidth, -halfwidth, -halfwidth, 0.0f, 0.0f, -1.0f, // back bottom left
        -halfwidth,  halfwidth, -halfwidth, 0.0f, 0.0f, -1.0f, // back top left
         halfwidth,  halfwidth, -halfwidth, 0.0f, 0.0f, -1.0f, // back top right
         halfwidth, -halfwidth, -halfwidth, 0.0f, 0.0f, -1.0f, // back bottom right
        -halfwidth, -halfwidth, -halfwidth, 0.0f, 0.0f, -1.0f, // back bottom left
         halfwidth,  halfwidth, -halfwidth, 0.0f, 0.0f, -1.0f, // back top right

         // left face
         -halfwidth, -halfwidth, -halfwidth, -1.0f, 0.0f, 0.0f, // back bottom left
         -halfwidth,  halfwidth, -halfwidth, -1.0f, 0.0f, 0.0f, // back top left
         -halfwidth,  halfwidth, halfwidth,  -1.0f, 0.0f, 0.0f, // front top left
         -halfwidth, -halfwidth, halfwidth,  -1.0f, 0.0f, 0.0f, // front bottom left
         -halfwidth, -halfwidth, -halfwidth, -1.0f, 0.0f, 0.0f, // back bottom left
         -halfwidth,  halfwidth, halfwidth,  -1.0f, 0.0f, 0.0f, // front top left

         // right face
         halfwidth, -halfwidth, halfwidth,  1.0f, 0.0f, 0.0f, // front bottom right
         halfwidth,  halfwidth, halfwidth,  1.0f, 0.0f, 0.0f, // front top right
         halfwidth,  halfwidth, -halfwidth, 1.0f, 0.0f, 0.0f, // back top right
         halfwidth, -halfwidth, -halfwidth, 1.0f, 0.0f, 0.0f, // back bottom right
         halfwidth, -halfwidth, halfwidth,  1.0f, 0.0f, 0.0f, // front bottom right
         halfwidth,  halfwidth, -halfwidth, 1.0f, 0.0f, 0.0f, // back top right

         // top face
         -halfwidth,  halfwidth, halfwidth,  0.0f, 1.0f, 0.0f, // front top left
         -halfwidth,  halfwidth, -halfwidth, 0.0f, 1.0f, 0.0f, // back top left
          halfwidth,  halfwidth, -halfwidth, 0.0f, 1.0f, 0.0f, // back top right
          halfwidth,  halfwidth, halfwidth,  0.0f, 1.0f, 0.0f, // front top right
         -halfwidth,  halfwidth, halfwidth,  0.0f, 1.0f, 0.0f, // front top left
          halfwidth,  halfwidth, -halfwidth, 0.0f, 1.0f, 0.0f, // back top right

         // bottom face
         -halfwidth, -halfwidth, halfwidth,  0.0f, -1.0f, 0.0f, // front bottom left
         -halfwidth, -halfwidth, -halfwidth, 0.0f, -1.0f, 0.0f, // back bottom left
          halfwidth, -halfwidth, -halfwidth, 0.0f, -1.0f, 0.0f, // back bottom right
          halfwidth, -halfwidth, halfwidth,  0.0f, -1.0f, 0.0f, // front bottom right
         -halfwidth, -halfwidth, halfwidth,  0.0f, -1.0f, 0.0f, // front bottom left
          halfwidth, -halfwidth, -halfwidth, 0.0f, -1.0f, 0.0f, // back bottom right
    ;

    glDisable(GL_CULL_FACE);

    // Generate VAO.
    glGenVertexArrays(1, &m_vao);
    glBindVertexArray(m_vao);

    // Generate VBO.
    glGenBuffers(1, &m_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // Vertex position attribute.
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // Vertex normal attribute.
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (GLvoid*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    string vert_source;
    if (!read_file_text(SHADER_DIR + "pos_norm.vert", vert_source))
        throw runtime_error("error loading vert shader");

    string frag_source;
    if (!read_file_text(SHADER_DIR + "flat_shade_light.frag", frag_source))
        throw runtime_error("error loading frag shader");

    m_sha.init_from_str(vert_source, frag_source);


cube_model::~cube_model()

    glDeleteVertexArrays(1, &m_vao);
    glDeleteBuffers(1, &m_vbo);


void cube_model::render(const glm::mat4& projection, const glm::mat4& view, const std::shared_ptr<gl_lights>& lights)

    m_sha.use();

    glBindVertexArray(m_vao);
    glUniformMatrix4fv(m_sha.get_uniform("model"), 1, GL_FALSE, glm::value_ptr(m_model));
    glUniformMatrix4fv(m_sha.get_uniform("view"), 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(m_sha.get_uniform("projection"), 1, GL_FALSE, glm::value_ptr(projection));
    glUniform4fv(m_sha.get_uniform("color"), 1, glm::value_ptr(m_color));

    glUniform3fv(m_sha.get_uniform("light0.position"), 1, glm::value_ptr(lights->position(0)));
    glUniform3fv(m_sha.get_uniform("light0.color"), 1, glm::value_ptr(lights->color(0)));
    int enabled = (lights->is_enabled(0) ? 1 : 0);
    glUniform1iv(m_sha.get_uniform("light0.enable"), 1, &enabled);

    glDrawArrays(GL_TRIANGLES, 0, 6 * 6);
    glFinish();

请注意glDisable(GL_CULL_FACE);。看起来背面和正面剔除不应该归咎于此,并且在调用 cube_model::render 的代码中,深度缓冲区被清除,所以我也不能责怪深度缓冲。

【问题讨论】:

这只是一个猜测,但很可能您错过了启用Depth Test:glEnable(GL_DEPTH_TEST)。启用深度测试后,您还必须清除深度缓冲区:glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 是的,Rabbid76,这就是答案。我认为默认情况下启用了深度缓冲,但显然没有。 【参考方案1】:

您错过了启用Depth Test。

glEnable(GL_DEPTH_TEST)

启用深度测试后,您也必须清除深度缓冲区:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

【讨论】:

【参考方案2】:

您需要使用深度测试。打电话 glEnable(GL_DEPTH_TEST) 在你的循环开始之前。

然后您需要每帧清除深度缓冲区,否则即使场景发生变化,每次渲染时也会使用相同的深度缓冲区。在主循环中使用它: glClear(GL_DEPTH_BUFFER_BIT);

【讨论】:

以上是关于为啥正面剔除用 OpenGL 渲染立方体?的主要内容,如果未能解决你的问题,请参考以下文章

Modern OpenGL - 渲染矩体/矩形体/立方体/正方体/长方体

Opengl:渲染到立方体贴图?

Opengl 3d立方体不渲染

在 OpenGL 中渲染透明块

OpenGL:渲染天空盒立方体贴图问题

渲染动态立方体贴图 (OpenGL)