OpenGL半透明四边形伪影问题

3

我现在正在尝试使我的水纹理半透明。我已经添加了以下混合参数:

void Application::initialiseOpenGL() {
  printf("Initialising OpenGL context\n");
  context = SDL_GL_CreateContext(window);
  assertFatal(context != NULL, "%s\n", SDL_GetError());
  SDL_GL_SetSwapInterval(0);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_DEPTH_TEST);
  // glEnable(GL_CULL_FACE);
  // glCullFace(GL_BACK);
}

从一侧看,我的水看起来很好:

enter image description here

然而,从另一侧看,它似乎覆盖了已经渲染的四边形:

enter image description here

这是水下的样子:

enter image description here

问题可能出在哪里?

这是我的着色器:

#version 300 es
layout(location = 0) in vec3 position;
layout(location = 1) in float vertexFaceIndex;
layout(location = 2) in vec2 vertexUV;

out float fragmentFaceIndex;
out vec2 fragmentUV;
out float visibility;

uniform mat4 view;
uniform mat4 viewProjection;
uniform float currentTime;

const float fogDensity = 0.005;
const float fogGradient = 5.0;

void main() {
  fragmentFaceIndex = vertexFaceIndex;
  fragmentUV = vertexUV;
  float distance = length(vec3(view * vec4(position, 1.0)));
  visibility = exp(-1.0f * pow(distance * fogDensity, fogGradient));
  visibility = clamp(visibility, 0.0, 1.0);
  if(vertexFaceIndex == 6.0f) {
    float yVal = position.y - 0.4 +
    min(0.12 * sin(position.x + currentTime / 1.8f) + 0.12 * sin(position.z + currentTime / 1.3f), 0.12);
    gl_Position = viewProjection * vec4(vec3(position.x, yVal, position.z), 1.0);
  }
  else
    gl_Position = viewProjection * vec4(position, 1.0);
}

#version 300 es
precision mediump float;
uniform sampler2D atlas;
out vec4 color;

in float fragmentFaceIndex;
in vec2 fragmentUV;
in float visibility;

const float ambientStrength = 1.1f;
const float diffuseStrength = 0.3f;

const vec3 lightDirection = vec3(0.2f, -1.0f, 0.2f);
const vec4 skyColor = vec4(0.612, 0.753, 0.98, 1.0);
const vec3 lightColor = vec3(1.0f, 0.996f, 0.937f);
const vec3 ambientColor = lightColor * ambientStrength;
// Face normals have been manually verified...
const vec3 faceNormals[7] = vec3[7](
  vec3(0.0f, 0.0f, 1.0f),
  vec3(0.0f, 0.0f, -1.0f),
  vec3(0.0f, 1.0f, 0.0f),
  vec3(0.0f, -1.0f, 0.0f),
  vec3(-1.0f, 0.0f, 0.0f),
  vec3(1.0f, 0.0f, 0.0f),
  vec3(0.0f, 1.0f, 0.0f)
);

void main() {
  vec4 textureFragment = texture(atlas, fragmentUV).rgba;
  if(textureFragment.a < 0.5) discard;
  float diffuseFactor = max(dot(faceNormals[int(fragmentFaceIndex)], normalize(-1.0f * lightDirection)), 0.0) * diffuseStrength;
  vec3 diffuseColor = diffuseFactor * lightColor;
  color = vec4((ambientColor + diffuseColor) * textureFragment.rgb, textureFragment.a);
  color = mix(skyColor, color, visibility);
}

1个回答

4

如果存在多个重叠的半透明多边形,使用这种多边形渲染方法时,半透明多边形必须按照后到前的顺序绘制。

如果不进行排序,仅使用深度缓冲区(z-buffer)无法正确地呈现包含半透明多边形的场景。

你所观察到的问题是因为水面多边形先被绘制,而其后面的方块随后被绘制,但没有像素被呈现,因为 z-buffer 已经被设置为水平面。即使在绘制水面时禁用 z-buffer 更新也不起作用,因为这种情况下后面绘制的水下方块会以普通颜色出现。

水面应该最后绘制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接