转载自:lulu_upcss
https://segmentfault.com/a/1190000039647481html
开篇介绍
若是你没接触过3d可视化技术, 你也许会认为可视化很是难, 光是一个物体的阴影要如何计算就至关复杂, 可是告诉你个好消息, 阴影的计算都是集成好的, 而咱们只要设置好光源的位置,绘制好物体就能够了, 真的没有想象中那么复杂, 本文面向有前端基础,但零可视化基础的同窗, 我会从最基础的入门知识提及。前端
学习可视化方面的技术会让咱们对计算机, 对前端技术有更深的理解, 还能够作出更多有趣味的东西来, 本文是我踩了好多坑后总结出来的, 我更清楚一个初入门的小白哪里不懂。vue
three.js
是 webgl
的第三方库, 它更适合不太复杂的可视化项目, 而咱们要作的3d地球项目使用它来作会更简单, 因此选择了它, 放心后面也会说webgl
相关知识 。web
当前效果以下:面试
一. 关于此系列文章
-
自食其力:
不论是在公司仍是网上都有相似的库, 可是当遇到bug或是缺乏功能的状况时就会很麻烦, 例如咱们公司的FGL库(一个内网绘制3d景象的技术), 它官网上的例子不少都是错的, 使用起来也是一堆问题, 好比没法精准选择某个国家, 点击事件消融等bug。还好比说Echarts
的地球, 它太注重真实感而且用起来有点卡, 以及交互作的不太好。 -
直指核心:
去年我经过看书、看文章、看视频认真的学习three.js
, 并作出了3d地球这个项目, 而这个系列文章将会直指作出3d地图的核心知识, 尽可能不随意扩散知识面。 -
更好入门:
网上的教学文章千篇一概, 点进去阅读完感受其对于一个three.js
零基础的同窗来讲都不太好懂, 教学视频里的知识点太普遍, 事无巨细的罗列, 而这个系列文章将更突出绘制3d地球这个重点。 -
同道中人:
我学习three.js
就是为了作出3d地球, 期间走了很多弯路, 被某些问题卡了好久, 因此我更懂一个刚入门的人困惑的点在哪里。 -
专一vue:
市面上较少专门针对vue
作到开箱即用的3d地球插件, 而咱们就要编写这样一款产品。 -
不断学习:
编写文章也是我提升本身能力的一种方法, 死磕每一个知识点让本身的理解更上一层楼。
二. 任务目标
-
入门 three.js
技术。 -
绘制出3d地球。 -
作成专门 vue
使用的库。 -
后期也会介绍 着色器
的概念与基本的使用技巧。 -
会介绍少许 webgl
的相关用法, 而且会有部分数学知识。
三. 文章主线剧情与支线任务
-
主线剧情: 围绕着如何作出3d地球, 这部分在vue工程里面进行。 -
支线任务: 每一个分散的知识点, 可能与3d地球不要紧, 可是它能帮助咱们更好的理解3d技术, 而这些知识点我就不在vue项目里面演示了, 会单首创建一个html文件来演示说明。
四. 理解坐标系: 别着急写代码先有基本模型
像绘制图形这类技术, 最基本的概念就坐标系, 下图是二维坐标系
, 咱们的故事就从这个家伙开始。 咱们用
(0, 0)
表示坐标的中心点, 绘制一条起点为中心点长度为1的线段可使用 (0, 0) (1, 0)
这两个点相连表示。ajax
关于向量的概念后面须要用数学知识的时候再介绍, 前几篇文章就越通俗越好。
在three.js
中咱们要打交道的就是下面这位三维坐标系
他的坐标原点就是
(0, 0, 0)
, 绘制一条起点为中心点的长度为1的线段能够是 (0, 0, 0) (1, 0, 0)
。算法
这里要记住, three.js
里面设置的默认坐标系就是这种形式x向右, y向上, z向前
, 之因此说是默是由于它能够修改。编程
上图中, 观看这个三维坐标系的目光实际上是在斜上方, 正常状况下在咱们开发的时候z轴
是正对着咱们的眼睛的, 因此你只能看到z轴
是一个点,canvas
在开发与学习的时候, 最好先把坐标系绘制到页面上, 方便咱们更好的绘制。
五. 相机的概念
假设如今咱们的正前方有一个三维坐标系
的全息投影, 那么此时你的眼睛就至关于一架相机, 你看到的 坐标系
景象取决于你站的位置。
在three.js
中就有这样一个对象, 他就是负责从哪一个角度观察咱们绘制的3d世界, 也就是相机
这个概念的由来。
相机分为两种, 正投影相机和透视投影相机, 正投影相机就是你站的多远你看到的物体的大小都不变, 透视投影相机就是物体会近大远小
, 下面是张引用图 (图片来自网络)。

正投影相机能够用在工程制图
上, 或者能够作一些视觉欺骗小游戏。
本文主要目的是绘制3d地球因此主要使用透视投影相机
六. 绘制坐标系, 安放摄像机 (代码安排上)
引入three.js
, 能够把包下载到本地, 也能够直接获取在cdn上的资源, 引入以后全局会出现THREE
对象, 咱们就能够开始编程之旅了。
<script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>
一个普普统统的html空文件的script标签里面, 发生着这样的故事: 让咱们逐句解析
第一步:建立场景, 也就是虚拟的空间
咱们以后绘制的3d物体
都要放入这个空间里面, 你能够把它当作一个鸿蒙空间神器, 里面有一个小世界, 而咱们是掌控者(很中二)。
const scene = new THREE.Scene();
第二步:建立相机
相机的概念上面讲述过了, PerspectiveCamera
这个类就是透视投影相机
, 咱们来逐个攻破他参数的意思。
-
35
:视角
也就是咱们左眼与右眼能够看到的横向角度, 其越小物体则越大, 由于目光变狭窄会突出物体, 你能够作一个实验, 聚精会神的盯着看一个物体, 你就会发现此时你左右两边原本靠余光能够看到的物体你如今看不清, 这个就是你的视角变小了, 变小视角还可使目标物体比例变大, 咱们知道这些就够理解这个数字了, 后期能够利用这个原理作一些使人惊讶的动画特效。 -
window.innerWidth / window.innerHeight
: 纵横比宽/高
, 这里宽高不会去写px
这种单位, 坐标系里面是一种抽象的长度单位, 因此要告诉浏览器我们当前显示图像的区域的宽高比例(能够当它是百分比布局, 就像咱们写css布局时使用vh
vw
为单位)。 -
1
:近平面
, 简单理解就是当一个图像
距离相机
的距离小于1的时候, 就不显示这个图像了。 -
1000
:远平面
, 简单理解就是当一个图像
距离相机
的距离大于1000的时候, 就不显示这个图像了。 -
camera.position.z = 10;
相机的坐标不设置的话, 默认就是(0, 0, 0)坐标原点, 这样相似脑壳在坐标轴原点上看坐标轴, 因此这里要设置距离坐标中心有必定距离, 也就是远距离观察这个坐标系。
const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 10;
-
无聊的知识: 咱们在玩 3d游戏
的时候, 是否是有时候与另外一个游戏人物距离太近了就会出现人物中空
的效果, 这些极可能就是他的某些部分距离你相机的距离, 小于了近平面
的距离致使的。 -
物体距离眼睛越近越大, 越远越小, 由于一个物品无限大与无限远没有意义, 显示起来浪费性能, 因此才会设置近平面与远平面。 -
第三步:生成渲染实例
-
WebGLRenderer
生成一个渲染实例, 用来渲染咱们全部的3d效果。 -
setSize
设置场景的宽高。 -
setClearColor
设置背景色, 这个背景色不是平面的, 是全方位的, 你能够想一想成你在一个屋子里, 这个颜色就是屋子墙壁、地板、天花板的颜色(.5是透明度)。 -
renderer.domElement
生成的渲染的实例, 这个要放到对应的dom容器里面(是个canvas标签)。
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x00FFFF, .5)
document.body.appendChild(renderer.domElement);
-
知识点: setClearColor
不写就是黑色 -
知识点: setClearColor
能够直接写"red"这种, 不用必须16进制。
第四步:插入坐标系实例
-
AxisHelper
: 用于生成辅助坐标实例,2
表明这个坐标系的长度, 由于咱们不必定须要多长的辅助线。 -
scene
: 老朋友场景
, 它的add
方法就是把某某某加入到场景中来。
const axisHelper = new THREE.AxisHelper(2)
scene.add(axisHelper)
第五步:渲染出来
-
第一个参数是 场景
, 第二个参数是相机
。
renderer.render(scene, camera);
下面是效果图, z轴正对着咱们因此看不到:
在斜上方看到是以下的效果, 以后的章节会说如何调整相机的位置与角度
完整的代码以下
<html>
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>
<script>
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 10;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x00FFFF, .5)
document.body.appendChild(renderer.domElement);
const axisHelper = new THREE.AxisHelper(2)
scene.add(axisHelper)
renderer.render(scene, camera);
</script>
</body>
</html>
七. 第一个立方体
不画一个立方体感受对不起 第一篇
这个题目, 要注意了在three.js
中你能够理解为绘制一个几何体须要两部分, 一个是几何体
自己, 好比这个几何体的长宽高, 另外一个就是材质
能够简单理解为表面的颜色样式。 geometry
这个单词咱们会常常打交道的, 来一块儿记下它吧。

BoxGeometry
长方体
const geometry = new THREE.BoxGeometry(1, 2, 3);
-
1:
'长', 也能够理解为在不设置坐标的时候在x轴上的长度。 -
2:
'高', 也能够理解为在不设置坐标的时候在y轴上的长度。 -
3:
'宽', 也能够理解为在不设置坐标的时候在z轴上的长度。
new出来的实例上面会有这个几何体的点的信息, 面的信息等等, 这个后面再详细说此次主要入门。
MeshBasicMaterial
材质
颜色与上面设置setClearColor
同样, 什么写法都行的, 下面是我设置了一个红色的材质。const material = new THREE.MeshBasicMaterial({ color: 'red' });
生成'网格' Mesh
const cube = new THREE.Mesh(geometry, material);
网格上含有位置信息、旋转信息、缩放信息等等, 他须要用几何体
与材质
两个参数, 但其实并不像网上说的必需要有材质, 不传材质也能显示。
放入场景
也就是场景对象scene
自己有个add
方法。scene.add(cube);
右上方视角
放入场景的几种方式
1: 我直接放入geometry
scene.add(geometry);
会报错了, 能够理解为不是网格对象因此报错了。之后遇到这类报错必定要考虑类型问题。
2: 未设置材质
const cube = new THREE.Mesh(geometry);
scene.add(cube);
白白的一片, 而且控制台没有报错。
八. 所有代码
<html>
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>
<script src="./utils/OrbitControls.js"></script>
<script>
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 10;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x00FFFF, .5)
document.body.appendChild(renderer.domElement);
const axisHelper = new THREE.AxisHelper(2)
scene.add(axisHelper)
const geometry = new THREE.BoxGeometry(1, 2, 3);
const material = new THREE.MeshBasicMaterial({ color: 'red' });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
renderer.render(scene, camera);
</script>
</body>
</html>
end
第一篇写的内容并很少, 等基本知识储备够了就能够开始编写3d地球
了, 那里将会颇有意思。但愿与你一块儿进步。
最后

本文分享自微信公众号 - 前端瓶子君(pinzi_com)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。