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

本文深入探讨Android系统中的OpenGL渲染原理,重点关注MVP矩阵(模型矩阵、视图矩阵、投影矩阵)及其在图形渲染中的应用。通过实例解析正交投影矩阵在2D图形中的作用,解释其解决的屏幕宽高比缩放问题,并介绍了模型矩阵如何实现图形的平移和缩放。同时,简要概述了透视投影和视图矩阵在3D渲染中的基本原理和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

研究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的分量设置:

<think>好的,我现在需要帮助用户找到如何配置和调试Android系统中的debug.hwui.renderer。首先,我应该回忆一下Android的硬件加速渲染相关的知识。记得Android的硬件加速主要涉及Hwui和Skia库,可能还涉及到一些系统属性或者开发者选项。 用户提到的debug.hwui.renderer可能是一个系统属性,用于控制渲染器的类型。根据之前的引用,比如引用[5]提到了Skia库的位置,这可能与渲染器选择有关。另外,引用[1]中提到了enableHardwareAcceleration函数,这可能涉及到硬件加速的启用和配置。 接下来,我应该考虑如何设置这些调试选项。通常,Android可以通过adb命令设置系统属性。例如,使用adb shell setprop命令。可能的属性名类似debug.hwui.renderer,值可能包括skia、opengl或其他选项。 另外,开发者选项中可能有相关的设置。用户可能需要进入开发者选项,查找硬件加速渲染或者调试GPU渲染的选项。例如,在开发者选项里开启“GPU呈现模式分析”或类似的选项,这可能与debug.hwui.renderer有关。 还要考虑是否需要修改系统配置文件,如引用[3]提到的settings_global.xml等,但通常这些设置可能通过adb或代码实现,而不是直接修改XML文件。 此外,查看日志可能有助于调试。使用adb logcat过滤相关标签,如HWUI,可以查看渲染过程中的详细日志,帮助确认配置是否生效或出现的问题。 需要验证可能的属性设置方式。例如,adb shell setprop debug.hwui.renderer skia,然后重启进程或设备,观察渲染行为变化。同时,检查是否有相关的文档或开发者指南说明这些属性的用法。 可能还需要考虑不同Android版本的差异,某些属性可能在较新或旧版本中名称不同或可用性不同。因此,建议用户查阅对应版本的文档或源码,比如引用[1]中的ViewRootImpl.java代码,了解enableHardwareAcceleration的具体逻辑,是否有相关的属性控制。 总结步骤应该是:1. 使用adb设置系统属性;2. 通过开发者选项调整相关设置;3. 查看日志确认效果;4. 可能需要重启应用或设备使设置生效。同时提醒用户注意系统版本差异,并参考官方文档。</think>### 配置和调试 `debug.hwui.renderer` 的方法 Android 的硬件加速渲染HWUI)可通过系统属性和开发者选项进行配置和调试。以下是具体步骤: --- #### 1. **通过系统属性配置渲染器类型** `debug.hwui.renderer` 属性用于指定渲染引擎类型,可选值包括 `skia`(默认)、`opengl`(基于 OpenGL ES)等。 **操作步骤**: ```bash adb shell setprop debug.hwui.renderer [renderer_type] # 例如:skia、opengl adb shell stop && adb shell start # 重启系统进程使配置生效(或重启应用) ``` --- #### 2. **开发者选项中启用调试功能** 在 **开发者选项** 中启用以下功能辅助调试: - **GPU 呈现模式分析**:可视化渲染性能(Settings > Developer options > Profile GPU rendering)。 - **调试 GPU 过度绘制**:显示界面过度绘制区域(Developer options > Debug GPU overdraw)。 - **强制 GPU 渲染**:强制使用 GPU 进行 2D 渲染(Developer options > Force GPU rendering)。 --- #### 3. **日志过滤与分析** 通过 `adb logcat` 过滤 HWUI 相关日志,查看渲染引擎状态和错误: ```bash adb logcat | grep -E "HWUI|OpenGLRenderer" ``` --- #### 4. **源码层验证** 若需深入调试,可参考以下源码逻辑: - **渲染引擎选择**:`ViewRootImpl.java` 中通过 `enableHardwareAcceleration()` 控制硬件加速的启用[^1]。 - **Skia 与 OpenGL 实现**:Skia 库路径为 `external/skia`,包含 2D 渲染实现[^5];OpenGL 相关逻辑在 `CanvasContext::draw()` 中触发[^2]。 --- #### 5. **配置文件调整(可选)** 部分系统级配置可通过修改 `settings_global.xml` 或 `settings_secure.xml` 实现[^3],但需系统权限或定制 ROM。 --- ### 注意事项 - **兼容性**:不同 Android 版本对 `debug.hwui.renderer` 的支持可能不同,需实测验证。 - **权限**:修改系统属性可能需要 root 权限。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值