夜间模式CodeSnippetStyle:
日间模式CodeSnippetStyle:

0%


Three中的动画实现-[three.js]

动画原理

动画的本质实际上就是快速地不断变化的图片,每张图片对比前后两张图片有细微的变化。整个连续的过程达到一定速度在我们人眼看来就是动画。人眼一般能区分的帧率是24帧。过低给人的感觉就会很不流畅。
和我们小时候看的动画书原理一样

js中动画实现原理

在js中,要实现动画,我们首先需要做的第一件事情,就是找到一个能够以特定时间间隔的方法重复渲染画面,在Three.js中就是重绘场景Scene。在HMTL5之前,JavaScript中的做法是使用JS API提供的定时器,setInterval(function,interval)方法,通过该方法,我们可以指定一个定时器,让他间隔的调用定时器函数,例如每隔100毫秒调用一次,在定时器的回调函数中,定义场景渲染。
但是通过setInterval方法,有一些很致命的问题,那就是该定时器函数并不会考虑浏览器发生的动作,例如,打开一个新的页面,该方法在后台还是会不断的执行。此外,setInterval函数并不是和重绘屏幕同步进行,这将会导致很高的CPU占用,性能会很差。

js中动画实现新方法

为了解决上述问题,现代浏览器提供了一个解决方案,那就是requestAnimationFrame方法。 通过该方法,你可以通过调用浏览器定义的方法,指定一个定时器。你的任何重绘都将在该提供的方法中进行。浏览器将会确保流畅高效地绘制场景,该方法的使用也非常简单,你只需要创建一个处理渲染的函数。如下示例:

function renderScene(){
    requestAnimationFrame(renderScene);
    renderer.render(scene,camera);
}

在该函数中,我们不断的调用本身,不断的重绘场景,实现动画效果。

一个示例:

以下是一个动画示例:

模型部分代码如下

function draw(scene,clock) {
var textureLoader  = new THREE.TextureLoader();
//太阳
var sun = new THREE.SphereGeometry(50,50,50);
var sunMaterial = new THREE.MeshPhongMaterial({
    map:textureLoader.load('./assets/2k_sun.jpg'),
    color:0xffaaaa,
    // wireframe:true
});
var sunModel = new THREE.Mesh(sun,sunMaterial);

sunModel.position.set(0,60,0)
sunModel.castShadow  = true;
//这个函数 每帧都会在渲染之前执行一次  所有的网格模型 都有这个方法
sunModel.onBeforeRender = function (renderer, scene, camera) {
    var elapsed =  clock.getElapsedTime();
    this.rotation.y += -Math.PI/120

}

scene.add(sunModel)

//地球
var sphereGeometry = new THREE.SphereGeometry(20,40,50);
var sphereMaterial = new THREE.MeshPhongMaterial({
    map:textureLoader.load('./assets/earth_atmos_2048.jpg'),
    specular:0x333333,
});
var sphere = new THREE.Mesh(sphereGeometry,sphereMaterial);
// sphere.position.y = 60
sphere.castShadow  = true;

//这个函数 每帧都会在渲染之前执行一次  所有的网格模型 都有这个方法
sphere.onBeforeRender = function (renderer, scene, camera) {
    var elapsed =  clock.getElapsedTime();
    this.position.set(Math.sin(elapsed)*200,60,Math.cos(elapsed)*200);
    this.rotation.y += -Math.PI/120

}

scene.add(sphere)

//月球
var moonGeometry = new THREE.SphereGeometry(5,40,50);
var moonMaterial = new THREE.MeshPhongMaterial({
    map:textureLoader.load('./assets/moon_1024.jpg'),
    specular:0x333333,

});
var moon = new THREE.Mesh(moonGeometry,moonMaterial);
// sphere.position.y = 60
moon.castShadow  = true;

//这个函数 每帧都会在渲染之前执行一次  所有的网格模型 都有这个方法
moon.onBeforeRender = function (renderer, scene, camera) {
    var elapsed =  clock.getElapsedTime();
    this.position.set((Math.sin(elapsed*5)*50+Math.sin(elapsed)*200),60,(Math.cos(elapsed)*200+Math.cos(elapsed*5)*50))
}

scene.add(moon)

}

控制更新以及初始化如下

function init() {
    var stats = initStats();
    var renderer = initRenderer();
    var camera = initCamera();
    var scene = new THREE.Scene();
    var clock = new THREE.Clock();
    // var elapsed =  Math.acos(clock.getDelta())

    initDefaultLighting(scene);
    initModel()
    initControls();
    render();
    draw(scene,clock);

    function initModel() {
        //辅助工具
        var helper = new THREE.AxesHelper(900);
        scene.add(helper);
        // var map = new THREE.TextureLoader().load("./assets/jay.jag");
        //外部盒子
        // var material = new THREE.MeshLambertMaterial({
        //     // map: map
        //     color: 0xffffff,
        // });
        // material.transparent = true;
        // material.opacity = 0.4;

        //--------------------------------地板--------------------------
        var planeGeometry = new THREE.PlaneGeometry(1000, 1000, 50, 50);
        var planeMaterial = new THREE.MeshBasicMaterial({
            color: 0xff0000,
            wireframe: true
        });
        planeMaterial.transparent = true;
        planeMaterial.opacity = 0.2;

        plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 0;
        plane.position.y = -6;
        plane.position.z = 0;


        //告诉底部平面需要接收阴影
        plane.receiveShadow = true;

        scene.add(plane);
        // scene.add(PlaneSegs);
        //--------------------------------地板end-----------------------
    }

    //初始化控制器
    var obtControls; //定义控制器变量
    function initControls() {
        //定义控制器核心           
        obtControls = new THREE.OrbitControls(camera, renderer.domElement);

        // 如果使用animate方法时,将此函数删除
        // controls.addEventListener('change', render);
        //以下都是为了满足各种需求的各种控制器配置参数
        obtControls.enableDampling = true; //使动画循环使用时阻尼或自转 意思是否有惯性
        obtControls.enableZoom = true; //是否允许缩放
        obtControls.enablePan = true; //是否开启鼠标右键拖拽
        obtControls.autoRotate = false; //是否允许自动旋转
        obtControls.dampingFactor = 0.25; //动态阻尼系数:就是鼠标拖拽旋转灵敏度
        obtControls.minDistance = 0; //设置相机距离原点的最近距离;
        obtControls.maxDistance = 1000; //设置相机距离原点的最远距离;

    }
    //控制更新
    function render() {
        stats.update();
        // fpControls.update(clock.getDelta());
        obtControls.update(clock.getDelta());
        requestAnimationFrame(render);
        renderer.render(scene, camera)
    }

}

该demo的完整代码在这里:Link

posted @ 2019-12-31 17:02  暮冬有八  阅读(2773)  评论(0编辑  收藏  举报
BACK TO TOP

😀迷海无灯听船行。Github WeChat