系列文章:
1.基于BLE SoC芯片GR5526开发GPU 3D图形效果(1) - 概览
2.基于BLE SoC芯片GR5526开发GPU 3D图形效果(2) - 先看Demo效果
3.基于BLE SoC芯片GR5526开发GPU 3D图形效果(3) - GPU知识概念梳理
4.基于BLE SoC芯片GR5526开发GPU 3D图形效果(4) - 解析第一个GPU工程
5.基于BLE SoC芯片GR5526开发GPU 3D图形效果(5) - 理解图形学中的矩阵变换
6.基于BLE SoC芯片GR5526开发GPU 3D图形效果(6) - 开发炫酷新动画
前言: 这个专题的几篇文章下来, 对汇顶GR5526 的特点和图形化能力, 总体有了一个熟悉和理解. 可不可以在 GR5526 SDK 的基础上, 再开发出一些新的动画效果, 来应用到产品上, 让产品更炫酷一些呢? 毕竟这就是 GPU 应该具备的能力和强项. 答案必定是可以的.
结合前面的知识点, 再深入看了下 graphics_animation_effects 和 graphics_rotate_box 示例工程的参考代码, 这篇文章来开发一个新效果.
一、绘制旋转立方体的MVVP 矩阵变换逻辑
1. 定义立方体8个点(x,y,z)的初始坐标
坐标系为 X向右Y向下Z向后. 参考上图
- box_size_2 设置0.2, 是对立方体进行了缩小处理
- FoV 是一个经验值, 参考上一篇文章, 可以根据效果进行条件
- v[] 定义了 立方体6个面8个点的NDC 坐标
float box_size_2 = 0.2f; float FoV = 28.0724869359f;
//x y z float v[] = {-box_size_2, -box_size_2, box_size_2, //0 0 box_size_2, -box_size_2, box_size_2, //1 3 box_size_2, box_size_2, box_size_2, //2 6 -box_size_2, box_size_2, box_size_2, //3 9 -box_size_2, -box_size_2,-box_size_2, //4 12 box_size_2, -box_size_2,-box_size_2, //5 15 box_size_2, box_size_2,-box_size_2, //6 18 -box_size_2, box_size_2,-box_size_2}; //7 21 |
2. 用参数组合(FoV=28.07, aspect=1, near=0.2, far=100) 构建透视投影矩阵
- 454/454 表示屏幕的宽高都为 454 像素, 正方屏, aspect 算下来为1
- Fov, Near 和 far 给的 经验值, 可以根据需要条件
hal_gfx_matrix4x4_t mvp; hal_gfx_mat4x4_load_perspective(mvp, FoV, (float)454/454, 0.2f, 100.f); |
3. M 变换
创建单位矩阵, 在其基础上分别进行基于 X/Y/Z 轴的角度旋转. 然后再进行 Z=1.8 轴向平移.
- 这里进行的是从局部空间到世界空间的模型变换(Model Transform)
hal_gfx_matrix4x4_t proj; hal_gfx_mat4x4_load_identity(proj); hal_gfx_mat4x4_rotate_X(proj, angle_x); hal_gfx_mat4x4_rotate_Y(proj, angle_y); hal_gfx_mat4x4_rotate_Z(proj, angle_z); hal_gfx_mat4x4_translate(proj, 0, 0, 2.f-box_size_2); |
4. P 变换和NDC 归一化处理
- 由于只存在单视觉, 就没有独立的View 变换 (或者可以将第3步视作 V 变换). 然后计算 M' = P * M, 得到 P变换结果, 但透视变换还没有完成, 需要在hal_gfx_mat4x4_obj_to_win_coords 中进一步NDC归一化处理
- 每个顶点坐标逐次调用接口hal_gfx_mat4x4_obj_to_win_coords, 进行: 空间剪切处理(裁切空间); NDC 归一化处理; 计算视口屏幕空间坐标
hal_gfx_mat4x4_mul(mvp, mvp, proj); int i; void * pic = s_canvas_buf; for (i = 0; i < 24; i+=3) { float w = 1.f; hal_gfx_mat4x4_obj_to_win_coords(mvp, 0.f, 0.f, 454, 454, 1.f, 100.f, &v[i ], &v[i+1], &v[i+2], &w); } |
5. 最后的Fragment 处理 - 纹理贴图
- 设置混合模式
- 配置透视剔除模式
- 进行纹理贴图, 完成从 剪切空间到屏幕空间的处理
//blend color with background hal_gfx_set_blend_fill(HAL_GFX_BL_SIMPLE ); //remove this to draw back sides also hal_gfx_tri_cull(HAL_GFX_CULL_NONE); //配置透视剔除模式 //进行 纹理贴图处理, 从 剪切空间到屏幕空间 _draw_cube_side(v, 0, 1, 2, 3, 0xA08b008b); //front _draw_cube_side(v, 4, 0, 3, 7, 0xA0228b22); //left _draw_cube_side(v, 1, 5, 6, 2, 0xA0ff4500); //right _draw_cube_side(v, 4, 5, 1, 0, 0xA0003366); //top _draw_cube_side(v, 3, 2, 6, 7, 0xA066cc99); //bottom _draw_cube_side(v, 5, 4, 7, 6, 0x60808080); //back |
通过分析旋转立方体的渲染和变换逻辑, 厘清了GPU涉及的矩阵变换和流水线处理, 接下来通过这套逻辑, 设计一个垂直面翻转效果.
二、基于GR5526 GPU设计垂直面翻转动画效果
1. 定义动画效果的NDC 坐标示意图
- 动画可以围绕Y轴进行顺时针或逆时针方向的翻转
- 动画只有正反两个面, 不是立方体形式
- 动画正反面可以进行纹理贴图
/************************************************* * Coordinate Axis * * 7 (Z) * * * * * * * * * * * **************************> (X) * * * * * * * * * * * * * * * * (Y) * V * ************************************************* * * 围绕Y轴的翻转动画 * **** 围绕Y轴的顺时针翻转动画示意图 * * 0_____1 0 /| 1 1_____0 * | | / | | | * | | ------> | | ------> | | * |_____| | | |_____| * 3 2 3\ | 2 3 * \| 2 * * ****围绕Y轴的逆时针翻转动画示意图 * * 0_____1 0|\ 1_____0 * | | | \ 1 | | * | | ------> | | ------> | | * |_____| | | |_____| * 3 2 | / 2 2 3 * 3|/ * * ************************************************* */ |
2. 定义动画面NDC 坐标
- 由于动画是面翻转而非立体翻转, 因此只需定义一个面(存在正面和反面).
float v[12] = {-box_size_2, -box_size_2, 0, //0 box_size_2, -box_size_2, 0, //1 box_size_2, box_size_2, 0, //2 -box_size_2, box_size_2, 0, //3 }; |
3. 根据step定义旋转规则
float angle = step*180.f; if(is_clockwise) { // if(angle <= 90.0) { angle = angle; } else { angle = 180 + angle; } } else { if(angle <= 90.0) { angle = 180 - angle; } else { angle = 360 - angle; } } |
4. 构建透视投影矩阵并进行MVP 矩阵变换
hal_gfx_matrix4x4_t mvp; hal_gfx_mat4x4_load_perspective(mvp, FoV, 1.f, 1.f, 100.f); mvp[0][0] = mvp[1][1] = 2.f; hal_gfx_matrix4x4_t proj; hal_gfx_mat4x4_load_identity(proj); hal_gfx_mat4x4_rotate_Y(proj, angle); hal_gfx_mat4x4_translate(proj, 0.f, 0.f, 1.0f); // 向Z轴平移一个单位, 让界面产生一个视觉上的相对距离. hal_gfx_mat4x4_mul(mvp, mvp, proj); float w = 1.f; for (int i = 0; i <= 9; i+=3) { (void)hal_gfx_mat4x4_obj_to_win_coords(mvp, 0.f, 0.f, width, height, 1.f, 100.f, &v[i ], &v[i+1], &v[i+2], &w); } |
5. 最后, 根据是顺时针旋转还是逆时针旋转, 完成纹理贴图渲染即可.
- 要点
- 使用step 值来区分 第一、二个界面的分界
- 旋转方向, 有 angle 的范围与变化趋势觉得
- 注意 View 变化时候,需要将 画面向Z 轴移动一段距离. 产生一个视觉深度, 看起来舒服.
- v[0] / v[3] 的位置关系,也表明了旋转方向
三、效果及终章
下面来看看GR5526 GPU开发的新动画效果 - 基于Y轴的垂直翻转动画
这个效果是 Demo 性质的效果, 最终在产品效果呈现 更惊艳些。
经过这段时间对GR5526 GPU的学习, 及这几篇技术博客的梳理, 基本把 GR5526 GPU 的用法弄熟悉了,可以看出来, GR5526 GPU表现出的图形化能力和实现的3D动画效果是很不错的, 接下来等有时间把之前挖的几个坑给填一下.
另外抽时间再研究下GR5526 GPU版本 Lvgl 相对原生Lvgl 的优化情况, 因为实际产品中用GR5526 Lvgl 版本表现出来的帧率还是很不错的. 又挖个大坑 : )