OpenGL:混合

news/2025/3/10 5:46:23/文章来源:https://www.cnblogs.com/warren-j1an/p/18238701

OpenGL中,混合(Blending)通常是实现物体透明度(Transparency)的一种技术。透明就是说一个物体(或者其中的一部分)不是纯色(Solid Color)的,它的颜色是物体本身的颜色和它背后其它物体的颜色的不同强度结合。一个有色玻璃窗是一个透明的物体,玻璃有它自己的颜色,但它最终的颜色还包含了玻璃之后所有物体的颜色。这也是混合这一名字的出处,我们混合(Blend)(不同物体的)多种颜色为一种颜色。所以透明度能让我们看穿物体。

丢弃片段

我们首先考虑一种最简单的情况,全透明纹理。在这种情况下,纹理中要么是全透明的,要么是完全不透明的图案。当着这种纹理被加载时我们可以简单地保留不透明的部分,并将透明的部分丢弃。幸运的是,在片段着色器中存在着discard语法,它会保证片段不会被进一步处理,所以就不会进入颜色缓冲。其使用如下所示:

#version 330 core
out vec4 FragColor;in vec2 TexCoords;uniform sampler2D texture1;void main()
{vec4 texColor = texture(texture1, TexCoords);if(texColor.a < 0.1)discard;FragColor = texColor;
}

混合

虽然丢弃片段简单实用,但是它不能让我们渲染半透明的图像。对于纹理中的片段,要么渲染,要么完全丢弃它。要想渲染有多个透明度级别的图像,我们需要启用混合(Blending)。和OpenGL大多数的功能一样,我们可以启用GL_BLEND来启用混合:

glEnable(GL_BLEND);

OpenGL中的混合是通过下面这个方程来实现的:

\[\overline{C}_{result} = \overline{C}_{source} * F_{source} + \overline{C}_{destination} * F_{destination}. \]

  • \(\overline{C}_{source}\):源颜色向量。这是源自纹理的颜色向量。
  • \(\overline{C}_{destination}\):目标颜色向量。这是当前储存在颜色缓冲中的颜色向量。
  • \(F_{source}\):源因子值。指定了alpha值对源颜色的影响。
  • \(F_{destination}\):目标因子值。指定了alpha值对目标颜色的影响。

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

image

我们有两个方形,我们希望将这个半透明的绿色方形绘制在红色方形之上。红色的方形将会是目标颜色(所以它应该先在颜色缓冲中),我们将要在这个红色方形之上绘制这个绿色方形。

问题来了:我们将因子值设置为什么?

嘛,我们至少想让绿色方形乘以它的alpha值,所以我们想要将\(F_{source}\)设置为源颜色向量的alpha值,也就是0.6。接下来就应该清楚了,目标方形的贡献应该为剩下的alpha值。如果绿色方形对最终颜色贡献了60%,那么红色方块应该对最终颜色贡献了40%,即1.0 - 0.6。所以我们将\(F_{destination}\)设置为1减去源颜色向量的alpha值。这个方程变成了:

\[\overline{C}_{result} = \left(\begin{array}{c} 0.0 \\ 1.0 \\ 0.0 \end{array} \right) * 0.6 + \left(\begin{array}{c} 1.0 \\ 0.0 \\ 0.0 \end{array} \right) * (1 - 0.6). \]

结果就是重叠方形的片段包含了一个60%绿色,40%红色的一种脏兮兮的颜色:
image

最终的颜色将会被储存到颜色缓冲中,替代之前的颜色。

这样子很不错,但我们该如何让OpenGL使用这样的因子呢?正好有一个专门的函数,叫做glBlendFunc

glBlendFunc(GLenum sfactor, GLenum dfactor)函数接受两个参数,来设置源和目标因子。OpenGL为我们定义了很多个选项,我们将在下面列出大部分最常用的选项。注意常数颜色向量\(\overline{C}_{constant}\)可以通过glBlendColor函数来另外设置。

为了获得之前两个方形的混合结果,我们需要使用源颜色向量的alpha作为源因子,使用1−alpha
作为目标因子。这将会产生以下的glBlendFunc

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

也可以使用glBlendFuncSeparate为RGB和alpha通道分别设置不同的选项:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);

这个函数和我们之前设置的那样设置了RGB分量,但这样只能让最终的alpha分量被源颜色向量的alpha值所影响到。

OpenGL甚至给了我们更多的灵活性,允许我们改变方程中源和目标部分的运算符。当前源和目标是相加的,但如果愿意的话,我们也可以让它们相减。glBlendEquation(GLenum mode)允许我们设置运算符,它提供了三个选项:

GL_FUNC_ADD:默认选项,将两个分量相加:\(\overline{C}_{result} = Src + Dst.\)

GL_FUNC_SUBTRACT:将两个分量相减: \(\overline{C}_{result} = Src - Dst.\)

GL_FUNC_REVERSE_SUBTRACT:将两个分量相减,但顺序相反: \(\overline{C}_{result} = Dst - Src.\)

通常我们都可以省略调用glBlendEquation,因为GL_FUNC_ADD对大部分的操作来说都是我们希望的混合方程,但如果你真的想打破主流,其它的方程也可能符合你的要求。

不要打乱渲染顺序

渲染半透明纹理时会出现在不同深度下的半透明纹理可能丢失的情况,因此要保持一定的渲染顺序,一般来说都是由远及近的顺序。普通不需要混合的物体仍然可以使用深度缓冲正常绘制,所以它们不需要排序。但我们仍要保证它们在绘制(排序的)透明物体之前已经绘制完毕了。当绘制一个有不透明和透明物体的场景的时候,大体的原则如下:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/721873.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

下水道拾的沟槽的文章

wow天色将晚,在我看着你的眼里色彩斑斓 五月的气候合往年一样闷热,二中的晚自习太静,于是闲下来了,止不住地去向,好像又来一轮毕业的时候。小学时,谈起毕业总是很害怕的,那时觉得毕业时候一定是要大哭一场,不然就算不上毕业结果那天也如同流水一般平淡地过去了,正如过…

P3756 [CQOI2017] 老C的方块 解题报告

P3756 [CQOI2017] 老C的方块 解题报告oj:https://gxyzoj.com/d/gxyznoi/p/P266 又是网格题,考虑染色:显然可以发现,每一个不合法的图形都可以被染成黄->蓝->特殊边->绿->红,且旋转后同样满足条件 推广到整个棋盘就是:所以是否可以将颜色编号,然后按照上述方法…

[stars-one] 星念轻小说下载器

原文地址: [stars-one] 星念轻小说下载器-Stars-One的杂货小窝 一款将在线轻小说保存到本地的下载工具 软件介绍小说单卷下载 小说全卷下载(需VIP) 多线程解析和下载 下载导出为epub文件 自动更新软件使用前需要进行用户登录(邮箱注册) 采用会员订阅制,PC版和Android版共用账号…

裁剪序列Cut the Sequence

首先,我们可以先想一想朴素算法,推出DP,i表示分了几段,则可以推出$$F[i]=min_{1<=j<=i}(f[j]+max_{j+1<=k<=i}(a[k]))$$点击查看代码memset(f,0x3f,sizeof f);f[0]=0;for(int i=1;i<=n;i++){for(int j=0;j<i;j++){int tmp=0;ll sum=0;for(int k=j+1;k<…

vits-simple-api搭建

根据vits-simple-api中文文档指南自行搭建后端 以下步骤均在windows平台cpu推理搭建为例选择你的vits模型(注意是vits!不是So-Vits Bert Vits2 Gpt Vits)建议去抱脸网搜索或者b站搜素以及自己训练.在vits-simple-api的路径的model目录下新建你下载模型的名字的文件夹将模型的js…

bili-emoji自定义表情包设置

使用图床上传图片.推荐使用聚合图床,简单免费 把图片的图床链接复制到一个txt文件中,如abc.txt 将abc.txt放到koishi目录的非node_modules\koishi-plugin-emojihub-bili文件夹中,如koishi\lumia\abc.txt 在插件界面填写要触发的命令以及路径如下图所示5.使用如下图所示

关于LTspice如何导入第三方的.lib文件进行仿真

转载自:https://bbs.eeworld.com.cn/thread-1265324-1-1.html 1.在芯片官网找到对应的PSPICE模型下载后,将.lib文件移入到路径下的sub文件夹中。(例如C:\Users\\username\Documents\LTspiceXVII\lib\sub) 2.将.lib文件拖入LTspice后右键单击.subckt后的芯片名称,选择Creat S…

OOP题目集4~6的总结

目录(一)前言 (二)作业介绍 (三)算法与代码 (四)PowerDesigner类图模型 (五)SourceMonitor代码分析 (六)自学内容 (七)总结一、前言介绍本篇博客的大致内容、写作目的、意义等本篇博客介绍如何使用Java语言基础和算法来解决题目问题,在此基础上进行对最近Java编…

前端使用 Konva 实现可视化设计器(13)- 折线 - 最优路径应用【思路篇】

这一章把直线连接改为折线连接,沿用原来连接点的关系信息。关于折线的计算,使用的是开源的 AStar 算法进行路径规划,启发方式为 曼哈顿距离,且不允许对角线移动。请大家动动小手,给我一个免费的 Star 吧~ 大家如果发现了 Bug,欢迎来提 Issue 哟~ github源码 gitee源码 示…

SpringBoot热部署设置

在使用SpringBoot进行开发过程中,我们往往会对代码进行反复修改并对项目进行部署查看效果,这时反复重启SpringBoot会很麻烦,因此使用热部署是提高开发效率的必备插件——“spring-boot-starter-test” <!--SpringBoot热部署依赖--> <dependency> <gr…

redis zset源码

zset底层是由hash字典和跳表实现的,字典存储member->分数的映射关系,这样根据membe查询score的 时间复杂度O为1 跳表可以理解为多个层级的有序链表,每个节点可能在不同层级上,通过在不同层级的跳跃查找,把查询时间复杂度降低到 Olgn 1.随机层数,只有0.25的概率升级层数…

C++U7-08-拓扑排序

拓扑:是指把实体抽象成与其大小形状无关的点,把连接实体的线路抽象成线,研究这些点线之间的相连关系。而表示点和线之间关系的图就被称为拓扑结构图。 拓扑学原本是一个数学概念,描述的是几何图形或空间在连续改变形状后还能保持不变的性质,它只考虑物体间的位置关系而不考…