惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog
Blog — PlanetScale
Blog — PlanetScale
酷 壳 – CoolShell
酷 壳 – CoolShell
GbyAI
GbyAI
M
MIT News - Artificial intelligence
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
C
Check Point Blog
云风的 BLOG
云风的 BLOG
aimingoo的专栏
aimingoo的专栏
V
Visual Studio Blog
U
Unit 42
Microsoft Azure Blog
Microsoft Azure Blog
Spread Privacy
Spread Privacy
博客园 - Franky
Vercel News
Vercel News
月光博客
月光博客
罗磊的独立博客
博客园 - 叶小钗
腾讯CDC
A
About on SuperTechFans
P
Privacy International News Feed
V
V2EX
L
LINUX DO - 最新话题
K
Kaspersky official blog
P
Privacy & Cybersecurity Law Blog
D
DataBreaches.Net
D
Darknet – Hacking Tools, Hacker News & Cyber Security
有赞技术团队
有赞技术团队
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Stack Overflow Blog
Stack Overflow Blog
T
Tor Project blog
MyScale Blog
MyScale Blog
Y
Y Combinator Blog
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
Recorded Future
Recorded Future
大猫的无限游戏
大猫的无限游戏
P
Proofpoint News Feed
L
LangChain Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
雷峰网
雷峰网
Project Zero
Project Zero
G
Google Developers Blog
博客园 - 【当耐特】
C
Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
The GitHub Blog
The GitHub Blog

音视频开发进阶

音视频教程-第三节 音视频教程-第二节 真的,AI 可能就是新时代的信息差 充值 Cursor 之后,工作有了哪些变化?🤔 个人'蒸馏'大模型能做哪些有意思的事情 DeepSeek 大模型在 Mac 上的部署和运行 音视频教程-第一节 【WebRTC 专栏】-- Android 开发集成 WebRTC 库的几种方式 【WebRTC 专栏】-- 在 Mac M1 等系列芯片编译和开发 WebRTC-Android 库 Meta Llama3 大模型在 Mac 上的部署和运行 iOS VideoToolBox 解码 HEVC Open-GOP 视频的问题排查 Flutter 状态管理之 InheritedWidget 使用和分析 用 ChatGPT 回答技术问题怎么样 ? 音视频开发系统入门大致路线 UE 4.27 添加自定义 ShadingModel 用 UE4 虚幻引擎做个捏脸小功能~~ UE4 材质练习 之 凹凸贴图偏移的使用 UE4 材质练习系列基础 OpenGL上下文创建以及共享机制 007 | 播放器系列专栏-解析 MP4 文件读取信息 006 | 播放器系列专栏-在 Mac 上查看 MP4 格式信息 干货 | 快速抽取缩略图是怎么练成的? 关于直播、WebRTC、FFmpeg 的那些事 005 | 播放器系列专栏-在 Windows 上查看 MP4 格式信息 将音视频中的花屏、绿屏、黑屏问题一网打尽 关于音视频里面的解码帧率和渲染帧率 004 | 播放器系列专栏-认识MP4视频(下) 003 | 播放器系列专栏-认识MP4视频(上) 入门或者转行音视频,应该要怎么做? H264视频文件如何缩放分辨率 002 | 播放器系列专栏-FFmpeg依赖库的配置 001 | 播放器系列专栏-关于播放器项目的一个小实践 Seek策略以及在有B帧情况下的处理 目前流媒体开发工程师工作内容主要是什么? 一个音视频领域专业问答的小圈子 干货收藏 || Vulkan Game Engine 视频教程 音视频春节假期内卷指南(实操) Vulkan 在 FFmpeg 中的支持 Windows 下 FFmpeg 和 LibX264 的编译和配置 Metal 开发 | 使用 C++ 进行接口调用 音视频开发工作经验分享 || 视频版 FFmpeg 调用 MediaCodec 硬解码到 Surface 上 代码吸猫 | 用 OpenGL 图像渲染的养猫计划 百倍变速--解码到底能不能丢 非参考帧 ?FFmpeg 有话说!!! 老生常谈-FFmpeg 的编译问题轻松搞定 FFmpeg 调用 Android MediaCodec 进行硬解码(附源码) 【WebRTC 专栏】--创建相机预览 Unity Shader 光照基础之 Half Lambert 光照模型 Unity Shader 光照基础之Lambert光照模型 Unity Shader 光照基础内容 Unity Shader 显示一张图片纹理 UnityShader 的基本概念 Unity 物体的基本操作 C++ 模板系列小结07-尾置返回类型 C++ 模板系列小结06-可变参数模板特性 C++ 中的多线程的使用和线程池建设 C++ 模板系列小结05-模板类型作为模板参数 C++ 模板系列小结04-类模板中的成员模板 C++ 模板系列小结03-在模板中指定变量类型 C++ 模板系列小结02-非类型模板参数 C++ 模板系列小结01-函数模板和类模板 从零打造渲染引擎系列01-什么是渲染引擎 iOS开发 - 在 Swift 中去调用 C/C++ 代码 2021 技术新番 - 从零打造渲染引擎系列 iOS 音视频开发的一些基础准备工作 音视频交流群又来啦~~~ 【WebRTC 专栏】WebRTC & Android 开发学习环境搭建~ 【喜大普奔】域名终于备案通过啦 Shader 优化 | OpenGL 绘制网格效果 【音视频连载-011】第二季 FFmpeg 一层一层获取文件信息 KodeLife | Shader 实时编辑预览的强大工具使用实践 推荐几个堪称教科书级别的 Android 音视频入门项目 【音视频连载-010】第二季 FFmpeg 日志打印 【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下) 【音视频连载-007】基础学习篇-SDL 播放 PCM 音频文件(上) 【音视频连载-006】基础学习篇-SDL 播放 YUV 视频文件 【音视频连载-005】基础学习篇-SDL 加载 YUV 文件并显示 【音视频连载-004】基础学习篇-SDL 加载图片并显示 【音视频连载-003】基础学习篇-SDL 消息循环和事件响应 【音视频连载-002】基础学习篇-SDL 创建窗口并显示颜色 【音视频连载-001】基础学习篇- SDL 介绍以及工程配置 LearnOpenGL 源码在 MAC 上的编译与调试 2019 年终总结与回顾 Android NDK 开发的免费技术视频来啦~~ OpenGL 实现视频编辑中的转场效果 OpenGL 实践之贝塞尔曲线绘制 图像库 libjpeg-turbo 编译与实践 图像库 libpng 编译与实践 rust 开发编译 Android 动态库实践 Android NDK 开发 —— 从 Assets 文件夹加载图片并上传纹理 简单易用的图像解码库介绍 —— stb_image 博客图床迁移记 进击的 Vulkan 移动开发之 SwapChain 进击的 Vulkan 移动开发之 Command Buffer 进击的 Vulkan 移动开发之 Instance & Device & Queue 进击的 Vulkan 移动开发(一)之今生前世 Java 显式锁 Lock 与条件队列 C++ 标准容器库小结 一文读懂 YUV 的采样与格式 《OpenGL ES 3.x 游戏开发》碰撞检测之 AABB 包围盒
《OpenGL ES 3.x 游戏开发》之利用 Alpha 透明度进行测试
音视频开发进阶 · 2018-07-13 · via 音视频开发进阶

一个专注音视频领域的小圈子

在前面的博客文章中有提到 OpenGL 裁剪测试及注意点,并且裁剪测试只能裁剪一个矩形区域,相当于就是把整个内容都绘制上去了,但是透过一个小矩形区域来看绘制的物体。 除了透过矩形区域,还可以实现透过任意形状区域来观察物体,这就是要用到 OpenGL 的 Alpha 透明度测试。 关于 Alpha 透明度测试,在 用 OpenGL 对视频帧内容进行替换 也用实践用到过。 在 OpenGL 中,每个颜色都有四个色彩通道 — RGBA,其中 A 就是 Alpha 透明度通道,可以利用它的值进行检测。

Alpha 测试的基本原理为,当绘制一个片元时,首先检测其 Alpha 值,若 Alpha 值满足要求,就通过测试,绘制此片元,否则丢弃此片元,不进行绘制。

比如如下的场景:

如果是裁剪测试,只能屏幕上透过一个矩形区域来观察实际场景。

而换成 Alpha 测试,就可以实现透过任意形状的观察,效果如下:

图上的内容实际由三部分组成,树、地形、中间带透明度的边框。

正因为绘制的边框带透明度,才不会全部遮住后面的内容。

具体绘制代码如下:

            GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT or GLES20.GL_COLOR_BUFFER_BIT)
            // 打开深度检测
             GLES20.glEnable(GLES20.GL_DEPTH_TEST)
			// 设置相机和观察矩阵,绘制地形和树
            MatrixState.setProjectFrustum(-ratio!!, ratio!!, -1f, 1f, 1f, 100f)
            MatrixState.setCamera(cx, 0f, cz, 0f, 0f, 0f, 0f, 1.0f, 0f)

            MatrixState.pushMatrix()
            MatrixState.translate(0f, -2f, 0f)
            // 绘制地形
            desert!!.drawSelf(desertId)
            MatrixState.popMatrix()
			// 开启混合,因为树要和地形有混合的地方
            GLES20.glEnable(GLES20.GL_BLEND)
			// 设置混合因子
            GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)
            MatrixState.pushMatrix()
            MatrixState.translate(0f, -2f, 0f)
            // 绘制树
            tg!!.drawSelf(treeId)
            MatrixState.popMatrix()
			// 关闭混合
            GLES20.glDisable(GLES20.GL_BLEND)
			// 清除深度缓冲
            GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT)
			// 设置相机和投影矩阵来绘制带透明度的边框
            MatrixState.pushMatrix()
            MatrixState.setProjectOrtho(-1f, 1f, -1f, 1f, 1f, 100f)
            MatrixState.setCamera(0f, 0f, 3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
            rect!!.drawSelf(maskTextureId)
            MatrixState.popMatrix()

这里面绘制带透明度的边框时清除了一次深度缓冲,因为带透明度边框不属于主场景,不应该和主场景中的物体以同一标准进行深度检测,否则可能会产生不正确的视觉效果。

具体实现

Alpha 测试的重点在于片段着色器的处理,在这里可以对每一个片段进行处理,根据 Alpha 来决定是否抛弃它。

precision mediump float;
varying vec2 vTextureCoord; //接收从顶点着色器过来的参数
uniform sampler2D sTexture;//纹理内容数据
void main() { 
	//给此片元从纹理中采样出颜色值 
   vec4 bcolor = texture2D(sTexture, vTextureCoord);
   if(bcolor.a<0.6) {
   		discard;
   } else {
      gl_FragColor=bcolor;
}}

根据具体的图片透明度,这里,如果透明度小于 0.6 ,就抛弃这个片元,否则的话就赋值给原本采样的颜色。

其中,在 GLSL 着色器语言中,discard 代表放弃该片元。

而 texture2D 方法代表纹理采样,它的结果类型是一个向量,向量在着色器代码中的地位非常重要,可以方便地存储以及操作 颜色位置纹理坐标 等不仅包含一个组成部分的量。

对于一个向量,有时需要单独访问向量中的某个分量,基本语法为 <向量名>.<分量名>,从不同的角度来看,它的每个分量代表的含义是不同的:

  • 将向量看作颜色时,可以使用 r、g、b、a 四个分量名,分别代表红、绿、蓝、透明度 4 个色彩通道。
vec4 aColor;
aColor.r = 0.6;
aColor.g = 0.8;

若向量是 4 维的,可以使用的分量名为 r、g、b、a;若向量是 3 维的,可以使用的分量名为 r、g、b;若是 2 维的,可以使用的 r、g 两个分量名。

  • 将向量看作位置时,可以使用 x、y、z、w 四个分量名,分别代表 x 轴、y 轴、z 轴分量及 w 值。
vec4 aPosition;
aPosition.x = 34.2
aPosition.z = 12.2

若向量是 4 维的,可以使用的分量名为 x、y、z、w;若向量是 3 维的,可以使用的分量名为 x、y、z;若是 2 维的,可以使用的 x、y 两个分量名。

  • 将向量看作纹理坐标时,可以使用 s、t、p、q 四个分量名,分别代表纹理坐标的不同分量。
vec4 aTexCoor;
aTexCoor.s = 0.45;
aTexCoor.t = 0.22;

若向量是 4 维的,可以使用的分量名为 s、t、p、q;若向量是 3 维的,可以使用的分量名为 s、t、p;若是 2 维的,可以使用的 s、t 两个分量名。

除了使用 . 的形式来访问分量名,还可以将向量看作一个数组,用下标来进行访问:

aColor[0] = 0.4;
aPostion[2] = 0.34;
aTexCoorp[1] = 0.12;

理解了 discard 的作用和向量各分量的含义,就很容易明白 Alpha 测试的原理了。

实际上,Alpha 测试并不是渲染管线上要进行的操作流程,而是我们自己想出的根据 Alpha 透明度值对片元进行处理罢了。

具体的实现可以参考我的 Github 项目,求一波 Star 。

https://github.com/glumes/AndroidOpenGLTutorial

参考

  1. 《OpenGL ES 3.x 游戏开发》

最后

俗话说:

独学而无友,则孤陋而寡闻

学习的路上是需要交流和分享的,这里有个二维码,如果你对 OpenGL ES 感兴趣欢迎一起来交流讨论。

加群讨论

要是二维码过期了,加微信 ezglume 好友,备注 OpenGL ,拉你入群~

原创文章,转载请注明来源:    《OpenGL ES 3.x 游戏开发》之利用 Alpha 透明度进行测试