5

向我解释我做错了什么。我已将 3d 模型加载到自编码的 opengl 渲染(v 3.3)并尝试使用顶点着色器使其像 xray 效果一样透明:

#version 330

attribute vec3 coord3d;
attribute vec2 texcoord;
varying vec2 f_texcoord;

uniform mat4 projectionMatrix; 
uniform mat4 modelViewMatrix; 

layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec4 inColor;

smooth out vec4 theColor;

void main()
{
    gl_Position = projectionMatrix*modelViewMatrix*vec4(inPosition, 1.0);
    theColor = vec4(0.0,0.2,0.4,0.4);
    f_texcoord = texcoord;

}

该模型在编辑器中进行了三角剖分并绘制:

glDrawArrays(GL_TRIANGLE_FAN, 0, (vertices.at(i)->size()/3));

如果我使用

glEnable(GL_ALPHA_TEST);
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0); 

我看到一些不需要的三角形或线条:

如果我在没有深度测试的情况下这样做,我会在面内看到多个三角形(我不想要):

我怎样才能摆脱不需要的效果并像 Google Sketchup 那样实现 X 射线效果

如果我希望所有模型都透明,我应该实施深度排序吗?

我该如何实现:

GS

4

2 回答 2

10

问题1:

首先,不要禁用深度测试。在混合之前执行深度测试以确保正确丢弃片段,即使启用了混合也是如此。有关每个片段操作及其执行顺序的更多信息,请参阅核心 OpenGL 4.4 规范的第 17.3 节。

当你禁用深度测试时,除非绘制调用的顺序绝对正确,否则你会得到意想不到的结果,从而违背了深度缓冲的目的。即使你得到了正确的命令,你也不能期望所有的副作用都会消失,并且试图按照你需要的方式对每个命令进行排序,除了最简单的程序之外,它对任何东西都不起作用。

考虑以下非常简单的示例:

在此处输入图像描述

您可以看到 3 个四边形,最远的可视化通常的 tex 坐标空间 (s,t E [0, 1]),一个与后者混合的蓝色四边形,以及一个应该在前面的不透明红色四边形。显然,红色四边形不在前面,尽管深度值另有说明。同样明显的是,目的是不要将蓝色四边形与红色四边形混合。在蓝色四边形之后渲染红色四边形似乎可以解决问题,但如果您绘制另一个应该位于蓝色和红色四边形后面四边形,它只会出现在顶部并禁用深度测试。这都是错误的。

在此处输入图像描述

黄色四边形掩盖了一切,尽管它应该在红色和蓝色四边形后面。正确的图像如下,纯粹通过启用深度测试获得:

在此处输入图像描述

我的一般建议是:除非您有充分的理由禁用深度测试,例如在渲染叠加层并且不想打扰深度缓冲区时,请启用深度测试。

注意:深度缓冲不能解决您通常必须将非透明几何体从后到前排列以获得正确结果的问题!如果您想在尝试模拟透明度时完全独立于排序,请在许多关于顺序无关透明度的论文中寻找通常的嫌疑人。

问题2:

从它的外观来看,我假设您使用以下混合功能:

gl::BlendFunc (gl::ONE, gl::ONE);

或任何导致稳定,连续积累价值的东西,例如

gl::BlendFunc (gl::SRC_ALPHA, gl::ONE);

以及 RGB 和 alpha 分量的默认混合方程:

gl::BlendEquation (gl::FUNC_ADD);

如果不是这种情况,请添加说明实际值的评论,以便我可以重新检查并可能编辑我的建议。以下仍然适用,因为颜色不会说谎。;)

您的第二个问题是由于投影下的z-fighting。有些片段被正确丢弃,有些则没有。由于您显然具有在某些地方完全重合的重复面,因此对于一个片段,可能会为第一个面生成稍高的深度值。渲染第二个面时,会生成稍低的深度值,并且片段会通过,导致在实际上应该没有的地方过度绘制。

第一个片段已经完成了所有的魔法,混合值被写入帧缓冲区,深度值被写入深度缓冲区,即您有一个通过所有测试并与背景混合的面部片段。现在是第二个片段,它没有被丢弃,因为深度值略低,并且再次与帧缓冲区中已经混合的颜色混合。由于添加剂混合,您会得到观察到的结果。我在以下示例中使用您使用的相同颜色和 alpha 值重现了这种情况:

在此处输入图像描述

问题 3:您的模型似乎有很多重复的面孔,一般来说,三角剖分看起来很糟糕。你真的应该重做。理解和使用混合已经够难了。不要用次优数据使其复杂化。

于 2013-09-19T15:23:50.587 回答
0

渲染透明对象的典型过程如下:

  1. 绘制不透明对象
  2. 将深度掩码设置为 false:glDepthMask(GL_FALSE);
  3. 将透明三角形从后到前排序。
  4. 按此顺序渲染透明。
  5. 将深度掩码设置为 true:glDepthMask(GL_TRUE);

这是您确保获得准确结果的唯一方法。不幸的是,深度排序既复杂又耗时。有时,您可以跳过它并获得“足够好”的结果。还有一些用于订单独立透明度的技术,可以提供相当好的结果。

在您的情况下,看起来深度排序将是不可避免的。

编辑:绘制透明对象时,您不能完全启用深度测试,因为您绘制的任何内容后面的像素都会被覆盖。您也不能完全禁用它,因为这样您就可以看到透明对象,即使它们位于不透明对象后面。解决方案是仍然检查您绘制的透明片段是否被更接近(不透明)的片段遮挡,但不保存透明片段的深度,以便以后不会检查它们。用于告诉 OpenGL 停止/开始保存深度值的方法是glDepthMask().

于 2013-09-19T20:21:42.280 回答