画一个妹子陪着你 | 情人节特辑

662 阅读2分钟

情人节快乐!又到了一年一度的情人节,今年依然是 new 一个对象吗?来用代码画一个吧。

说搞就搞,Let's go ~

实现方案

基于 Android 平台,使用 Kotlin + C++ 的方式实现。

上层负责 UI 相关,以及监听用户交互事件,并通过 JNI 交给 Native 层做具体响应。

Native 层则负责模型的解析、视图变换、Shader 渲染等逻辑。

-w554

主要的 JNI 一览

// Surface 创建
external fun nativeSurfaceCreated(assertManager: AssetManager, modelDir: String, modelFile: String, animFile: String)
// Surface 调整
external fun nativeSurfaceChanged(width: Int, height: Int)
// Surface 绘制当前帧
external fun nativeDrawFrame()
// 通知触摸事件
external fun nativeTouchEvent(deltaX: Float, deltaY: Float)
// 相关生命周期事件
external fun nativeDestroy()
external fun nativePause()
external fun nativeResume()

3D 模型的解析

OpenGL 2.0 引入了管线的概念,从管线的流程来看,在栅格化之后,就变成了一个一个的点,然后通过 Fragment Shader 上色。

所以绘制复杂的 3D 模型,最终也是转成无数的点去渲染。事实上,点可以练成线,线可以连成面,面可以拼成一个完整的物体。

所以,我们需要把 3D 模型转成无数个点坐标才可以渲染。

Assimp(Open Asset Import Library)是一个很强大的开源库,支持把 40 多种格式的 3D 模型文件转成统一的格式,然后再按照再解析这个统一的格式即可。

关于 Assimp 的官网,公众号文章不能放外链,需要的直接 Google 就可以搜到。

Assimp 把模型文件转成了统一的格式,这个格式可以理解为是一颗二叉树,从 Root Node 开始,逐渐发散。假设 Root Node 在心脏的位置,那么就是从心脏遍布到全身。

通过对二叉树进行广度优先遍历,就可以拿到所有节点信息,进而拿到所有点的坐标信息。然后交给 OpenGL 进行渲染。

骨骼动画

3D 模型解析出坐标信息之后,结合纹理信息,就可以得到一个静态的图片。那么怎么做动画呢?

所谓动画,其实是各个点的一系列坐标点的有序变化,人眼看上去就是正常的动画了。

Assimp 解析出的统一格式,大致是一颗二叉树,二叉树的两个顶点之间的线,称为「骨骼」,做动画时,骨骼做仿射变换,带动附近的「肌肉」跟着联动,就像人做运动一样,骨骼带着肉体做运动。

类比骨骼带动肌肉群实现动画,谓之「骨骼动画」。

透视变换 与 Camera 视角变换

3D 效果的最直观的感觉就是「近大远小」。

Camera 视角变换,用来做旋转。

OpenGL_04_Cube

hero_male

呐,给你画了个对象

hero_female