You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 15:28:09