OpenGL半透明四边形神器

Posted

技术标签:

【中文标题】OpenGL半透明四边形神器【英文标题】:OpenGL translucent quad artifact 【发布时间】:2020-07-18 20:56:22 【问题描述】:

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

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);

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

但是,从另一方面来看,它似乎覆盖了已经渲染的四边形:

这是水下的样子:

这可能是什么问题?

这些是我的着色器:

#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);

【问题讨论】:

见OpenGL - How to create Order Independent transparency? 【参考方案1】:

当使用这种多边形渲染方法时,如果有多个重叠的半透明多边形,则半透明多边形必须最后绘制,并且按从后到前的顺序。

如果不进行这种排序,z-buffer 不足以正确渲染包含半透明多边形的场景。

您观察到的问题是因为首先绘制了水多边形,然后绘制了它后面的块但没有渲染像素,因为 z-buffer 已经设置为水位。绘制水时禁用 z-buffer 更新也不起作用,因为在这种情况下,稍后绘制的水下方块将以正常颜色显示。

你需要最后抽水。

【讨论】:

以上是关于OpenGL半透明四边形神器的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL:渲染具有大量纹理透明度的模型,没有绘制顺序?

OpenCV:如何混合多个不同颜色的半透明多边形?

在 OpenGL 中渲染一个*填充的*半透明立方体

OpenGL GLSL 通过任意形状混合两个纹理

如何改变ggplot中椭圆的半透明度?

iOS - 导航栏设置半透明或取消半透明