HarmonyOS 6 自定义人脸识别模型 4:OH_ArkUI_SurfaceHolder 绘制方式介绍

前面文章《HarmonyOS 6 自定义人脸识别模型 2:OH_NativeXComponent 方式绘制》、《HarmonyOS 6 自定义人脸识别模型 3:OH_NativeXComponent 基于 OpenGL 绘制》介绍了如何将 ArkTS 层的 XComponent 与 C++层的 OH_NativeXComponent 进行关联与映射,并使用 OpenGL 方式进行绘制。
使用 OH_NativeXComponent 方式存在一些弊端:
OH_NativeXComponent 实例生命周期与 XComponent 组件强相关,如果我们在 XComponent 组件销毁后仍然操作该对象将可能出现稳定性问题,造成应用的崩溃。
OH_NativeXComponent 提供的交互事件接口不够丰富,只提供基础的触摸、鼠标、键盘交互接口,我们如果想识别长按、拖拽等高级手势需要自己写识别逻辑。
HarmonyOS 提供了 OH_ArkUI_SurfaceHolder 来替代 OH_NativeXComponent 相关接口,文本接着介绍如何在 C++中通过 OpenGL 在 OH_ArkUI_surfaceHolder 中进行绘制等操作。
为什么要迁移到 OH_ArkUI_SurfaceHolder?
在 HarmonyOS 6 及更高版本中,推荐使用 OH_ArkUI_SurfaceHolder 配合 FrameNode 进行 Native 渲染。其核心优势在于:
更稳定的生命周期:
SurfaceHolder作为独立的对象管理,解耦了 Native 资源与组件树的直接绑定,提供了更显式的创建与销毁回调。丰富的事件体系:通过 ArkUI NDK 的
NodeEvent接口,可以接入更完整的手势系统,支持手势拦截、冒泡等高级控制。更灵活的组件管理:支持手动创建
FrameNode并在 Native 侧进行属性设置(如initialize),更符合现代复杂 UI 的按需渲染逻辑。
开发流程解析
1. ArkTS 层:手动绑定 Node
可以直接使用 XComponent 或者通过动态创建方式创建,这里我们通过native.bindNode(this.xComponentId, this.xComponent)将 XComponent 作为 FrameNode 手动绑定到 Native 侧。
2. Native 层:获取 SurfaceHolder 并注册回调
在 C++ 端,我们通过 NAPI 获取 Node 句柄,并创建对应的 SurfaceHolder。以下是核心实现及其系统函数的详细解析:
在 OnSurfaceChangedNative 回调中开启真正的绘制
系统函数详解
BindNode 方法中涉及到的系统 API 如下:
生命周期回调详解
在 SurfaceHolder 体系中,渲染逻辑通常分布在以下两个核心回调中:
OnSurfaceCreatedNative(OH_ArkUI_SurfaceHolder *holder):触发时机:当 XComponent 对应的底层 Surface 成功创建并在内存中准备好时触发。
职责:
通过
OH_ArkUI_XComponent_GetNativeWindow(holder)获取NativeWindow指针。执行 EGL 环境初始化(包括创建 Display、Config、Context 和 Surface)。
此时还不适合进行频繁绘制,因为尺寸可能尚未最终确定。
OnSurfaceChangedNative(OH_ArkUI_SurfaceHolder *holder, uint64_t width, uint64_t height):触发时机:Surface 尺寸发生变化(如组件初始化完成、转屏、分屏)时触发。首次创建后也会立即触发一次。
职责:
获取最新的
width和height像素值。更新 OpenGL 的 Viewport(视口区域)。
发起首帧绘制。这是确保应用启动后屏幕不黑屏的关键逻辑点。
在分屏交互中,此方法会被频繁调用以保证画面按比例缩放。
3. 触摸手势事件识别
使用 OH_ArkUI_SurfaceHolder 方式时,事件通过 onEvent 统一分发。需要特别注意的是触摸动作常量的对应:
代码实现示例:
触摸事件负责将 XComponent 上的触摸手势转化为 3D 物体(球体、立方体)的旋转效果。系统调用 onEvent 时会传入一个 event。代码首先过滤出触摸事件 (NODE_TOUCH_EVENT),并通过映射表找到该节点对应的 SurfaceHolder 和 EGLRender 渲染器实例。
当用户手指按下屏幕时,记录下当前的坐标。这作为后续计算滑动距离的“参考点”。
通过当前坐标与上一次坐标的差值 (
delta),确定用户滑动的方向和距离。通过 UpdateRotation 方法将
deltaX/Y累加到渲染器的偏航角 (yaw) 和仰角 (pitch) 变量中在 UpdateRotation 修改了 3D 变换变量后,立即调用 DrawSphere 重绘画面。由于 OpenGL 渲染极快,用户会感觉到 3D 物体在随手指实时旋转。
精准绘制:3D 球体逻辑实现
之前文章介绍的是五角星绘制,本问介绍一个具有高度立体感的 3D 红色球体的绘制。
几何生成
通过经纬度法(Spherical Coordinates)生成球体网格。为了提升立体感,我们将分段数设置为 64x32,确保曲面平滑无棱角。数学原理为球面上任意一点可通过参数方程 计算得出。这里生成了 64x32 个网格点,保证球面的圆滑度。
光照模型 (Blinn-Phong)
为了表现球体的立体感,我们在 CPU 端预计算了光照效果:
漫反射 (Diffuse):根据顶点法线与光源方向的点积计算。
镜面高光 (Specular):引入 Blinn-Phong 模型,计算半程向量(Halfway Vector),实现在球面上产生一个明亮的聚光点,营造金属或光滑材质的质感。
边缘光 (Rim Light):通过法线与视角方向的夹角计算增强轮廓感,使球体从背景中脱颖而出。下面是详细代码实现和说明:
效果
渲染出的球体可以触摸 XComponent 组件进行滑动旋转,通过改变光照参数看到不同效果。
总结
OH_ArkUI_SurfaceHolder 的引入是 HarmonyOS 原生开发向更稳健、更灵活架构演进的重要一步。它不仅解决了 XComponent 强耦合带来的稳定性隐患,还通过 ArkUI NDK 赋予了开发者更强大的交互控制能力。虽然迁移过程在事件常量匹配和节点初始化上需要更细致的对接,但换来的性能与可靠性提升是非常显著的。
示例代码地址:https://github.com/qingkouwei/ArkUISurfaceHolder
版权声明: 本文为 InfoQ 作者【轻口味】的原创文章。
原文链接:【http://www.infoq.cn/zones/harmonyos/article/7431509e8daaba5b1432bc930】。文章转载请联系作者。







评论