【AR.js】在AR.js中使用spine动画

14 篇文章 0 订阅

说在前面

  • 测试浏览器:Microsoft Edge(PC版本 97.0.1072.55)
  • github库:AR.js
  • AR系列文章:这里
  • go版本:go version go1.17.3 windows/amd64
  • three.js版本:r79(版本比较老)
  • 其他:AR.js支持three.js
  • github地址:这里

效果图

在这里插入图片描述

代码

<!DOCTYPE html>
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<!-- three.js library -->
<script src='/js/three.js'></script>
<script src="/js/spine-threejs.js"></script>
<!-- ar.js -->
<script src="/js/ar.js"></script>

<script>THREEx.ArToolkitContext.baseURL = '../'</script>

<body style='margin : 0px; overflow: hidden; font-family: Monospace;'>
    <div style='position: absolute; top: 10px; width:100%; text-align: center; z-index: 1;'>

    </div>
    <script>
        //
        //		初始化
        //

        // 通过three.js初始化webgl渲染器
        var renderer = new THREE.WebGLRenderer({
            antialias: true,
            alpha: true
        });
        renderer.setClearColor(new THREE.Color('lightgrey'), 0)
        renderer.setSize(640, 480);
        renderer.domElement.style.position = 'absolute'
        renderer.domElement.style.top = '0px'
        renderer.domElement.style.left = '0px'
        document.body.appendChild(renderer.domElement);

        // 主渲染循环中使用到的渲染函数
        var onRenderFcts = [];

        // 使用three.js初始化场景
        var scene = new THREE.Scene();

        // 加载spine数据
        var assetManager = new spine.threejs.AssetManager();
        assetManager.loadText("assets/build_char_291_aglina_boc_1.json");
        assetManager.loadText("assets/build_char_291_aglina_boc_1.atlas");
        assetManager.loadTexture("assets/build_char_291_aglina_boc_1.png");


        //
        //		初始化相机
        //

        // 使用three.js创建一个相机
        var camera = new THREE.Camera();
        scene.add(camera);

        
        //      ar.js初始化
        

        var arToolkitSource = new THREEx.ArToolkitSource({
            // webcam源
            sourceType: 'webcam',
        })

        arToolkitSource.init(function onReady() {
            setTimeout(() => {
                onResize()
            }, 2000);
        })

        // 处理浏览器resize事件
        window.addEventListener('resize', function () {
            onResize()
        })

        // resize回调
        function onResize() {
            arToolkitSource.onResizeElement()
            arToolkitSource.copyElementSizeTo(renderer.domElement)
            if (arToolkitContext.arController !== null) {
                arToolkitSource.copyElementSizeTo(arToolkitContext.arController.canvas)
            }
        }
        
        //      ar.js初始化context
        


        // 创建context
        var arToolkitContext = new THREEx.ArToolkitContext({
            // 设置相机内参
            cameraParametersUrl: THREEx.ArToolkitContext.baseURL + '/assets/camera_para.dat',
            // 设置检测模式为mono,单目(通常指单摄像头)
            detectionMode: 'mono',
        })
        // 初始化
        arToolkitContext.init(function onCompleted() {
            // 将ar context计算的projectionMatrix复制给three.js创建的camera
            // 相当于调整three.js camera的内参
            camera.projectionMatrix.copy(arToolkitContext.getProjectionMatrix());
        })

        // 将以下函数放入渲染队列
        // 该函数的作用应该是将ar context捕获的真实相机数据渲染到web
        onRenderFcts.push(function () {
            if (arToolkitSource.ready === false) return

            arToolkitContext.update(arToolkitSource.domElement)

            // update scene.visible if the marker is seen
            scene.visible = camera.visible
        })

        
        //      使用ar.js创建three.js camera的控制器
        

        // 初始化ar.js控制器
        // 将该控制器绑定到three.js camera
        // 这一步相当于调整相机的外参
        var markerControls = new THREEx.ArMarkerControls(arToolkitContext, camera, {
            // 类型为pattern 标记
            type: 'pattern',
            // 标记数据,用于计算相机外参
            patternUrl: THREEx.ArToolkitContext.baseURL + '/assets/aglina.patt',

            changeMatrixMode: 'cameraTransformMatrix'
        })
        // as we do changeMatrixMode: 'cameraTransformMatrix', start with invisible scene
        scene.visible = false

        //
        //		渲染
        //

        // three.js场景渲染
        onRenderFcts.push(function (delta, now) {

            // update the animation
            skeletonMesh.update(delta);

            renderer.render(scene, camera);
        })

        // 准备spine数据
        function spineLoad(name, scale) {
            if (assetManager.isLoadingComplete()) {

                // 添加spine数据
                var atlas = new spine.TextureAtlas(assetManager.get("assets/build_char_291_aglina_boc_1.atlas"), function (path) {
                    return assetManager.get("assets/" + path);
                });
                var skeletonData = loadSkeleton("build_char_291_aglina_boc_1", 0.4);

                // 创建mesh
                skeletonMesh = new spine.threejs.SkeletonMesh(skeletonData);
                skeletonMesh.state.setAnimation(0, "Move", true);

                // 调整mesh scale 以及 rotation
                skeletonMesh.scale.set(0.01, 0.01, 0.01);
                skeletonMesh.rotation.set(-Math.PI / 2, 0, 0);

                scene.add(skeletonMesh)

                requestAnimationFrame(animate);
            } else requestAnimationFrame(spineLoad);
        }

        function loadSkeleton(name, scale) {
            // 加载texture
            atlas = new spine.TextureAtlas(assetManager.get("assets/" + name + ".atlas"), function (path) {
                return assetManager.get("assets/" + path);
            });

            // 创建AtlasAttachmentLoader
            atlasLoader = new spine.AtlasAttachmentLoader(atlas);

            // 解析json数据并创建SkeletonJson
            var skeletonJson = new spine.SkeletonJson(atlasLoader);

            // 设置缩放
            skeletonJson.scale = scale;
            var skeletonData = skeletonJson.readSkeletonData(assetManager.get("assets/" + name + ".json"));
            return skeletonData;
        }

        var lastTimeMsec = null
        function animate(nowMsec) {
            requestAnimationFrame(animate);
            // 时间
            lastTimeMsec = lastTimeMsec || nowMsec - 1000 / 60
            var deltaMsec = Math.min(200, nowMsec - lastTimeMsec)
            lastTimeMsec = nowMsec
            // 调用渲染函数
            onRenderFcts.forEach(function (onRenderFct) {
                onRenderFct(deltaMsec / 1000, nowMsec / 1000)
            })
        }

        // 递归调用
        requestAnimationFrame(spineLoad)
    </script>
</body>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值