如何在Sceneform中播放.glb模型动画并按顺序执行指定动画?
问题:Sceneform中实现GLB模型动画的顺序播放
我正在Android Studio中使用Sceneform和ArCore,以Java开发一款类似Pokemon Go的AR虚拟宠物应用,目前拥有一个包含多段动画的.glb模型。当前代码已能渲染模型,但无法实现动画的顺序播放,具体需求为先播放“Congratulate”动画,再播放“Approach”动画。
以下是我的代码:
import androidx.appcompat.app.AppCompatActivity; import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; import android.content.Context; import android.os.Build; import android.os.Bundle; import android.view.MotionEvent; import android.widget.Toast; import com.google.ar.core.Anchor; import com.google.ar.core.HitResult; import com.google.ar.core.Plane; import com.google.ar.sceneform.AnchorNode; import com.google.ar.sceneform.rendering.ModelRenderable; import com.google.ar.sceneform.rendering.Renderable; import com.google.ar.sceneform.ux.ArFragment; import com.google.ar.sceneform.ux.BaseArFragment; import com.google.ar.sceneform.ux.TransformableNode; import java.lang.ref.WeakReference; import java.util.Objects; public class MainActivity extends AppCompatActivity { private ArFragment arCam; //object of ArFragment Class private int clickNo = 0; //helps to render the 3d model only once when we tap the screen public static boolean checkSystemSupport(Activity activity) { //checking whether the API version of the running Android >= 24 that means Android Nougat 7.0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { String openGlVersion = ((ActivityManager) Objects.requireNonNull(activity.getSystemService(Context.ACTIVITY_SERVICE))).getDeviceConfigurationInfo().getGlEsVersion(); //checking whether the OpenGL version >= 3.0 if (Double.parseDouble(openGlVersion) >= 3.0) { return true; } else { Toast.makeText(activity, "App needs OpenGl Version 3.0 or later", Toast.LENGTH_SHORT).show(); activity.finish(); return false; } } else { Toast.makeText(activity, "App does not support required Build Version", Toast.LENGTH_SHORT).show(); activity.finish(); return false; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (checkSystemSupport(this)) { arCam = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.arCameraArea); //ArFragment is linked up with its respective id used in the activity_main.xml arCam.setOnTapArPlaneListener((hitResult, plane, motionEvent) -> { clickNo++; //the 3d model comes to the scene only when clickNo is one that means once if (clickNo == 1) { Anchor anchor = hitResult.createAnchor(); ModelRenderable.builder() .setSource(this, R.raw.hund) .setIsFilamentGltf(true) .build() .thenAccept(modelRenderable -> addModel(anchor, modelRenderable)) .exceptionally(throwable -> { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Somthing is not right" + throwable.getMessage()).show(); return null; }); } }); } else { return; } } private void addModel(Anchor anchor, ModelRenderable modelRenderable) { AnchorNode anchorNode = new AnchorNode(anchor); // Creating a AnchorNode with a specific anchor anchorNode.setParent(arCam.getArSceneView().getScene()); //attaching the anchorNode with the ArFragment TransformableNode model = new TransformableNode(arCam.getTransformationSystem()); model.setParent(anchorNode); //attaching the anchorNode with the TransformableNode model.setRenderable(modelRenderable); //attaching the 3d model with the TransformableNode that is already attached with the node model.select(); } }
解决方案
要实现指定动画的顺序播放,需利用Sceneform的AnimationData和AnimationInstance类,通过监听动画结束事件触发下一段动画。具体实现如下:
修改后的代码
首先在MainActivity中添加成员变量保存模型节点:
private TransformableNode petNode;
然后修改addModel方法,加入动画播放逻辑:
private void addModel(Anchor anchor, ModelRenderable modelRenderable) { AnchorNode anchorNode = new AnchorNode(anchor); anchorNode.setParent(arCam.getArSceneView().getScene()); petNode = new TransformableNode(arCam.getTransformationSystem()); petNode.setParent(anchorNode); petNode.setRenderable(modelRenderable); petNode.select(); // 启动顺序动画播放 playSequentialAnimations(modelRenderable); } private void playSequentialAnimations(ModelRenderable renderable) { // 获取"Congratulate"动画数据 AnimationData congratulateAnim = renderable.getAnimationData("Congratulate"); if (congratulateAnim == null) { Toast.makeText(this, "未找到Congratulate动画", Toast.LENGTH_SHORT).show(); return; } // 创建并播放第一段动画 AnimationInstance congratulateInstance = congratulateAnim.createInstance(); congratulateInstance.play(); // 设置动画结束监听,触发第二段动画 congratulateInstance.setOnAnimationEndListener(animationInstance -> { AnimationData approachAnim = renderable.getAnimationData("Approach"); if (approachAnim != null) { AnimationInstance approachInstance = approachAnim.createInstance(); approachInstance.play(); } else { Toast.makeText(this, "未找到Approach动画", Toast.LENGTH_SHORT).show(); } }); }
关键说明
- 确保GLB模型中的动画名称与代码中使用的
"Congratulate"、"Approach"完全一致(区分大小写)。 - 若需循环播放某段动画,可调用
animationInstance.setRepeatCount(AnimationInstance.REPEAT_INDEFINITELY)。 - 可通过
animationInstance.setSpeed(float speed)调整动画播放速度。
内容的提问来源于stack exchange,提问作者salomon
相关产品推荐
相关产品推荐

