当前位置: 首页 > news >正文

QT+OpenGL模板测试和混合

QT+OpenGL模板测试和混合

本篇完整工程见gitee:QtOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主

模板测试

当片段着色器处理完一个片段之后,模板测试会开始执行。和深度测试一样,它可能会丢弃片段,接下来被保留的片段会进入深度测试。

通常每个模板的值是8位的,所以每个像素/片段一共能有256种不同的模板值。

  • 启用模板缓冲的写入。
  • 渲染物体,更新模板缓冲的内容。
  • 禁用模板缓冲的写入。
  • 渲染(其它)物体,这次根据模板缓冲的内容丢弃特定的片段
// 启用模板缓冲
glEnable(GL_STENCIL_TEST);
// 清除模板缓冲
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样
glStencilMask(0x00); // 每一位在写入模板缓冲时都会变成0(禁用写入)

模板函数

一共有两个函数能够用来配置模板测试: glStenciFunc和glStencilOp

glStencilFunc(GLenum func, GLint ref, GLuint mask)
  • func:设置模板测试函数(Stencil Test Function)。这个测试函数将会应用到已储存的模板值上和glStencilFunc函数的ref值上。可用的选项有:GL_NEVER、GL_LESS、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL和GL_ALWAYS。它们的语义和深度缓冲的函数类似。
  • ref:设置了模板测试的参考值(Reference Value)。模板缓冲的内容将会与这个值进行比较。
  • mask:设置一个掩码,它将会与参考值和储存的模板值在测试比较它们之前进行与(AND)运算。初始情况下所有位都为1。

这个函数告诉opengl,只要一个片段的模板值等于1,它将会通过测试并被绘制,否则会被丢弃。但glStencilFunc仅仅描述了OpenGL应该对模板缓冲内筒做什么,而不是我们应该如何更新缓冲。

glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
  • sfail:模板测试失败时采取的行为。
  • dpfail:模板测试通过,但深度测试失败时采取的行为。
  • dppass:模板测试和深度测试都通过时采取的行为。
行为描述
GL_KEEP保持当前储存的模板值
GL_ZERO将模板值设置为0
GL_REPLACE将模板值设置为glStencilFunc函数设置的ref
GL_INCR如果模板值小于最大值则将模板值加1
GL_INCR_WRAP与GL_INCR一样,但如果模板值超过了最大值则归零
GL_DECR如果模板值大于最小值则将模板值减1
GL_DECR_WRAP与GL_DECR一样,但如果模板值小于0则将其设置为最大值
GL_INVERT按位翻转当前的模板缓冲值

默认情况下glStencilOp是设置为(GL_KEEP, GL_KEEP, GL_KEEP)的,所以不论任何测试的结果是如何,模板缓冲都会保留它的值。默认的行为不会更新模板缓冲,所以如果你想写入模板缓冲的话,你需要至少对其中一个选项设置不同的值。

物体轮廓

  1. 在绘制(需要添加轮廓的)物体之前,将模板函数设置为GL_ALWAYS,每当物体的片段被渲染时,将模板缓冲更新为1。
  2. 渲染物体。
  3. 禁用模板写入以及深度测试。
  4. 将每个物体缩放一点点。
  5. 使用一个不同的片段着色器,输出一个单独的(边框)颜色。
  6. 再次绘制物体,但只在它们片段的模板值不等于1时才绘制。
  7. 再次启用模板写入和深度测试。

代码展示:

void TurboOpenGLWidget::paintGL()
{model.setToIdentity();view.setToIdentity();projection.setToIdentity();glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glEnable(GL_DEPTH_TEST);glEnable(GL_STENCIL_TEST);glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);glStencilMask(0x00); // 禁止模板缓冲的写入// float time = m_time.elapsed() / 50.0;// model.rotate(time, 1.0f, 5.0f, 0.0f);shader_program_.bind();projection.perspective(camera_.getZoom(), float(width() / height()), near_, far_);view = camera_.getViewMatrix();shader_program_.setUniformValue("projection", projection);shader_program_.setUniformValue("view", view);shader_program_.setUniformValue("viewPos", camera_.getPosition());shader_program_.setUniformValue("spotLight.ambient",  QVector3D(0.7, 0.7, 0.7));shader_program_.setUniformValue("spotLight.diffuse",  QVector3D(0.9, 0.9, 0.9)); // 将光照调暗了一些以搭配场景shader_program_.setUniformValue("spotLight.specular", QVector3D(1.0, 1.0, 1.0));shader_program_.setUniformValue("spotLight.position",  camera_.getPosition());shader_program_.setUniformValue("spotLight.direction", camera_.getFront());shader_program_.setUniformValue("spotLight.cutOff",   (float)cos(12.5f*3.1415926/180));shader_program_.setUniformValue("spotLight.outerCutOff",   (float)cos(17.5f*PI/180));shader_program_.setUniformValue("spotLight.constant",  1.0f);shader_program_.setUniformValue("spotLight.linear",  0.09f); // 将光照调暗了一些以搭配场景shader_program_.setUniformValue("spotLight.quadratic", 0.032f);shader_program_.setUniformValue("dirLight.direction", -0.2, -1.0, -0.3);shader_program_.setUniformValue("dirLight.ambient",  0.05, 0.05, 0.05);shader_program_.setUniformValue("dirLight.diffuse",  0.4, 0.4, 0.4); // 将光照调暗了一些以搭配场景shader_program_.setUniformValue("dirLight.specular", 0.5, 0.5, 0.5);shader_program_.setUniformValue("material.shininess", 32.0f);shader_program_.setUniformValue("model", model);m_planeMesh->draw(shader_program_);shader_program_.release();signal_color_program_.bind();signal_color_program_.setUniformValue("projection", projection);signal_color_program_.setUniformValue("view", view);signal_color_program_.release();auto it = models_.begin();while(it != models_.end()){model.setToIdentity();model.translate(it.value().world_pos);model.rotate(it.value().pitch, QVector3D(1.0, 0.0, 0.0));model.rotate(it.value().yaw, QVector3D(0.0, 1.0, 0.0));model.rotate(it.value().roll, QVector3D(0.0, 0.0, 1.0));glStencilFunc(GL_ALWAYS, 1, 0xFF);glStencilMask(0xFF);shader_program_.bind();shader_program_.setUniformValue("model", model);it.value().model->draw(shader_program_);shader_program_.release();if(!it.value().is_selected){it++;continue;}glStencilFunc(GL_NOTEQUAL, 1, 0xFF);glStencilMask(0x00);float height=it.value().model->max_y_-it.value().model->min_y_;float width=it.value().model->max_x_-it.value().model->min_x_;if(it.value().model->min_y_>=0)model.translate(0.0f,height/2,0.0f);model.scale(1.1f,1.0+0.1*(width/height));if(it.value().model->min_y_>=0)model.translate(0.0f,-height/2,0.0f);signal_color_program_.bind();signal_color_program_.setUniformValue("model", model);it.value().model->draw(signal_color_program_);signal_color_program_.release();glStencilMask(0xFF);glStencilFunc(GL_ALWAYS, 1, 0xFF);it++;}update();
}

在这里插入图片描述

混合

在OpenGL中混合主要是实现物体透明度的一中技术

丢弃片段

有些图片并不需要半透明,只需要根据纹理颜色值,显示一部分,或者不显示一部分,没有中间情况。

discard.frag

#version 330 core
struct Material {sampler2D diffuse;sampler2D specular;float shininess;
};uniform Material material;struct SpotLight {vec3 position;vec3 direction;vec3 ambient;vec3 diffuse;vec3 specular;float constant;float linear;float quadratic;float cutOff;float outerCutOff;
};struct DirLight {vec3 direction;vec3 ambient;vec3 diffuse;vec3 specular;
};uniform DirLight dirLight;
uniform SpotLight spotLight;struct PointLight {vec3 position;float constant;float linear;float quadratic;vec3 ambient;vec3 diffuse;vec3 specular;
};out vec4 FragColor;
uniform vec3 lightPos;
uniform vec3 viewPos;in vec3 Normal;
in vec3 fragPos;
in vec2 TexCoords;void main()
{vec4 texColor=texture(material.diffuse,TexCoords);if(texColor.a < 0.1) discard;FragColor = texColor;
}
discard_program_.bind();
discard_program_.setUniformValue("projection", projection);
discard_program_.setUniformValue("view", view);
discard_program_.setUniformValue("model", model);foreach (auto item, vegetation) {model.setToIdentity();model.translate(item);discard_program_.setUniformValue("model", model);m_discardMesh->draw(discard_program_);
}

具体的实现可以在项目中查询到。

在这里插入图片描述

混合

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

glEnable(GL_BLEND);
  • 源颜色向量。这是源自纹理的颜色向量。
  • 目标颜色向量。这是当前储存在颜色缓冲中的颜色向量。
  • 源因子值。指定了alpha值对源颜色的影响。
  • 目标因子值。指定了alpha值对目标颜色的影响。
选项
GL_ZERO因子等于
GL_ONE因子等于
GL_SRC_COLOR因子等于源颜色向量
GL_ONE_MINUS_SRC_COLOR因子等于
GL_DST_COLOR因子等于目标颜色向量
GL_ONE_MINUS_DST_COLOR因子等于
GL_SRC_ALPHA因子等于的分量
GL_ONE_MINUS_SRC_ALPHA因子等于 的分量
GL_DST_ALPHA因子等于的分量
GL_ONE_MINUS_DST_ALPHA因子等于 的分量
GL_CONSTANT_COLOR因子等于常数颜色向量
GL_ONE_MINUS_CONSTANT_COLOR因子等于
GL_CONSTANT_ALPHA因子等于的分量
GL_ONE_MINUS_CONSTANT_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);

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

  • GL_FUNC_ADD:默认选项,将两个分量相加:。
  • GL_FUNC_SUBTRACT:将两个分量相减: 。
  • GL_FUNC_REVERSE_SUBTRACT:将两个分量相减,但顺序相反:。

融合会存在遮挡问题,所以应该按照如下顺序绘制物体。

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

代码在项目中查看

效果展示:
在这里插入图片描述

相关文章:

QT+OpenGL模板测试和混合

QTOpenGL模板测试和混合 本篇完整工程见gitee:QtOpenGL 对应点的tag&#xff0c;由turbolove提供技术支持&#xff0c;您可以关注博主或者私信博主 模板测试 当片段着色器处理完一个片段之后&#xff0c;模板测试会开始执行。和深度测试一样&#xff0c;它可能会丢弃片段&am…...

《英雄编程体验课》第 11 课 | 前缀和

文章目录 零、写在前面一、概念定义1、部分和2、朴素做法3、前缀和4、前缀和的边界值5、边界处理6、再看部分和二、题目描述1、定义2、求解三、算法详解四、源码剖析五、推荐专栏六、习题练习零、写在前面 该章节节选自 《算法零基础100讲》,主要讲解最基础的算法 —— 前缀和…...

Java学习--多线程2

2.线程同步 2.1卖票【应用】 案例需求 某电影院目前正在上映国产大片&#xff0c;共有100张票&#xff0c;而它有3个窗口卖票&#xff0c;请设计一个程序模拟该电影院卖票 实现步骤 定义一个类SellTicket实现Runnable接口&#xff0c;里面定义一个成员变量&#xff1a;privat…...

【Virtualization】Windows11安装VMware Workstation后异常处置

安装环境 Windows 11 专业版 22H2 build 22621.1265 VMware Workstation 17 Pro 17.0.0 build-20800274 存在问题 原因分析 1、BIOS未开启虚拟化。 2、操作系统启用的虚拟化与Workstation冲突。 3、操作系统启用内核隔离-内存完整性保护。 处置思路 1、打开“资源管理器”…...

第四章.神经网络—BP神经网络

第四章.神经网络 4.3 BP神经网络 BP神经网络(误差反向传播算法)是整个人工神经网络体系中的精华&#xff0c;广泛应用于分类识别&#xff0c;逼近&#xff0c;回归&#xff0c;压缩等领域&#xff0c;在实际应用中&#xff0c;大约80%的神经网络模型都采用BP网络或BP网络的变化…...

如何压缩RAR格式文件?

RAR是我们日常生活工作中经常用到的压缩文件格式之一&#xff0c;那么RAR文件如何压缩呢&#xff1f; 不管压缩哪种格式的压缩文件&#xff0c;我们都需要用到压缩软件。针对RAR格式&#xff0c;我们可以选择最常见的WinRAR&#xff0c;当然如果有同样适用于RAR格式的压缩软件…...

JS 执行机制 详解(附图)

一、JS是单线程JS语言的一大特点就是单线程&#xff0c;也就是说&#xff0c;同一个时间只能做一件事。这是JS这门脚本语言诞生的使命所致——用来处理页面中用户的交互&#xff0c;以及操作DOM而诞生的。单线程就意味着&#xff0c;所有任务需要排队&#xff0c;前一个任务结束…...

华为OD机试真题Java实现【 计算面积】真题+解题思路+代码(20222023)

计算面积 绘图机器的绘图笔初始位i在原点(0.0)。 机器启动后其绘图笔按下面规则绘制直线: 1 )尝试沿着横向坐标轴正向绘制直线,直到给定的终点值E, 2 )期间可通过指令在纵坐标轴方向进行偏移。井同时绘制直线,偏移后按规则1绘制直线;指令的格式为X offsetY。表示在横坐标X…...

【JVM】运行时数据区与对象的创建流程

4、运行时数据区 4.1、运行时数据区介绍 运行时数据区也就是JVM在运⾏时产生的数据存放的区域&#xff0c;这块区域就是JVM的内存区域&#xff0c;也称为JVM的内存模型——JMM 堆空间&#xff08;线程共享&#xff09;&#xff1a;存放new出来的对象 元空间&#xff08;线程共…...

flutter- JSON解析框架使用方法json_serializable

对于目前来说&#xff0c;大部分的API网络请求的通讯内容数据格式都是JSON。JSON返回的都是字符串&#xff0c;假如要取到data里面的id&#xff0c;去直接字符串截取肯定是不行的&#xff0c;要通过一定的方式把它解析成Map或者解析成对象&#xff0c;再去处理它。像一些简单的…...

第十三届蓝桥杯国赛 C++ B 组 J 题——搬砖(AC)

目录1.搬砖1.题目描述2.输入格式3.输出格式4.样例输入5.样例输出6.数据范围7.原题链接2.解题思路3.Ac_code1.搬砖 1.题目描述 这天&#xff0c;小明在搬砖。 他一共有 nnn 块砖, 他发现第 iii 砖的重量为 wiw_{i}wi​, 价值为 viv_{i}vi​ 。他突然想从这些 砖中选一些出来从…...

Spring Cloud Nacos源码讲解(十)- Nacos服务端服务发现处理

Nacos集群数据同步 ​ 当我们有服务进行注册以后&#xff0c;会写入注册信息同时会触发ClientChangedEvent事件&#xff0c;通过这个事件&#xff0c;就会开始进行Nacos的集群数据同步&#xff0c;当然这其中只有有一个Nacos节点来处理对应的客户端请求&#xff0c;其实这其中…...

C++ 修改程序进程的优先级(Linux,Windows)

文章目录1、Linux1.1 常用命令1.1.1 不占用终端运行和后台运行方式1.1.2 查询进程1.1.3 结束进程1.1.4 优先级命令1.2 C 代码示例1.2.1 代码一1.2.2 代码二2、Windows2.1 简介2.2 函数声明2.3 C 代码示例2.3.1 代码一2.3.2 代码二结语1、Linux 1.1 常用命令 1.1.1 不占用终端…...

同步和异步promise

进程和线程进程&#xff08;厂房&#xff09;&#xff1a;程序的运行环境线程&#xff08;工人&#xff09;&#xff1a;进行运算的东西同步和异步同步&#xff1a;一件事干完才去干下一件事&#xff0c;前面的代码不执行&#xff0c;后面的代码也不执行。同步的代码可能会出现…...

CHATGPT是新的“搜索引擎终结者”吗?百度是否慌了

ChatGPT 以其非凡的自然语言处理 &#xff08;NLP&#xff09; 能力和清晰的响应风靡全球&#xff0c;有望带来一场重大的技术革命。在不知不觉中&#xff0c;叙事转向了ChatGPT与百度的对决&#xff0c;因为来自OpenAI的智能和健谈的聊天机器人已经慢慢获得了“潜在的百度终结…...

力扣-订单最多的客户

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;586. 订单最多的客户二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其他总…...

MyBatis学习笔记(六) —— MyBatis的各种查询功能

6、MyBatis的各种查询功能 6.1、查询一个实体类对象 SelectMapper.java接口 /*** 根据用户id查询用户信息* param id* return*/ User getUserById(Param("id") int id);SelectMapper.xml <!--User getUserById(Param("id") int id)--> <selec…...

2023年最新详细教程!手把手教你搭建Hexo + GitLab个人博客

文章目录前言一、安装和配置环境1.安装 Git2.安装 Node.js二、新建博客项目1.GitLab配置CI/CD自动化部署1.1 GitLab新建项目1.2 GitLab自建Runners1.2.1 下载gitlab-runner1.2.2 注册Runners1.2.3 安装Runners并启动1.3 添加.gitlab-ci.yml文件2.拉取和推送hexo blog2.1 拉取he…...

centos7安装

centos7安装制作U盘启动盘下载镜像下载 UltralISO制作启动盘使用U盘安装系统修改模式为 UEFI调整BOOT option保存重启进入安装界面安装图形界面安装搜狗输入法制作U盘启动盘 下载镜像 去官网下载镜像&#xff0c;找到 mirrors链接&#xff08;速度快&#xff09; 选择一个中…...

java String类(超详细,含常用方法、面试题,内存图,案例)

String类一、String类的特点二、String 类的常见构造方法三、String常见的面试题1.字符串常量池2.String s "abc"与String s new String("abc")区别3.字符拼接4.常量优化机制四、String常用方法1. 比较字符串内容2. 遍历字符串3.截取字符串4.替换字符串5…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...