在这里,我们将动态画面简称为动画(animation)。正如动画片的原理一样,动画的本质是利用了人眼的视觉暂留特性,快速地变换画面,从而产生物体在运动的假象。而对于Three.js程序而言,动画的实现也是通过在每秒中多次重绘画面实现的。

为了衡量画面切换速度,引入了每秒帧数FPS(Frames Per Second)的概念,是指每秒画面重绘的次数。FPS越大,则动画效果越平滑,当FPS小于20时,一般就能明显感受到画面的卡滞现象。

那么FPS是不是越大越好呢?其实也未必。当FPS足够大(比如达到60),再增加帧数人眼也不会感受到明显的变化,反而相应地就要消耗更多资源(比如电影的胶片就需要更长了,或是电脑刷新画面需要消耗计算资源等等)。因此,选择一个适中的FPS即可。

NTSC标准的电视FPS是30,PAL标准的电视FPS是25,电影的FPS标准为24。而对于Three.js动画而言,一般FPS在30到60之间都是可取的。

setInterval方法

如果要设置特定的FPS(虽然严格来说,即使使用这种方法,JavaScript也不能保证帧数精确性),可以使用JavaScript DOM定义的方法:

setInterval(func,msec)

其中,func是每过msec毫秒执行的函数,如果将func定义为重绘画面的函数,就能实现动画效果。setInterval函数返回一个id,如果需要停止重绘,需要使用clearInterval方法,并传入该id,具体的做法为:

requestAnimationFrame方法

大多数时候,我们并不在意多久重绘一次,这时候就适合用requestAnimationFrame方法了。它告诉浏览器在合适的时候调用指定函数,通常可能达到60FPS。

如何取舍

setInterval方法与requestAnimationFrame方法的区别较为微妙。一方面,最明显的差别表现在setInterval可以手动设定FPS,而requestAnimationFrame则会自动设定FPS;但另一方面,即使是setInterval也不能保证按照给定的FPS执行,在浏览器处理繁忙时,很可能低于设定值。当浏览器达不到设定的调用周期时,requestAnimationFrame采用跳过某些帧的方式来表现动画,虽然会有卡滞的效果但是整体速度不会拖慢,而setInterval会因此使整个程序放慢运行,但是每一帧都会绘制出来;

总而言之,requestAnimationFrame适用于对于时间较为敏感的环境(但是动画逻辑更加复杂),而setInterval则可在保证程序的运算不至于导致延迟的情况下提供更加简洁的逻辑(无需自行处理时间)。

开始工作

完成init函数

var requestAnimationFrame =window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame;

window.requestAnimationFrame=requestAnimationFrame;var scene = null;var camera = null;var renderer = null;var id = null;var stat = null;

function init() {

stat= newStats();

stat.domElement.style.position= 'absolute';

stat.domElement.style.right= '0px';

stat.domElement.style.top= '0px';

document.body.appendChild(stat.domElement);

renderer= newTHREE.WebGLRenderer({

canvas: document.getElementById('mainCanvas')

});

scene= newTHREE.Scene();

id=requestAnimationFrame(draw);

}

function draw() {

stat.begin();

renderer.render(scene, camera);

id=requestAnimationFrame(draw);

stat.end();

}

function stop() {if (id !== null) {

cancelAnimationFrame(id);

id= null;

}

}

然后,为了实现弹球弹动的效果,我们创建一个球体作为弹球模型,创建一个平面作为弹球反弹的平面。为了在draw函数中改变弹球的位置,我们可以声明一个全局变量ballMesh,以及弹球半径ballRadius。

var ballMesh = null;var ballRadius = 0.5;

在init函数中添加球体和平面,使弹球位于平面上,平面采用棋盘格图像作材质:

//ball

ballMesh = new THREE.Mesh(new THREE.SphereGeometry(ballRadius, 16, 8),newTHREE.MeshLambertMaterial({

color:0xffff00}));

ballMesh.position.y=ballRadius;

scene.add(ballMesh);//plane

var texture = THREE.ImageUtils.loadTexture('../img/chess.png', {}, function() {

renderer.render(scene, camera);

});

texture.wrapS= texture.wrapT =THREE.RepeatWrapping;

texture.repeat.set(4, 4);var plane = new THREE.Mesh(new THREE.PlaneGeometry(5, 5),newTHREE.MeshLambertMaterial({map: texture}));

plane.rotation.x= -Math.PI / 2;

scene.add(plane);

现在,每帧绘制的都是相同的效果:

为了记录弹球的状态,我们至少需要位置、速度、加速度三个矢量,为了简单起见,这里弹球只做竖直方向上的自由落体运动,因此位置、速度、加速度只要各用一个变量表示。其中,位置就是ballMesh.position.y,不需要额外的变量,因此我们在全局声明速度v和加速度a:

var v = 0;var a = -0.1;

这里,a = -0.1代表每帧小球向y方向负方向移动0.1个单位。

一开始,弹球从高度为maxHeight处自由下落,掉落到平面上时会反弹,并且速度有损耗。当速度很小的时候,弹球会在平面上作振幅微小的抖动,所以,当速度足够小时,我们需要让弹球停止跳动。因此,定义一个全局变量表示是否在运动,初始值为false:

var isMoving = false;

在HTML中定义一个按钮,点击按钮时,弹球从最高处下落:

function drop() {

isMoving= true;

ballMesh.position.y=maxHeight;

v= 0;

}

下面就是最关键的函数了,在draw函数中,需要判断当前的isMoving值,并且更新小球的速度和位置:

function draw() {

stat.begin();if(isMoving) {

ballMesh.position.y+=v;

v+=a;if (ballMesh.position.y <=ballRadius) {//hit plane

v = -v * 0.9;

}if (Math.abs(v) < 0.001) {//stop moving

isMoving = false;

ballMesh.position.y=ballRadius;

}

}

renderer.render(scene, camera);

id=requestAnimationFrame(draw);

stat.end();

}

这样就实现小球的弹动效果了。最终的代码为:

var requestAnimationFrame =window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame;

window.requestAnimationFrame=requestAnimationFrame;var scene = null;var camera = null;var renderer = null;var id = null;var stat = null;var ballMesh = null;var ballRadius = 0.5;var isMoving = false;var maxHeight = 5;var v = 0;var a = -0.01;

function init() {

stat= newStats();

stat.domElement.style.position= 'absolute';

stat.domElement.style.right= '0px';

stat.domElement.style.top= '0px';

document.body.appendChild(stat.domElement);

renderer= newTHREE.WebGLRenderer({

canvas: document.getElementById('mainCanvas')

});

scene= newTHREE.Scene();

camera= new THREE.OrthographicCamera(-5, 5, 3.75, -3.75, 0.1, 100);

camera.position.set(5, 10, 20);

camera.lookAt(new THREE.Vector3(0, 3, 0));

scene.add(camera);//ball

ballMesh = new THREE.Mesh(new THREE.SphereGeometry(ballRadius, 16, 8),newTHREE.MeshLambertMaterial({

color:0xffff00}));

ballMesh.position.y=ballRadius;

scene.add(ballMesh);//plane

var texture = THREE.ImageUtils.loadTexture('../img/chess.png', {}, function() {

renderer.render(scene, camera);

});

texture.wrapS= texture.wrapT =THREE.RepeatWrapping;

texture.repeat.set(4, 4);var plane = new THREE.Mesh(new THREE.PlaneGeometry(5, 5),newTHREE.MeshLambertMaterial({map: texture}));

plane.rotation.x= -Math.PI / 2;

scene.add(plane);var light = new THREE.DirectionalLight(0xffffff);

light.position.set(10, 10, 15);

scene.add(light);

id=requestAnimationFrame(draw);

}

function draw() {

stat.begin();if(isMoving) {

ballMesh.position.y+=v;

v+=a;if (ballMesh.position.y <=ballRadius) {//hit plane

v = -v * 0.9;

}if (Math.abs(v) < 0.001) {//stop moving

isMoving = false;

ballMesh.position.y=ballRadius;

}

}

renderer.render(scene, camera);

id=requestAnimationFrame(draw);

stat.end();

}

function stop() {if (id !== null) {

cancelAnimationFrame(id);

id= null;

}

}

function drop() {

isMoving= true;

ballMesh.position.y=maxHeight;

v= 0;

}

链接:http://runjs.cn/detail/ecll36ex

要好好复习一下物理和数学了

threejs 绘制球体_【webGl】threejs实现一个简单的动画-弹跳的小球相关推荐

  1. threejs 绘制球体_实战:用 threejs 创建一个地球

    原标题:实战:用 threejs 创建一个地球 提示: 讲座 前端大型免费公开课讲座 教程 从零基础学前端教程,都在这~ 上个月底,在朋友圈看到一个号称"这可能是地球上最美的h5" ...

  2. threejs 绘制球体_javascript – 使用ThreeJS获取球体纹理上的点击位置

    目前:我有一个球体,其上有一个围绕y轴旋转的纹理.我也有在3D空间中点击的位置,以及球体上的旋转位置(我认为). 目标:获取纹理上的位置,例如:我想获得我点击的图像的正方形. (参见下面的示例球体和图 ...

  3. pr如何跳到关键帧_PR教程 如何利用pr制作一个简单的动画

    Adobe Premiere Pro简称PR,是一款非常不错的视频制作编辑软件,如何如何利用pr制作一个简单的动画,这里小编为大家带来了pr动画制作教程--利用pr制作动画,一起来学习一下吧! Ado ...

  4. threejs 绘制球体_3D可视化库-Threejs调研及简单示例

    0 背景 WebGL是一种3D绘图协议,其允许JavaScript和OpenGL ES2.0结合在一起,为H5 Canvas提供硬件3D加速渲染,可以借助系统显卡在浏览器里更流畅地显示3D场景和模型. ...

  5. threeJS绘制球体

    使用three.js绘制球体 实现思路: 1. 生成三大组件:场景.相机.渲染器: 2. 场景添加光源: 3. 场景添加球体,并为球体添加纹理贴图: 4. 循环渲染. 首先,初始化变量,包括用到的渲染 ...

  6. d3js绘制y坐标轴_用d3js创建一个简单的矩形图

    用d3js创建一个简单的矩形 前言 本文并不是针对初学者的教程, 而是对矩形图绘制的基本流程做一个总结, 整理一下d3的基本工作流程. 正文 用d3创建矩形图一般分为下面几个步骤 flow.png b ...

  7. 基于python的系统构建_利用python构建一个简单的推荐系统

    摘要: 快利用python构建一个属于你自己的推荐系统吧,手把手教学,够简单够酷炫. 本文将利用python构建一个简单的推荐系统,在此之前读者需要对pandas和numpy等数据分析包有所了解. 什 ...

  8. hashmap 从头到尾_如何从头到尾设计一个简单的复古徽标

    hashmap 从头到尾 在纸上素描粗糙的概念 (Sketch rough concepts on paper) Start by sketching out a few ideas for your ...

  9. python推荐_利用Python构建一个简单的推荐系统

    原标题:利用Python构建一个简单的推荐系统 摘要:快利用python构建一个属于你自己的推荐系统吧,手把手教学,够简单够酷炫.在此之前读者需要对pandas和numpy等数据分析包有所了解. 什么 ...

最新文章

  1. shell操作典型案例--FTP操作
  2. mysql ibdata作用_mysql data文件夹下ibdata1 文件作用
  3. 【python】排序算法的稳定性冒泡排序(画图详细讲解)
  4. 浅析Memcache和Redis
  5. Google App Engine JAX-RS REST服务
  6. 前端学习(2914):差值表达式的用法
  7. 数据结构之单链表(头结点)的一些常用操作(增删改查逆)
  8. The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
  9. 使用kettle导入数据到ADB for PostgreSQL
  10. Vue2.0全家桶实现一个买买买提醒应用
  11. 前端开发面试题总结-代码篇
  12. 用SeaMonkey写cnblogs博客时碰到的问题
  13. WinSCP无法连接linux,而secureCRT却可以
  14. 终面后拿offer几率_战绩 | 恭喜VIP学员斩获德勤(北京)风险分析师全职Offer!...
  15. Linux命令 uname:查看系统与内核相关信息
  16. 使用delphi开发人工智能程序(环境搭建)
  17. iOS开发者必备:五大编程类工具
  18. csp202112-1:序列查询 题解
  19. 局域网如何设置服务器
  20. 脑机接口技术介绍、应用与挑战

热门文章

  1. xp wifi android,《解决没无线路由照样WIFI,笔记本xp系统建立wifi使手机上网 - 游戏 - MIUI官方论坛 - 发烧友必刷的Android ROM》.doc...
  2. 海纳云智慧城市白皮书 附下载
  3. 操作系统系列七 —— 装载
  4. 大话Mysql三:mysql 备份恢复之 物理备份与逻辑备份的区别比较
  5. 电机调速matlab仿真书,双闭环直流电机调速的matlab仿真.doc
  6. 教你区别瓷片电容、独石电容、陶瓷电容的区别
  7. 7大运维监控系统|总有合适你的业务
  8. Mediapipe框架学习
  9. 大数据-你投的简历真的是你认为的工作么?
  10. matlab绝对均值,在K-Means算法中使用绝对皮尔逊相关作为距离(MATLAB)