Three.js基础入门

Three.js是一款开源的主流3D绘图JS引擎(名字Three就是3D的含义),原作者为Mr.Doob,项目地址为:https://github.com/mrdoob/three.js/。

Threejs主要的应用场景有:

  • 物联网3D可视化

随着物联网的发展,工业、建筑等各个领域与物联网相关Web项目网页交互界面都会呈现出3D化的趋势。 这种方式更为直观,开发成本也比较大。

物联网粮仓3D可视化案例:http://www.yanhuangxueyuan.com/3D/liangcang/index.html

image.png
  • 产品720在线预览

随着WebGL技术的持续推广,5G技术的持续推广,各种产品在线3D展示将会变得越来越普及,一些电商平台会通过3D模型取代2D图片。

服装在线预览:http://suit.xuantech.cn/

image.png
  • 数据可视化

与webgl相关的数据可视化主要是两方面,一方面是海量超大数据的可视化,另一方面是与3D相关的数据可视化。对于超大的海量数据而言,基于canvas、svg等方式进行web可视化,没有基于WebGL技术实现性能更好,对于3D相关的数据可视化基于WebGL技术,借助3D引擎Threejs可以很好的实现。

解析GeoJOSN数据中国GDP数据可视化:3D直方图:https://www.echartsjs.com/examples/zh/editor.html?c=transparent-bar3d&gl=1

image.png
  • H5/微信小游戏

通过Threejs开发的小游戏,可以直接部署在微信小程序或者web端,无需下载,方便传播。(eg.微信小游戏跳一跳) 开发3D类的H5小游戏或者微信小游戏,Three.js引擎是很好的选择。

image.png
  • 科教领域

在科教领域通过3D方式展示特定的知识相比较图像更为直观。

科研平台-蛋白质结构可视化案例:http://www.rcsb.org/3d-view/2JEN/1

image.png

  • 机械领域

  • WebVR

  • 家装室内设计相关

  • ....

创建第一个3D场景

为了真正能够让你的场景借助three.js来进行显示,我们需要以下几个对象:场景、相机和渲染器,这样我们就能透过摄像机渲染出场景。

场景——相机——渲染器

image.png

从实际生活中拍照或是使用三维渲染软件的角度理解,生活的场景对应一个虚拟的三维场景,相机对象就像生活中使用的相机一样可以拍照,只不过一个是拍摄真实的景物,一个是拍摄虚拟的景物,拍摄时还要设置相机的位置和角度以及投影方式。当创建好一个三维场景,设置好相机后,渲染器就可以执行拍照动作。

// 场景
var scene = new THREE.Scene();
// 摄像机
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
// 渲染器
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

three.js里有几种不同的相机,在这里,我们使用的是PerspectiveCamera(透视摄像机)。

视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的值是角度单位。

长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值。比如说,当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。

近截面(near)和远截面(far)。 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。未来为了获得更好的渲染性能,你将可以在你的应用程序里去设置它。

我们需要在应用程序里设置一个渲染器的尺寸。比如,可以使用所需要的渲染区域的宽高,来让渲染器渲染出的场景填充满应用程序。

最后一步将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。这就是渲染器用来显示场景给我们看的<canvas>元素。

添加立方体:

// 立方体几何对象
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
// 材质对象
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
// 网格对象
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
// 设置相机高度
camera.position.z = 5;

默认情况下,当我们调用scene.add()的时候,物体将会被添加到(0,0,0)坐标。但将使得摄像机和立方体彼此在一起。为了防止这种情况的发生,我们只需要将摄像机稍微向外移动一些即可。

渲染场景:

function handleRender() {
 // 渲染器渲染
 renderer.render(scene, camera);//执行渲染操作
 cube.rotation.x += 0.01;
 cube.rotation.y += 0.01;
}
// 20ms也就是刷新频率是50FPS(1s/20ms),每秒渲染50次
setInterval('handleRender()', 20);

在这里我们使用渲染器的render方法,把场景、相机对象作为参数,告诉浏览器根据相机的放置方式拍摄已经创建好的三维场景对象。

每执行一次渲染器对象WebGLRenderer的渲染方法.render(),浏览器就会渲染出一帧图像并显示在Web页面上。如果按照一定的周期不停地调用渲染方法.render()就可以不停地生成新的图像覆盖原来的图像。所以只要一边旋转立方体,一边重新渲染,就可以实现立方体的旋转效果。

结果

下面是完整的代码:

<!DOCTYPE html>
<html>
 <head>
 <title>My first three.js app</title>
 <style>
 body { margin: 0; }
 canvas { width: 100%; height: 100% }
 </style>
 </head>
 <body>
 <script src="js/three.js"></script>
 <script>
 var scene = new THREE.Scene();
 var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
 var renderer = new THREE.WebGLRenderer();
 renderer.setSize( window.innerWidth, window.innerHeight );
 document.body.appendChild( renderer.domElement );
 var geometry = new THREE.BoxGeometry( 1, 1, 1 );
 var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
 var cube = new THREE.Mesh( geometry, material );
 scene.add( cube );
 camera.position.z = 5;
 function handleRender() {
 // 渲染器渲染
 renderer.render(scene, camera);//执行渲染操作
 cube.rotation.x += 0.01;
 cube.rotation.y += 0.01;
 }
 // 20ms也就是刷新频率是50FPS(1s/20ms),每秒渲染50次
 setInterval('handleRender()', 20);
 </script>
 </body>
</html>
image.png

优化

requestAnimationFrame周期性渲染

前面的动画效果,使用了 setInterval 函数,实际开发中,为了更好的利用浏览器渲染,可以使用函数 requestAnimationFrame 代替 setInterval 函数, requestAnimationFramesetInterval 一样都是浏览器 window 对象的方法。

requestAnimationFrame 参数是将要被调用函数的函数名, requestAnimationFrame 调用一个函数不是立即调用而是向浏览器发起一个执行某函数的请求, 什么时候会执行由浏览器决定,一般默认保持60FPS的频率,大约每16.7ms调用一次 requestAnimationFrame 方法指定的函数,60FPS是理想的情况下,如果渲染的场景比较复杂或者说硬件性能有限可能会低于这个频率。

function render() {
 renderer.render(scene,camera);//执行渲染操作
 mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
 requestAnimationFrame(render);//请求再次执行渲染函数render
}
render();

使用以上代码替换setInterval部分即可。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容