当前位置:网站首页>ThreeJS简介
ThreeJS简介
2022-08-03 17:12:00 【格格巫 MMQ!!】
近年来web得到了快速的发展。随着HTML5的普及,网页的表现能力越来越强大。网页上已经可以做出很多复杂的动画,精美的效果。 但是,人总是贪的。那么,在此之上还能做什么呢?其中一种就是通过WebGL在网页中绘制高性能的3D图形。
OpenGL,WebGL到Three.js
OpenGL它是最常用的跨平台图形库。
WebGL是基于OpenGL设计的面向web的图形标准,提供了一系列JavaScript API,通过这些API进行图形渲染将得以利用图形硬件从而获得较高性能。
而Three.js是通过对WebGL接口的封装与简化而形成的一个易用的图形库。
简单点的说法threejs=three + js,three表示3D的意思,js表示javascript的意思。那么合起来,three.js就是使用javascript 来写3D程序的意思。而javascript的计算能力因为google的V8引 擎得到了迅猛的增强,做3D程序,做服务器都没有问题。
WebGL门槛相对较高,需要相对较多的数学知识(线性代数、解析几何)。因此,想要短时间上手WebGL还是挺有难度的。 Three.js对WebGL提供的接口进行了非常好的封装,简化了很多细节,大大降低了学习成本。并且,几乎没有损失WebGL的灵活性。
因此,从Three.js入手是值得推荐的,这可以让你在较短的学习后就能面对大部分需求场景。
Three.js的学习问题
Three.js的入门是相对简单的,但是当我们真的去学的时候,会发现一个很尴尬的问题:相关的学习资料很少。
通常这种流行的库都有很完善的文档,很多时候跟着官方的文档或官方的入门教程学习就是最好的路线。但Three不是的,它的文档对初学者来说太过简明扼要。
不过官方提供了非常丰富的examples,几乎所有你需要的用法都在某个example中有所体现。但这些example不太适合用来入门,倒是适合入门之后的进一步学习。
这里推荐一些相对较好的教程:
Three.js入门指南 :这是一份很好的Three.js 轻量级入门教程,作者文笔很好,基础知识讲解得简明易懂。
Three.js开发指南(第一版中文版)
Learning Three.js- Second Edition
Learning Three.js:The JavaScript 3D Library for WebGL是现在不多的也是最好的Three.js入门书,比较全面地讲解了Three.js的各种功能。 如果有能力的话,建议阅读英文版第二版,出版于2015年,与现在的Three.js区别很小。 中文版翻译自出版于2012年的原书第一版,大部分概念是适用的,但很多细节已经有所改变。
Three.js入门教程 :这是对国外一份教程的翻译,一共六篇文章。讲解不多,更多的是展示各个基本功能怎么用。更适合有一些图形基础的同学。
当然,实际的学习过程中这些资料肯定是不太够的,遇到问题还是要自己去查资料。不过这里要提醒一下,Three.js的更新是相当频繁的,现在是r80版本,自2010年4月发布r1以来,这已经是第72个版本了(中间有的版本号跳过了)。因此,在网上找到的资料有些可能是不适合当前版本的,需要注意甄别(前面推荐的资料也都或多或少存在这样的问题)。
剖析源目录结构
先去下载代码,它的地址是: https://github.com/mrdoob/three.js。 如图所示:
用解压软件解开刚才的源码包,各个目录如下所示:
Build目录:包含两个文件,three.js 和three.min.js 。这是three.js最终被引用的文件。一个已经压缩,一个没有压缩的js文件。
Docs目录:这里是three.js的帮助文档,里面是各个函数的api,可惜并没有详细的解释。试图用这些文档来学会three.js是不可能的。
Editor目录:一个类似3D-max的简单编辑程序,它能创建一些三维物体。
Examples目录:一些很有趣的例子demo,可惜没有文档介绍。对图像学理解不深入的同学,学习成本非常高。
Src目录:源代码目录,里面是所有源代码。
Test目录:一些测试代码,基本没用。
Utils目录:存放一些脚本,python文件的工具目录。例如将3D-Max格式的模型转换为three.js特有的json模型。
.gitignore文件:git工具的过滤规则文件,没有用。
CONTRIBUTING.md文件:一个怎么报bug,怎么获得帮助的说明文档。
LICENSE文件:版权信息。
README.md文件:介绍three.js的一个文件,里面还包含了各个版本的更新内容列表。
Three.js中的一些概念
要在屏幕上展示3D图形,思路大体上都是这样的:
1、构建一个三维空间
Three中称之为场景(Scene)
2、选择一个观察点,并确定观察方向/角度等
Three中称之为相机(Camera)
3、在场景中添加供观察的物体
Three中的物体有很多种,包括Mesh,Line,Points等,它们都继承自Object3D类
4、将观察到的场景渲染到屏幕上的指定区域
Three中使用Renderer完成这一工作
Scene
场景是所有物体的容器,也对应着我们创建的三维世界。
Camera
坐标系
Camera是三维世界中的观察者,为了观察这个世界,首先我们要描述空间中的位置。 Three中使用采用常见的右手坐标系定位。
三维投影
Three中的相机有两种,分别是正投影相机THREE.OrthographicCamera和透视投影相机THREE.PerspectiveCamera。
正交投影与透视投影的区别如上图所示,左图是正交投影,物体发出的光平行地投射到屏幕上,远近的方块都是一样大的;右图是透视投影,近大远小,符合我们平时看东西的感觉。
1)正交投影相机
注:图中的”视点”对应着Three中的Camera。
这里补充一个视景体的概念:视景体是一个几何体,只有视景体内的物体才会被我们看到,视景体之外的物体将被裁剪掉。这是为了去除不必要的运算。
正交投影相机的视景体是一个长方体,OrthographicCamera的构造函数是这样的:
OrthographicCamera( left, right, top, bottom, near, far )
Camera本身可以看作是一个点,left则表示左平面在左右方向上与Camera的距离。另外几个参数同理。于是六个参数分别定义了视景体六个面的位置。
可以近似地认为,视景体里的物体平行投影到近平面上,然后近平面上的图像被渲染到屏幕上。
2)透视投影相机
透视投影相机的视景体是个四棱台,它的构造函数是这样的:
PerspectiveCamera( fov, aspect, near, far )
fov对应着图中的视角,是上下两面的夹角。aspect是近平面的宽高比。在加上近平面距离near,远平面距离far,就可以唯一确定这个视景体了。
透视投影相机很符合我们通常的看东西的感觉,因此大多数情况下我们都是用透视投影相机展示3D效果。
Objects
有了相机,总要看点什么吧?在场景中添加一些物体吧。
Three中供显示的物体有很多,它们都继承自Object3D类,这里我们主要看一下Mesh和Points两种。
1)Mesh
我们都知道,计算机的世界里,一条弧线是由有限个点构成的有限条线段连接得到的。线段很多时,看起来就是一条平滑的弧线了。
计算机中的三维模型也是类似的,普遍的做法是用三角形组成的网格来描述,我们把这种模型称之为Mesh模型。
这是那只著名的斯坦福兔子。它在3D图形中的地位与数字图像处理领域中著名的lena是类似的。
看这只兔子,随着三角形数量的增加,它的表面越来越平滑/准确。
在Three中,Mesh的构造函数是这样的:
Mesh( geometry, material )
geometry是它的形状,material是它的材质。
不止是Mesh,创建很多物体都要用到这两个属性。下面我们来看看这两个重要的属性。
2)Geometry
Geometry,形状,相当直观。Geometry通过存储模型用到的点集和点间关系(哪些点构成一个三角形)来达到描述物体形状的目的。
Three提供了立方体(其实是长方体)、平面(其实是长方形)、球体、圆形、圆柱、圆台等许多基本形状;
你也可以通过自己定义每个点的位置来构造形状;
对于比较复杂的形状,我们还可以通过外部的模型文件导入。
3)Material
Material,材质,这就没有形状那么直观了。
材质其实是物体表面除了形状以为所有可视属性的集合,例如色彩、纹理、光滑度、透明度、反射率、折射率、发光度。
这里讲一下材质(Material)、贴图(Map)和纹理(Texture)的关系。
材质上面已经提到了,它包括了贴图以及其它。
贴图其实是‘贴’和‘图’,它包括了图片和图片应当贴到什么位置。
纹理嘛,其实就是‘图’了。
Three提供了多种材质可供选择,能够自由地选择漫反射/镜面反射等材质。
4)Points
讲完了Mesh,我们来看看另一种Object——Points。
Points其实就是一堆点的集合,它在之前很长时间都被称为ParticleSystem(粒子系统),r68版本时更名为PointCloud,r72版本时才更名为Points。更名主要是因为,Mr.doob认为,粒子系统应当是包括粒子和相关的物理特性的处理的一套完整体系,而Three中的Points简单得多。因此最终这个类被命名为Points。
5)Light
神说:要有光!
光影效果是让画面丰富的重要因素。
Three提供了包括环境光AmbientLight、点光源PointLight、 聚光灯SpotLight、方向光DirectionalLight、半球光HemisphereLight等多种光源。
只要在场景中添加需要的光源就好了。
6)Renderer
在场景中建立了各种物体,也有了光,还有观察物体的相机,是时候把看到的东西渲染到屏幕上了。这就是Render做的事情了。
Renderer绑定一个canvas对象,并可以设置大小,默认背景颜色等属性。
调用Renderer的render函数,传入scene和camera,就可以把图像渲染到canvas中了。
让画面动起来
现在,一个静态的画面已经可以得到了,怎么才能让它动起来?
很简单的想法,改变场景中object的位置啊角度啊各种属性,然后重新调用render函数渲染就好了。
那么重新渲染的时机怎么确定?
HTML5为我们提供了requestAnimFrame,它会自动在每次页面重绘前调用传入的函数。
如果我们一开始这样渲染:
function render()
{
renderer.render(scene, camera);
}
只需要改成这样:
function render()
{
requestAnimationFrame(render);
object.position.x += 1;
renderer.render(scene, camera);
}
object就可以动起来了!
举个例子
下面我们用一个简单的例子来梳理一下这个过程。
首先写一个有Canvas元素的页面吧。
function initRenderer() {
width = document.getElementById(‘three_canvas’).clientWidth;
height = document.getElementById(‘three_canvas’).clientHeight;
renderer = new THREE.WebGLRenderer({
//将Canvas绑定到renderer
canvas: document.getElementById(‘three_canvas’)
});
renderer.setSize(width, height);//将渲染的大小设为与Canvas相同
renderer.setClearColor(0xFFFFFF, 1.0);//设置默认颜色与透明度
}
初始化场景:
function initScene() {
scene = new THREE.Scene();
}
初始化相机:
function initCamera() {
//简单的正交投影相机,正对着视口的中心,视口大小与Canvas大小相同。
camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 1000);
//设置相机的位置
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 200;
//设置相机的上方向
camera.up.x = 0;
camera.up.y = 1;
camera.up.z = 0;
//设置相机聚焦的位置(其实就是确定一个方向)
camera.lookAt({
x: 0,
y: 0,
z: 0
});
}
要唯一确定一个相机的位置与方向,position、up、lookAt三个属性是缺一不可的。
这里我们创建了一个正交投影相机,这里我将视景体大小与屏幕分辨率保持一致只是为了方便,这样坐标系中的一个单位长度就对应屏幕的一个像素了。
我们将相机放在Z轴上,面向坐标原点,相机的上方向为Y轴方向,注意up的方向和lookAt的方向必然是垂直的(类比自己的头就知道了)。
下面添加一个立方体到场景中:
function initObject() {
//创建一个边长为100的立方体
var geometry = new THREE.CubeGeometry(100, 100, 100);
object = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());
scene.add(object);
}
注意我们使用了法向材质MeshNormalMaterial,这样立方体每个面的颜色与这个面对着的方向是相关的,更便于观察/调试。
在这个简单的demo里我不打算添加光影效果,而法向材质对光也是没有反应的。 最后来创建一个动画循环吧
function render() {
requestAnimationFrame(render);
object.rotation.x += 0.05;
object.rotation.y += 0.05;
renderer.render(scene, camera);
}
每次重绘都让这个立方体转动一点点。 当页面加载好时,调用前面这些函数就好了。
function threeStart() {
initRenderer();
initCamera();
initScene();
initObject();
render();
}
window.onload = threeStart();
边栏推荐
- sphinx coreseek的安装和php下使用
- Which thread pool does Async use?
- “LaMDA 存在种族歧视,谷歌的 AI 伦理不过是‘遮羞布’!”
- Components of communication - the drop-down menu
- J9数字虚拟论:元宇宙的潜力:一股推动社会进步的力量
- 工程仪器设备在线监测管理系统常见问题和注意事项
- 虹科分享 | 如何测试与验证复杂的FPGA设计(3)——硬件测试
- [Unity Getting Started Plan] Basic Concepts (7) - Input Manager & Input Class
- 面试突击71:GET 和 POST 有什么区别?
- [Unity Getting Started Plan] Basic Concepts (6) - Sprite Renderer Sprite Renderer
猜你喜欢
设置海思芯片MMZ内存、OS内存详解
组件通信--下拉菜单案例
B站回应HR称核心用户是Loser;微博回应宕机原因;Go 1.19 正式发布|极客头条
“68道 Redis+168道 MySQL”精品面试题(带解析),你背废了吗?
论文解读(JKnet)《Representation Learning on Graphs with Jumping Knowledge Networks》
Auto Scaling 弹性伸缩(运维释放人力)
Description of the functional scenario of "collective storage and general governance" in the data center
Web3的开源为何会如此受到人们喜爱?
Web3 安全风险令人生畏?应该如何应对?
【指针初解】
随机推荐
【指针初解】
持续投入商品研发,叮咚买菜赢在了供应链投入上
Adobe是什么?
LeetCode·1163.按字典序排在最后的子串·最小表示法
浅谈Service Mesh对业务系统的价值
【机器学习】机器学习基本概念/术语3
A complete detailed tutorial on building intranet penetration ngrok (with pictures and truth)
FinClip | 2022 年 7 月产品大事记
The strongest distributed lock tool: Redisson
EMQX Newsletter 2022-07|EMQX 5.0 正式发布、EMQX Cloud 新增 2 个数据库集成
C专家编程 第1章 C:穿越时空的迷雾 1.10 “安静的改变”究竟有多少安静
大型企业数据治理的现状和解决方案有哪些参考?_光点科技
工程仪器设备在线监测管理系统常见问题和注意事项
【Metaverse系列一】元宇宙的奥秘
新特性解读 | MySQL 8.0 在线调整 REDO
102. 最佳牛围栏
论文解读(JKnet)《Representation Learning on Graphs with Jumping Knowledge Networks》
通用型安全监测数据管理系统
最强分布式锁工具:Redisson
面试突击:什么是粘包和半包?怎么解决?