HWUI源码剖析(二) - 终于讲清楚OpenGL渲染的MVP矩阵的来龙去脉

news2024/10/5 18:32:44

概述

研究android8.1 HWUI源码的过程中,发现OpenGL是绕不过的一个知识点,不理解OpenGL的绘制基础,必然无法很好的理解Hwui基本原理,同时熟悉OpenGL之后,HWUI也是一个非常优秀的OpenGL 2D渲染的代码,本文将介绍一下OpenGL绘制图形的重要原理,为学习HWUI源码扫清障碍,本文我们将以会一直一个白色的矩形为例,结合代码实践加以说明。

OpenGL的向量矩阵

向量

OpenGL中,一个点(位置)通过一个向量表示,通常有4个元素:x,y,z,w,z代表深度,w代表距离,下面讲解透视矩阵的时候讲解。如果不指定z的值,其默认取值为0;如果不指定w的值,其默认值为1.

矩阵

OpenGL中的矩阵式4*4矩阵,要特别注意OpenGL中的矩阵Matrix是按列优先存储在内存中的。接下来我们看一个平移矩阵A

1     0     0     Xtransition
0     1     0     Ytransition
0     0     1     Ztransition
0     0     0     1

假设Xtransition = Ytransition =100,Ztransition = 0,那么这样得到矩阵A,A的作用是平移x ,y坐标100个位置。我们有一个坐标点B(2,2),这个坐标点z和w值没有指定,其默认值分别是,0和1,所以按照四维向量来看该点是B(2,2,0,1),那么使用矩阵A平移坐标点B(2,2,0,1)相当于A * B = (102, 102, 0 , 1),正是我们需要的。

注意:矩阵相乘满足结合率(A*B)*C = A*(B*C);不满足交换律

OpenGL渲染显示的pipeline

我们都知道OpenGL绘制最终是将一个个的点绘制成图,对于入门者来说难以理解的就是MVP矩阵,即model模型矩阵,View视图矩阵,projection投影矩阵。分析这三个矩阵之前我们先介绍下OpenGL显示渲染管线:

输入坐标-->mvp矩阵变换-->gl_Position--->透视除法---->归一化坐标--->视口变换--->窗口坐标。

注意,这里gl_Position就是shader里面的那个着色器的原始的gl_Position坐标。往往着色器代码会这写,其中a_Position就是我们调用openGL接口输入的顶点坐标。

uniform mat4 u_Matrix;

attribute vec4 a_Position;  
attribute vec4 a_Color;
varying vec4 v_Color;

void main()                    
{                            
    v_Color = a_Color;
	  	  
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * a_Position;
       
}   

正交投影矩阵

正交投影矩阵是重要的投影矩阵之一,2D图形渲染中经常使用,比如android的hwui渲染引擎就右使用正交投影,与之相对的是透视投影矩阵,本小节讲解正交投影矩阵。

要理解上面的整个工作流程最好先从渲染的最后即窗口坐标这里反向分析,假设mvp矩阵都没有设置,且计算的坐标点的w分量我们都假设是1(这样透视除法就可以忽略),屏幕的分辨率是width x height = 1280 * 800,我们在屏幕右上角1/4绘制一个矩形,由于此时没有矩阵作用羽a_Position,我们程序使用的vertex坐标就是归一化的坐标,即[-1,1]之间。这里涉及一个概念是:裁剪空间。当着色器把一个值写入gl_Position的时候,OpenGL期望这个位置是在裁剪空间(clip space)中的。剪裁空间背后的逻辑非常简单:对于任何给定的位置,它的x,y以及z都要在那个位置的-w和w之间。由于默认我们没有指定坐标点w分量,其默认值是1,所以要求x, y,z都在【-1,1】之间,这个范围之外的任何事物在屏幕不可见。

根据上面的分析我们要在屏幕中央绘制矩形给出的表做点如下:

float[] vertexColorTriangles = {
        //演示HWUI渲染的坐标
        0f, 0f, 0f, 1f, 
        1f, 0f, 0f, 1f, 
        0f, 1f, 0f, 1f, 
        1f, 1f, 0f, 1f, 
};

为什么要引入正交投影矩阵

这样绘制有什么问题吗?我想有几个方面的问题:

1. 缩放比例:我们输入的标志明明是一个长度=1的正方向的坐标,但是实际上显示的确实一个非正方形的矩形。这个点不是很友好,因为我们实际编程的时候拿到的需求可能就是一个屏幕的特定位置绘制一个正方形,最终输入坐标是矩形,绘制结果确实长方形。

2.限制输入坐标是[-1,-1]

由于没有使用任何的矩阵变换,受限于w=1的裁剪空间,输入的坐标a_Position必须是在[-1,1],这显然不方便编程,因为我们编程实现的时候,往往不想关心【-1,-1】范围内坐标和窗口坐标的映射关系,而是直接使用屏幕坐标,比如想在屏幕左上角(100,100)位置开始绘制一个宽高等于200的正方体,如果能直接输入的坐标是(200,200)编程就很方便了怎么实现上面的目标?:

正交投影矩阵可以解决上面的两个问题。

正交投影矩阵的代码试验

shader代码:

uniform mat4 u_Matrix;

attribute vec4 a_Position;  
attribute vec4 a_Color;

varying vec4 v_Color;

void main()                    
{                            
    v_Color = a_Color; 
    gl_Position = u_Matrix * a_Position;
    gl_PointSize = 10.0;          
}       

OpenGL顶点和矩阵设置以及绘制代码:

//设置绘制顶点
vertexColorTriangles = new float[]{
    //演示只使用正交投影,不使用其他投影矩阵的情况
    100f, 100f, 0f, 1f, 0.5f, 0.5f, 0.5f,
    100f, 300f, 0f, 1f, 0.5f, 0.5f, 0.5f,
    300f, 100f, 0f, 1f, 0.5f, 0.5f, 0.5f,
    300f, 300f, 0f, 1f, 0.5f, 0.5f, 0.5f,
};

//正交投影矩阵,width:屏幕宽度,height:屏幕高度,当前环境下分别等于1280和800
使用openGL Matrix.java 中的orthoM函数: 
    orthoM(orthoProjectionMatrix, 0, 0f, width, height, 0, -1f, 1f);

    //模型矩阵和视图矩阵都设置成单位矩阵
    setIdentityM(modelMatrix, 0);
    setIdentityM(viewMatrix, 0);

    //计算最终的mvp矩阵
    multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0);
    multiplyMM(mvpMatrix, 0, orthoProjectionMatrix, 0, modelViewMatrix, 0);

   //绘制代码,由于视图矩阵和模型矩阵都设置成单位矩阵,最终的mvpMatrix就等于orthoProjectionMatrix正交投影矩阵
   glClear(GL_COLOR_BUFFER_BIT);
   glUniformMatrix4fv(uMatrixLocation, 1, false, mvpMatrix, 0);
   // Draw
   glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

绘制的效果:在屏幕左上角(100,100)位置绘制了一个宽高等于200的正方形。

注意:上面orthoM函数生成正交矩阵时候我们注意到y的分量设置:height&#x

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

04、Python 爬取免费小说思路

目录 Python 爬取免费小说思路代码解析爬取东西基本的四行代码:user-agent安装模块从 bs4 导入 BeautifulSoup ,查询某个标签开头的数据筛选遍历获取小说的章节名称每章小说的链接获取请求网址的响应获取小说的内容筛选内容整理内容爬取下载到指定文件夹完整代码:Python 爬取…

HTML+CSS+JS+Django 实现前后端分离的科学计算器、利率计算器(附全部代码在gitcode链接)

🧮前后端分离计算器 📚git仓库链接和代码规范链接💼PSP表格🎇成品展示🏆🏆科学计算器:1. 默认界面与页面切换2. 四则运算、取余、括号3. 清零Clear 回退Back4. 错误提示 Error5. 读取历史记录Hi…

2023年【化工自动化控制仪表】最新解析及化工自动化控制仪表作业考试题库

题库来源:安全生产模拟考试一点通公众号小程序 化工自动化控制仪表最新解析参考答案及化工自动化控制仪表考试试题解析是安全生产模拟考试一点通题库老师及化工自动化控制仪表操作证已考过的学员汇总,相对有效帮助化工自动化控制仪表作业考试题库学员顺…

Linux进程(四)--进程地址空间(一)

前言:在Linux中,每个正在运行的进程都有自己独立的虚拟地址空间,该虚拟地址空间是逻辑上的抽象,用于在进程间提供隔离和保护。它将进程的内存分配和访问从物理内存中分离出来,为每个进程提供了一个独立的地址空间。这究…

【试题036】赋值运算符小例题2

1.题目:设int a0,b0,m0,n0;,执行(mab)/(nab)后m和n的值分别? 2.代码分析: int main() {//设int a0,b0,m0,n0;,执行(mab)/(nab)后m和n的值分别int a 0,b 0,m 0,n 0,…

openCV的CUDA GPU 版本安装 (Ubuntu windows 通用)

需要做template match, 比较注重时间,因此opencv 的普通版本不适用。需要用GPU 的。 下载 git clone https://github.com/opencv/opencv.git git clone https://github.com/opencv/opencv_contrib.git确保准备好以下内容 1: visual studio &#xff0…

吉利银河L6顶配续航测试 记录 方便后续对比

智能模式 不设置保电(优先用电)强动能回收,7成道路开启了L2辅助驾驶。基本无急加速,急减速。 空调开了不到20min 驾驶总时长:3h 5min,平均车速:35Km/h 充电: 慢充到100% 胎压: 2…

使用树莓派(香橙派)搭建文件共享服务器-samba服务器

域网内部通过文件共享来传输文件是一种非常方便的方式,小米摄像头也支持用文件共享smb模式将视频备份到局域网中的文件服务器上。之前我一直使用荣耀pro路由器游戏版,是自带USB接口支持文件共享服务的,接上USB移动硬盘,小米摄像头…

推荐收藏系列!2万字图解Hadoop

今天我用图解的方式讲解pandas的用法,内容较长建议收藏,梳理不易,点赞支持。 学习 Python 编程,给我的经验就是:技术要学会分享、交流,不建议闭门造车。一个人可能走的很快、但一堆人可以走的更远。如果你…

Spring AOP 详细深入讲解+代码示例

Spring AOP 这里是引用 一,介绍 spring aop工作原理图 1.什么是spring aop Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种面向切面编程的技术。它通过将横切关注点(例如日志记录、事务管理、安全性检查等&a…

solidworks 2024新功能之-让您的工作更加高效

您可以创建杰出的设计,并将这些杰出的设计将融入产品体验中。为了帮您简化和加快由概念到成品的产品开发流程,SOLIDWORKS 2024 涵盖全新的用户驱动型增强功能,致力于帮您实现更智能、更快速地与您的团队和外部合作伙伴协同工作。 SOLIDWORKS…

【JavaEE初阶】 线程池详解与实现

文章目录 🌴线程池的概念🎄标准库中的线程池🍀ThreadPoolExecutor 类🚩corePoolSize与maximumPoolSize🚩keepAliveTime🚩ThreadFactory🚩workQueue🚩RejectedExecutionHandler handl…

思科披露新的IOS XE零日漏洞,用于部署恶意软件植入

导语:思科最近披露了一个新的高危零日漏洞(CVE-2023-20273),该漏洞被积极利用来在已经通过本周早些时候披露的CVE-2023-20198零日漏洞遭到侵害的IOS XE设备上部署恶意植入物。 漏洞披露 思科最近披露了一款名为CVE-2023-20273的高…

Leetcode-Easy题解1-回文数字

目录 解法1解法2 解法1 自己的想法,直接转成字符串首尾俩下标同时遍历比较 class Solution {public boolean isPalindrome(int x) {if(x<0){return false;}String strString.valueOf(x);int i0;for (;i<str.length()>>1;i){if(str.charAt(i)!str.charAt(str.leng…

Unity中Shader阴影的接收

文章目录 前言一、阴影接受的步骤1、在v2f中添加UNITY_SHADOW_COORDS(idx),unity会自动声明一个叫_ShadowCoord的float4变量&#xff0c;用作阴影的采样坐标.2、在顶点着色器中添加TRANSFER_SHADOW(o)&#xff0c;用于将上面定义的_ShadowCoord纹理采样坐标变换到相应的屏幕空间…

DC-4 靶机

DC_4 信息搜集 存活检测 详细扫描 后台网页扫描 网页信息搜集 只有一个登陆界面 漏洞利用 尝试使用 burpsuite 密码爆破 尝试使用用户名 admin 登录管理员页面 成功爆破出密码 happy 登录管理员页面 显示可以使用命令 但只能使用三个命令 继续使用 bp 拦截查看数据包…

【C++】VS2019,关于scanf等的报错及其解决方案

参考资料&#xff1a;B站袁春旭老师的网课 报错一&#xff1a;this function may be unsafe. Consider using scanf_s instead. 如下图 这种错误是因为SDL检查不通过&#xff0c;默认这个检查是开的&#xff0c;如下图&#xff0c; 解决方案&#xff1a;把这个SDL检查关闭即…

5、k8s部署Nginx Proxy Manager

前言 Nginx-Proxy-Manager 是一个基于 Web 的 Nginx 服务器管理工具&#xff0c;它允许用户通过浏览器界面轻松地管理和监控 Nginx 服务器。通过 Nginx-Proxy-Manager&#xff0c;可以获得受信任的 SSL 证书&#xff0c;并通过单独的配置、自定义和入侵保护来管理多个代理。用…

51单片机KeyWard

eg1&#xff1a; 单片机键盘的分类 键盘分为编码键盘和非编码键盘&#xff0c;键盘上闭合键的识别由专用的硬件编码器实现&#xff0c;并产生键编码号或键值得称为编码键盘&#xff0c;如计算机键盘&#xff0c;而靠软件来识别的称为非编码键盘&#xff0c;在单片机组成的各种…

Python数字类型

目录 目标 版本 种类 官方文档 数据运算方法 常用函数 转整数 转浮点数 转绝对值 四舍五入 进制转换 math模块常用函数 目标 掌握Python两种数据类型的使用方法。 版本 Python 3.12.0 种类 数字类型有三种&#xff0c;分别是&#xff1a; 整数&#xff08;int&…