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

推荐订阅源

V
V2EX
爱范儿
爱范儿
Martin Fowler
Martin Fowler
T
The Blog of Author Tim Ferriss
B
Blog RSS Feed
博客园 - 聂微东
G
GRAHAM CLULEY
Engineering at Meta
Engineering at Meta
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
WordPress大学
WordPress大学
Scott Helme
Scott Helme
AI
AI
S
Security Affairs
T
Threat Research - Cisco Blogs
M
MIT News - Artificial intelligence
T
Troy Hunt's Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理
AWS News Blog
AWS News Blog
T
Threatpost
Cyberwarzone
Cyberwarzone
www.infosecurity-magazine.com
www.infosecurity-magazine.com
U
Unit 42
V
Vulnerabilities – Threatpost
J
Java Code Geeks
博客园 - Franky
月光博客
月光博客
Blog — PlanetScale
Blog — PlanetScale
NISL@THU
NISL@THU
D
Docker
小众软件
小众软件
N
News and Events Feed by Topic
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
A
Arctic Wolf
D
DataBreaches.Net
云风的 BLOG
云风的 BLOG
Forbes - Security
Forbes - Security
量子位
PCI Perspectives
PCI Perspectives
美团技术团队
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
I
InfoQ
Security Archives - TechRepublic
Security Archives - TechRepublic
有赞技术团队
有赞技术团队
腾讯CDC
P
Proofpoint News Feed
S
Security @ Cisco Blogs
G
Google Developers Blog
C
Cisco Blogs

音视频开发进阶

音视频教程-第三节 音视频教程-第二节 真的,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 开发学习环境搭建~ 【喜大普奔】域名终于备案通过啦 【音视频连载-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++ 标准容器库小结 MediaCodec 硬编码之相机内容编码成 H264 文件 一文读懂 YUV 的采样与格式 《OpenGL ES 3.x 游戏开发》碰撞检测之 AABB 包围盒
Shader 优化 | OpenGL 绘制网格效果
音视频开发进阶 · 2020-05-22 · via 音视频开发进阶

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

避免图片丢失,建议阅读微信原文:

https://mp.weixin.qq.com/s/FmILdXuy3HMpv8H1Kz_fPw 前几天发布了这样一篇文章: KodeLife | Shader 实时编辑预览的强大工具使用实践 除了介绍 KodeLife 的使用之外,还附带了一个 Shader 绘制网格效果的代码。 把这篇文章发到技术群里,随机就有大佬指出不足之处,提示说代码还可以进一步优化,并且提供了源码学习。 可见加入一个高质量的技术群是多么重要,哪怕平时不说话,围观大佬们聊天都能学到很多。 现在加入还来得及,尚有余位,详情点击如下链接: 移动端技术交流喊你入群啦~~~


在我的 Shader 代码中是这样绘制网格的:

    vec2 fragcoord = vec2(gl_FragCoord.xy / u_resolution);
    vec3 bgColor = vec3(1.0,1.0,1.0);
    vec3 pixelColor = bgColor;
    vec3 gridColor = vec3(0.5,0.5,0.5);

    const float width = 0.1;
    const float minWidth = 0.003;
    for(float i = 0.0; i < 1.0; i+=width){
    if (mod(fragcoord.x,width) < minWidth || mod(fragcoord.y,width) < minWidth){
            pixelColor = gridColor;
        }
    }
    gl_FragColor = vec4(pixelColor,1.0);

首先,讲解几个概念:

gl_FragCoord 代表当前像素相对于屏幕的坐标,屏幕左下角为原点。

u_resolution 是当前图像的分辨率。

gl_FragCoord 除以 u_resolution 得到的结果 fragcoord 就是归一化的屏幕坐标。

由于已经归一化了那么 fragcoord 的值就在 [0,1] 的闭区间内。

同时用 gridColor 作为网格的颜色,bgColor 作为背景色,也是默认的颜色,pixelColor 作为最后输出的颜色。

那么,代码的重点就在于 for 循环里面了。

由于 fragcoord 归一化有了确定的值域范围,所以可以在 for 循环中将它十等分。

另外,因为片段着色器每个像素都会执行一遍,每次 fragcoord 值都是变化的,但不管怎么变化,它的范围都会落在 for 循环的十等份里面。

比如其中某一份的范围是 [0.2,0.3) 的左闭右开区间,当前像素就落在这个范围内。

那么 mod 取模函数就会判断当前值距离左区间阈值是否在 minWidth 范围内,其中 minWidth 相当于是指定网格线的宽度。

如果在范围内,那么显示的颜色就是网格色,否则就是默认的背景色。

以上的讲解对于坐标的 xy 值是一样的道理。原理通过判断该像素点的坐标是否位于临界范围内来选择性着色。

显示这种绘制方式是有它的弊端,因为每一个像素执行片段着色器的时候,都要进行一次 for 循环判断它处于哪个区域内。

这样就有了太多不必要的计算流程,尤其是 for 循环的每次遍历。


接下来就是微信群中大佬给出的 Shader 代码:

vec2 st = vec2(gl_FragCoord.xy / u_resolution);
st.x *= u_resolution.x / u_resolution.y;

vec3 color = vec3(.0);

st *= 10.;

vec2 i_st = floor(st);
vec2 f_st = fract(st);

color += step(.98,f_st.x) + step(.98,f_st.y);

gl_FragColor = vec4(color,1.0);

可以一眼看出这里面没有 for 循环的操作了。

还是先讲解几个级别操作:

floor 函数就是向下取整的操作

fract 函数是 x - floor(x) 的操作,也就是取小数部分的意思。

通过对 st 进行 floorfract 操作可以分出它的整数和小数部分。

step 函数类似于 if 判断,当第二个参数大于等于第一个参数,则返回 1 ,否则返回 0 。

整个 Shader 代码第一行还是相同的,都是归一化操作。

然后在第二行

st.x *= u_resolution.x / u_resolution.y

实际上是做了一个比例切换的操作。将 stxy 值按照图像分辨率的宽高比做了调整,其中以 y 为基准 1 。

这样一来,sty 值还是在 [0,1] 范围内,而 x 值可能大于也可能小于这个范围了,这都取决于图像分辨率了。

接下来将 st 乘了 10 ,这下 st 的值域范围就在 [0,10] 了 ,这样的操作是为了接下来的 floor 函数,因为它是取整,如果都在 [0,1] 范围内,取的整数永远都是 0 了。

前面转换操作是为了接下来的重点函数 step

color += step(.98,f_st.x) + step(.98,f_st.y);

前面的 floor 其实也是将 xy 轴做了等分,比如 y 的值域是 [0,1] ,乘以 10 之后,就是十等分,x 的值域如果是 [0,1.7] ,乘以 10 之后,就是十七等分。

fract 操作的结果范围必然是 [0,1) 的左闭右开区间。

step 函数的意图就是如果该像素点的坐标接近于等分线,那么 color 的颜色值返回的就是 1 ,显示白色,否则返回 0 ,显示黑色。

比如,st 的 x 值是 7.99 了,接近于 8 ,那么就要显示白色网格线了,对于 y 值同理。

这样一来就可以对每个像素点进行判断,根据它的坐标决定要显示什么颜色。

总结对比

在第二种绘制中,由于做了比例转换操作,所以绘制出来的网格大小都是一致的,且都是正方形。

而第一种没有比例切换操作,当宽高不同的情况下,同样进行十等分的话,画出来的网格是个长方形了。

但是,两种绘制的思路都是相同的,姑且称它为 接近法 吧,当绘制的像素接近等分线时,就显示不一样的颜色。

于是,等分线的操作思路就各有不同了。前者是利用 for 循环来制造划分,后者则是利用当前像素的 xy 值的特点来绘制的。

当然更推崇后者的绘制方式了,也是学到了新技巧~~~

能力不足,经验有限,文中有何不对的地方欢迎批评指正,也可以加我微信 ezglumes 交流~~

原创文章,转载请注明来源:    Shader 优化 | OpenGL 绘制网格效果