为啥正面剔除用 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 渲染立方体?的主要内容,如果未能解决你的问题,请参考以下文章