美文网首页
three.js(31)-帧动画

three.js(31)-帧动画

作者: 姜治宇 | 来源:发表于2023-01-09 11:35 被阅读0次

帧动画

之前用的gsap动画库可以帮我们做补间动画。也就是说,我们只需定义开始和末尾的状态,这之间的过渡效果动画库会帮我们填充上。
但是,有时我们需要播放一系列自定义的动作,比如我们想做一个小人做体操的动画,我们需要绘制小人的不同动作,也就是说,我们需要自定义帧去存储物体的运动数据。
以一个普通物体为例,我们可以先绘制出这个物体的运动轨迹,然后定义出每一帧的动作,然后连贯起来就可以了。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="http://www.yanhuangxueyuan.com/threejs/build/three.min.js"></script>
    <script src="http://www.yanhuangxueyuan.com/threejs/examples/js/controls/OrbitControls.js"></script>

</head>


<body>
    <div id="webgl"></div>
</body>

</html>
<script>
    //场景
    var scene = new THREE.Scene();

    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 0, 100);
    scene.add(camera);//添加相机

    //添加坐标轴
    var axes = new THREE.AxesHelper(500);//500表示xyz轴的长度,红:x,绿:y,蓝:z
    scene.add(axes);
    //===========================================================================//
    const box = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshBasicMaterial({ color: 0x0000ff }));
    scene.add(box);
    box.position.set(-10, -50, -50);
    const curve = new THREE.CatmullRomCurve3([
        new THREE.Vector3(-10, -50, -50),
        new THREE.Vector3(10, 0, 0),
        new THREE.Vector3(8, 50, 50),
        new THREE.Vector3(-5, 0, 100)
    ]);
    const points = curve.getPoints(100);//将曲线切分100份,总共是101个顶点
    console.log(points);//101个点
    const geometry = new THREE.BufferGeometry().setFromPoints(points);//创建一个空几何体,用来存储顶点

    const line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0xff00ff }));
    scene.add(line);
    // 声明一个数组用于存储时间序列
    let arr = [];
    for (let i = 0; i < 101; i++) {
        arr.push(i);
    }
    // 生成一个时间序列
    var times = new Float32Array(arr);

    var posArr = [];
    points.forEach(elem => {
        posArr.push(elem.x, elem.y, elem.z);
    });
    // 创建一个和时间序列相对应的位置坐标系列
    var values = new Float32Array(posArr);
    // 创建一个帧动画的关键帧数据,曲线上的位置序列对应一个时间序列
    var posTrack = new THREE.KeyframeTrack('.position', times, values);
    let duration = 101;
    let clip = new THREE.AnimationClip("default", duration, [posTrack]);
    var mixer = new THREE.AnimationMixer(box);

    let AnimationAction = mixer.clipAction(clip);
    AnimationAction.timeScale = 20;
    AnimationAction.play();
    //===========================================================================//
    var renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
    });//画布
    renderer.setSize(window.innerWidth, window.innerHeight);//设置渲染区域尺寸
    renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色

    document.getElementById('webgl').appendChild(renderer.domElement);



    var controls = new THREE.OrbitControls(camera, renderer.domElement);


    window.addEventListener('resize', () => {
        camera.aspect = window.innerWidth / window.innerHeight;

        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);



    });
    var clock = new THREE.Clock();//声明一个时钟对象

    function animate() {

        renderer.render(scene, camera);//开始渲染

        requestAnimationFrame(animate);

        if (mixer) {

            mixer.update(clock.getDelta());
        }
    }

    animate();
</script>
GIF 2023-1-10 11-22-22.gif

模型的帧动画

在枪战小游戏中,敌人中弹倒地到消失,这是一个完整的动作,需要自定义完成。
不过这个工作一般在做模型时就会完成,我们只需播放这个动画即可。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="http://www.yanhuangxueyuan.com/threejs/build/three.min.js"></script>
    <script src="http://www.yanhuangxueyuan.com/threejs/examples/js/controls/OrbitControls.js"></script>
    <script src="http://www.yanhuangxueyuan.com/threejs/examples/js/loaders/GLTFLoader.js"></script>
    <script src="http://www.yanhuangxueyuan.com/threejs/examples/js/loaders/DRACOLoader.js"></script>
</head>

<body>
    <div id="webgl"></div>

</body>

</html>
<script>
    //场景
    var scene = new THREE.Scene();

    var camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 0, 100);
    scene.add(camera);//添加相机

    //添加坐标轴
    var axes = new THREE.AxesHelper(500);//500表示xyz轴的长度,红:x,绿:y,蓝:z
    scene.add(axes);



    addGlb();
    var mixer;//更新帧要用到
    async function addGlb() {
        const loader = new THREE.GLTFLoader();
        const dracoloader = getDracoLoader();
        loader.setDRACOLoader(dracoloader);//注入loader

        const city = await loadGlb('./model/city.glb', loader);

        scene.add(city.scene);
        city.scene.traverse(child => {
            if (child.name === '热气球') {
                
                // 混合动画
                mixer = new THREE.AnimationMixer(child);//初始化
                // 裁剪动画
                const clip = city.animations[0];
                const action = mixer.clipAction(clip);
                action.play();
            }

        });

    }

    function getDracoLoader() {
        //对模型解压
        const dracoloader = new THREE.DRACOLoader();
        dracoloader.setDecoderPath("./draco/");//把examples\jsm\libs\draco这个文件夹复制过来
        dracoloader.setDecoderConfig({ type: "js" })
        dracoloader.preload();
        return dracoloader;
    }
    function loadGlb(filepath, loader) {
        return new Promise((resolve, reject) => {

            loader.setCrossOrigin('Anonymous');//跨域问题
            loader.load(filepath, (gltf) => {
                console.log('gltf>>>', gltf);
                //处理材质丢失的情况
                gltf.scene.traverse(child => {
                    if (child.isMesh) {
                        child.material.emissive = child.material.color;
                        child.material.emissiveMap = child.material.map;
                    }
                });
                resolve(gltf);
            }, undefined, (error) => {

                console.error(error);
                reject(error);

            });
        });
    }
    var renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
    });//画布
    renderer.setSize(window.innerWidth, window.innerHeight);//设置渲染区域尺寸
    renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色

    document.getElementById('webgl').appendChild(renderer.domElement);



    var controls = new THREE.OrbitControls(camera, renderer.domElement);


    window.addEventListener('resize', () => {
        camera.aspect = window.innerWidth / window.innerHeight;

        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);



    });

   

    var clock = new THREE.Clock();
    function animate() {

        renderer.render(scene, camera);//开始渲染
        if(mixer) {
            mixer.update(clock.getDelta());
        }
        requestAnimationFrame(animate);

    }
   animate();

</script>
GIF 2023-1-10.gif

相关文章

  • three.js(31)-帧动画

    帧动画 之前用的gsap动画库可以帮我们做补间动画。也就是说,我们只需定义开始和末尾的状态,这之间的过渡效果动画库...

  • 手机影音04

    阅读原文 29-音乐列表AudioPager 30-音乐播放器页面-动画列表-帧动画 播放动画 31-创建服务和创...

  • cocos creator (1) ——帧动画

    帧动画 整体流程 帧动画,就是通过一系列图片定义动画表现的动画形式,首先我们需要动画运行所需的所有帧。 这些帧通常...

  • css动画

    css动画首先要明白动画是一帧一帧的,由多个帧拼起来的动画 @keyframes 此为动画样式中的关键帧,用关键帧...

  • Android开发之帧动画

    Android动画主要分为3种 View动画(Android开发之View动画) 帧动画 属性动画 何为帧动画? ...

  • 对WindowManager中的View设置动画

    1.直接对View设置传统动画 传统动画包括帧动画和补间动画。帧动画主要是一帧一帧的播放。可以在xml中使用 标签...

  • 记录ProgressBar实现Loading

    旋转 旋转资源 帧动画效果 帧动画效果资源

  • Android动画详解(一)补间动画

    一、概述 Android中常用到的动画有三种,分别是:帧动画、补间动画和属性动画。 1、帧(Frame)动画 帧动...

  • android 动画基础

    分类 :帧动画 (图片动画)视图动画属性动画 帧动画 :有多个图片组成方法 :· AnimationDrawab...

  • Android 动画总结

    Android 中的动画可以分为以下几类: 逐帧动画 补间动画 属性动画 一、逐帧动画 逐帧动画的原理就是让一系列...

网友评论

      本文标题:three.js(31)-帧动画

      本文链接:https://www.haomeiwen.com/subject/jtipcdtx.html