Sceneform-EQR
简介
Sceneform-EQR是EQ基于sceneform(filament)扩展的一个用于安卓端的三维渲染器。
相关链接
Git仓库
- Sceneform-EQR
码云
- EQ-Renderer的示例工程
EQ-R相关文档
- 文档目录
- CSDN专栏
实现通过filament加载gltf模型动画
运行示例
注意
原录屏经过压缩,并转成gif。实际效果远优于gif图所展示。
在sceneform-eqr中使用
我在sceneform-eqr中对模型动画做了一层封装,简化了模型动画的使用。
示例
示例工程:Sceneform-EQR
关键类:GltfSampleScene.java
创建模型
之前的文档【Sceneform-EQR】使用EQ-R加载模型 ,已经详细介绍如何在场景(AR场景、普通三维场景)中加载一个模型,这里不再赘述。
主要是创建了一个Node对象,而下面的示例需要用到这个Node。
创建动画
在sceneform-eqr中,当执行Node#setRenderable(model)后,我们即可创建动画
其中,创建动画的代码示例如下:
public void createAnimation(Node node){
if (node.getRenderableInstance() == null) {
return;
}
int animationCount = node.getRenderableInstance().getAnimationCount();
if (animationCount > 0){
//创建动画参数(这里主要设置周期)
ARAnimationParameter parameter = new ARAnimationParameter();
parameter.setDuration(6000L);//设置播放周期
parameter.setRepeatMode(ARAnimationRepeatMode.INFINITE);//设置循环方式
//创建默认动画
ARAnimationModel animationModel = new ARAnimationModel(node);
animationModel.createAnimation(parameter);
//默认播放第一个索引的动画
animationModel.setCurrentIndex(0);
//播放动画
animationModel.play();
}
}
至此,若使用Sceneform-EQR,读取模型动画及加载的教程已结束。
后文将结合filament,详细介绍流程。
分界线
Filament调用解析
创建FilamentAsset
我们先看一段使用filament加载gltf模型的代码片段。
loader = new AssetLoader(engine,newUbershaderProvider(filamentEngine),EntityManager.get());
FilamentAsset filamentAssets = loader.createAsset(gltfByteBuffer);
其中,gltfByteBuffer
是通过InputStream读取gltf文件得到的Buffer
对象。我们通过loader的createAsset方法,得到了filamentAssets对象。
获取FilamentAnimator
现在,我们从filamentAssets
中获取FilamentAnimator
,并用存入List。
ArrayList<ModelAnimation> animations = new ArrayList<>();
//...省略其他代码
filamentAnimator = filamentAssets.getInstance().getAnimator();
animations = new ArrayList<>();
for (int i = 0; i < filamentAnimator.getAnimationCount(); i++) {
animations.add(new ModelAnimation(this,filamentAnimator.getAnimationName(i), i,filamentAnimator.getAnimationDuration(i),getRenderable().getAnimationFrameRate()));
}
这里使用到的ModelAnimation
,参考Sceneform-EQR中ModelAnimation.java。
也可不使用ModelAnimation.java,与后续updateSkinning时对应上就行。
更新骨骼动画
在每一帧(“doFrame”)绘制前,执行updateSkinning。
// 更新蒙皮skinning
if (updateAnimations(false)) {
updateSkinning();
}
updateAnimations(false)中,则是从之前的List中取出ModelAnimation
,将其应用。代码片段如下:
这里的关键是ModelAnimation.java中采用了不同的单位计算TimePosition,因此是个不错的参考。
public boolean updateAnimations(boolean force) {
boolean hasUpdate = false;
for (int i = 0; i < getAnimationCount(); i++) {
ModelAnimation animation = getAnimation(i);
if (force || animation.isDirty()) {
if (getFilamentAnimator() != null) {
getFilamentAnimator().applyAnimation(i, animation.getTimePosition());
}
animation.setDirty(false);
hasUpdate = true;
}
}
return hasUpdate;
}
undateSkinning方法则是更新FilamentAnimator的骨骼动画
private void updateSkinning() {
if (getFilamentAnimator() != null) {
getFilamentAnimator().updateBoneMatrices();
}
}
综上所述
若要在filament中使用3D模型自身的动画,需要通过FilamentAssets获取Animator对象,然后在每一帧绘制前,调用applyAnimation以修改当前进度值,然后再updateBoneMatrices即可。
当然,使用Sceneform-EQR,是最简单的。当前Sceneform-EQR已适配最新的filament依赖(v1.53.4),并已开源,欢迎有缘人加入。若有其他使用问题,请在git讨论。