这一节是纯理论知识, 用于介绍 three.JS 的入门概念, 也就是开发前需要准备的理论基础.
一, 三剑客
当然就是 scene,camera,renderer 这三个基本要素.
scene 是一个用于容纳三维空间的场景, 相当于一个容器;
camera 则是一双帮助我们观察 3d 世界的眼睛;
而 renderer 是一个渲染器, 它负责把无色无相的三维物体绘制成肉眼可见的物体;
二, 选什么相机
选透视相机 (PerspectiveCamera).
简单来说, 透视相机有距离感, 远的物体看起来小一点, 近的物体看起来大一点, 符合现实生活中的人眼观感;
而正交投影相机没有距离感, 所有的物体看起来都是在一条直线上;
(左为透视相机, 右为正交投影相机)
三, 如何生成一个基础物体?
基础物体 mesh = 几何结构 (geometry)+ 贴片材质 (material)
几何结构就像一个骨架, three.JS 内置了不少几何结构, 像常见的球体, 正方体, 圆环等等;
而贴片材质则决定这个骨架的样式, 可以画上纯色, 也可以贴上图片纹理等;
四, 该选什么材质?
材质主要分为与光照没有任何交集的基础材质 (MeshBasicMaterial), 以及必须要光照才能看见, 可以配合光照产生阴影效果的标准材质 (MeshStandardMaterial);
一般来说, 全景图的视角在物体内部, 只观察图片纹理, 不需要阴影效果, 可选用基础材质;
而像 3d 物体, 给物体打上平行光, 显现出物体的影子, 可以让画面更真实, 因此选用标准材质. 但此时环境光要慎用, 因为如果物体是纯色材质, 视觉上环境光会和物体混色. 如: 在标准材质下: 黄色环境光 + 蓝色材质物体 = 视觉上物体呈绿色;
五, 初始化透视相机的参数如何设置?
var camera = newPerspectiveCamera(fov, aspect, near, far) 帮助我们初始化一个相机, 参数依次为: 视野, 可观测距离比, 最近观测距离, 最远观测距离.
如果你和我一样没什么图形学基础, 不太懂透视, 可以使用一个通用的参数设定:
var camera = new THREE.PerspectiveCamera(80, Windows.innerWidth / Windows.innerHeight, 0.1, 1000);
六, 相机该看哪儿?
默认情况下, 相机处于空间直角坐标系的原点;
一般的做法是, 通过相机的 position 属性把它摆放到三维空间的某个位置;
再通过 lookAt 属性设置一下相机该看向哪里, 一般看向物体的正中心 (newTHREE.Vector3(0, 0, 0));
七, 如何实现实时渲染 (循环渲染)?
结合 requestAnimationFrame 获得一个合适的帧率, 然后递归调用渲染器的 render 方法就行了, requestAnimationFrame 本质上就是一个异步延时函数.
代码如下所示:
- function animate() {
- renderer.render(scene, camera);
- requestAnimationFrame(animate);
- }
八, 图片纹理默认贴在几何体外部, 如何让其贴在几何体内壁?
一般做法是将几何体的 scale 属性的某一个坐标设为负值就行了, 如:
geometry.scale(- 1, 1, 1);
九, 自由拖动查看全景图, 该怎么搞?
这里的大体思路是这样的: 根据拖动事件计算出一个新的经纬度, 然后通过某种换算公式将新的经纬度换算为三维空间坐标 (x,y,z), 然后 camera 看向这个三维坐标.
换言之, 就是 camera 被安装在球体内部的球心, 然后探头可以转来转去, 查看球体内壁的不同区域.
关于经纬度转三维坐标, 如果你并不想去过多了解这个转换函数的具体意义, 也可以直接使用, 代码如下:
- function transCoord(sphereRadius,lon,lat) { // 参数分别表示球体的半径, 经度, 纬度
- lat = Math.max(-85, Math.min(85, lat));
- let phi = THREE.Math.degToRad(90 - lat);
- let theta = THREE.Math.degToRad(lon);
- camera.target.x = sphereRadius * Math.sin(phi) * Math.cos(theta);
- camera.target.y = sphereRadius * Math.cos(phi);
- camera.target.z = sphereRadius * Math.sin(phi) * Math.sin(theta);
- camera.lookAt(camera.target);
- }
十, 自由拖动查看 3d 物体, 该怎么弄?
与全景图相对应, 3d 物体拖动查看也是很常见的东西;
它的大体思路可能是这样的:
(1) 先把相机安装在物体外部的某一个点, 然后相机探头固定看着物体中心, 当我们拖动物体时, 实际上就是在令物体围着自身的中心点做各种旋转, 相机在外部一动不动,"静静地看着物体装逼";
(2) 然后相机探头固定看着物体中心, 当我们进行拖动时, 3d 物体不懂, 相机在物体外围的空间 "飞来飞去";
如果你不想考虑这么多坐标换算的东西, 不想搞这么多数学, 也可以当个 API 的调用者, three.JS 官方提供了 OrbitControls, 用来定于用户对物体的旋转查看行为, 其使用十分简单.
十一, 鼠标缩放如何比较科学地解决?
鼠标缩放画面, 其实就是在缩放透视相机的视野 (fov);
视野越大, 则表示看到的范围越大, 离物体也就越远;
视野越小, 则表示看到的范围很小, 说明离物体很近, 有 "一叶障目" 之感;
明白了这一点, 我们就可以通过调用内置 API 来实现这个缩放的功能, 内置的 API 封装了很多细节, 也简化了我们的运算, 代码如下:
- function mouseWheelHandler(event) {
- let fov = camera.fov + event.deltaY * 0.05;
- camera.fov = THREE.Math.clamp(fov, 10, 75); // 后两个参数表示最小视野, 最大视野, 也就是缩放范围
- camera.updateProjectionMatrix();
- }
以上就是 three.JS 一些比较入门的理论知识, 下一节我们将从一个实际页面出发, 动手完成一个可交互的简单 3d 物体.
来源: https://www.cnblogs.com/zhangnan35/p/10917109.html