opengl学习-混合

2021-04-25  本文已影响0人  小杰66

不使用混合如何实现透明度

通过在片源着色器中添加if (texColor.a < 0.1) discard;来根据透明度的值判断是否丢弃片段,丢弃的片段不会被进一步处理,不会进入颜色缓冲。效果如下。

image.png

这里有个问题是草的顶部可以看到一个有色边框,这是因为当采样纹理边缘的时候,OpenGL会对边缘的值和纹理下一个重复的值进行插值(因为我们将它的环绕方式设置为了GL_REPEAT。)为了避免这个问题当我们使用alpha纹理的时候,要将纹理的环绕方式设置为GL_CLAMP_TO_EGDGE

使用混合

虽然可以直接丢弃片段,但我们还是不能渲染半透明的图像,只能要么渲染要么丢弃。要想渲染多个透明度级别的图像,需要启用混合。

启用混合

glEnable(GL_BLEND);

混合方程

C_result = C_source ∗ F_source + C_destination ∗ F_destination

片段着色器运行完成后,并且所有的测试都通过之后,这个混合方程才会应用到片段颜色输出与当前颜色缓冲中的值(当前片段之前储存的之前片段的颜色)上。源颜色和目标颜色将会由OpenGL自动设定,但源因子和目标因子的值可以由我们来决定。

设置源因子和目标因子

glBlendFunc(GLenum sfactor, GLenum dfactor)
glBlendFuncSeparate 可以为RGB和alpha通道分别设置不同的值
glBlendColor 可以设置常数颜色向量C_constant

可选值有

改变方程中源和目标部分的运算符

glBlendEquation(GLenum mode)允许我们设置运算符

开始使用混合

glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

image.png

可以发现最前面窗户的透明部分遮蔽了背后的窗户,因为写入深度缓冲时,深度缓冲不会检查片段是否是透明的,所以透明的部分会和其它值一样写入到深度缓冲中。结果就是窗户的整个四边形不论透明度都会进行深度测试。即使透明的部分应该显示背后的窗户,深度测试仍然丢弃了它们。
要想保证窗户中能够显示它们背后的窗户,我们需要首先绘制背后的这部分窗户。也就是我们必须先手动将窗户按照最远到最近来排序,再按照顺序渲染。

绘制顺序规则需要如下

  1. 先绘制所有不透明的物体。
  2. 对所有透明的物体排序。
  3. 按顺序绘制所有透明的物体。

排序透明物体的一种方法是,从观察者视角获取物体的距离。这可以通过计算摄像机位置向量和物体的位置向量之间的距离所获得。
添加代码根据举例排序然后按顺序绘制

  std::map<float, glm::vec3> sorted;
        for (unsigned int i = 0; i < vegetation.size(); i++) {
            float distance = glm::length(camera.Position - vegetation[i]);
            sorted[distance] = vegetation[i];
        }
image.png

按照距离排序物体这种方法并没有考虑旋转、缩放或者其它的变换,奇怪形状的物体需要一个不同的计量,而不是仅仅一个位置向量。
在场景中排序物体是一个很困难的技术,更高级的技术有次序无关透明度(Order Independent Transparency, OIT)。

上一篇下一篇

猜你喜欢

热点阅读