OpenGL中Z缓冲区的乱序

问题描述 投票:0回答:1

我正在使用C ++开发OpenGL应用程序。这是一个距离较大且几何形状较大的空间场景,因此我使用的是对数深度标度。我已经在下面包含了代码的基础知识。本质上,我似乎无法正确进行深度测试。下图应使立方体出现在灰色球体之前。此外,您可以看到后面较大球体上的三角形的深度排序不正确。

 B=

这是我在应用程序中初始化深度缓冲区的方式(我正在使用SDL2和Glew)。我想念什么吗?

(一些附加信息,蓝色球体的直径为650000个单位,立方体的宽度为100个单位,灰色球体的直径为1000个单位)

#include <iostream.h>
#include <GL/glew.h>
#include <SDL.h>
#include <SDL_opengl.h>
#include <glm/mat4x4.hpp>

int main() {
  // Set up the window
  SDL_Init(SDL_INIT_VIDEO);
  SDL_GL_SetAttribute (SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
  SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3); //OpenGL 3+
  SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3); //OpenGL 3.3
  SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); //OpenGL core profile

  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

  displayWindow = SDL_CreateWindow(GAME_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)screenWidth, (int)screenHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

  SDL_GLContext context = SDL_GL_CreateContext(displayWindow);
  // SDL_GL_MakeCurrent(displayWindow, context);

  SDL_GL_SetSwapInterval( 1 );

  glewExperimental = GL_TRUE; 
  GLenum glewError = glewInit();
  if( glewError != GLEW_OK ) {
    std::cout << "Error Initializing GLEW" << std::endl;
    exit(1);
  }

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  // Enable Depth Buffering
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);
}

这里是顶点着色器:

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

uniform vec3 lightPosition;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix; 
uniform mat4 projectionMatrix;
uniform mat4 normalMatrix;

out vec3 Normal_camera;
out vec3 LightDirection_camera;
out vec3 Position_global;
out vec3 EyeDirection_camera;
out float logz;

void main()
{
  // vec3 lightPosition = vec3(1, 1, 0);
  // Position of the vertex, in worldspace : modelMatrix * position
  Position_global = (modelMatrix * vec4(position, 1)).xyz;

  // Vector that goes from the vertex to the camera, in camera space.
  // In camera space, the camera is at the origin (0,0,0).
  vec3 Position_camera = (viewMatrix * vec4(Position_global, 1)).xyz;
  EyeDirection_camera = (vec4(0, 0, 0, 0) - vec4(Position_camera, 1)).xyz;

  // Vector that goes from the vertex to the light, in camera space. M is ommited because it's identity.
  vec3 LightPosition_camera = (viewMatrix * vec4(lightPosition, 1)).xyz;
  LightDirection_camera = LightPosition_camera + EyeDirection_camera;

  // Normal of the the vertex, in camera space
  Normal_camera = (modelMatrix * vec4(normal, 0)).xyz;
  // Only correct if ModelMatrix does not scale the model ! Use its inverse transpose if not

  gl_Position = projectionMatrix * vec4(Position_camera, 1);
  logz = 0.0f;
  float ZNEAR = 0.0001;
    float ZFAR = 1000000.0;
    float FCOEF = 2.0 / log2(ZFAR + 1.0);
  logz = FCOEF;
    gl_Position.z = log2(max(ZNEAR, 1.0 + gl_Position.w)) * FCOEF - 1.0;
}

最后是片段着色器:

#version 330 core
uniform vec4 color;
uniform float lightPower;
uniform vec3 lightPosition;
uniform vec3 lightColor;

in vec3 Normal_camera;
in vec3 LightDirection_camera;
in vec3 Position_global;
in vec3 EyeDirection_camera;
in float logz;

out vec4 FragColor;

void main() {
  vec3 n = normalize(Normal_camera);
  vec3 l = normalize(lightPosition - Position_global);
  float cosTheta = clamp(dot(n, l), 0.0, 1.0);
  float distance = length( lightPosition - Position_global );

  // Eye vector (towards the camera)
    vec3 E = normalize(EyeDirection_camera);
    // Direction in which the triangle reflects the light
    vec3 R = reflect(-l,n);
    // Cosine of the angle between the Eye vector and the Reflect vector,
    // clamped to 0
    //  - Looking into the reflection -> 1
    //  - Looking elsewhere -> < 1
    float cosAlpha = clamp( dot( E,R ), 0.0, 1.0);
  float specularStrength = 0.3;
  float shininess = 16.0;
  float ambientStrength = 0.3;
  float sqDistance = distance * distance;

  vec3 MaterialAmbientColor = ambientStrength * lightColor;
  //* lightPower / sqDistance;  
  vec3 MaterialDiffuseColor = lightColor * lightPower * cosTheta / sqDistance;
  vec3 MaterialSpecularColor = specularStrength * lightColor * lightPower * pow(cosAlpha, shininess) / sqDistance;

  vec4 c = color * vec4(MaterialAmbientColor + MaterialDiffuseColor + MaterialSpecularColor, 1);
  FragColor = c;
  gl_FragDepth = logz;

  // Later on, I assign glm::perspective(radians(45.0f), SCREEN_HEIGHT/SCREEN_WIDTH, 1.0f, 1000.0f) to the perspective uniform
}
c++ opengl sdl glm-math
1个回答
2
投票

似乎您的顶点着色器将logz设置为常数,然后将其传递给片段着色器,然后片段着色器将其分配给gl_FragDepth。因此,所有片段的深度大致相同。

我会尝试从顶点着色器中删除所有特殊的对数数学,而是在片段着色器中全部执行。 OpenGL执行透视校正的插值,因此希望顶点着色器的传出Z介于-W和+ W之间。

© www.soinside.com 2019 - 2024. All rights reserved.