前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

实现一个360度全景插件|博客系列

# 导读

本文从绘图基础开始讲起,详细介绍了如何使用Three.js开发一个功能齐全的全景插件。

我们先来看一下插件的效果:

如果你对Three.js已经很熟悉了,或者你想跳过基础理论,那么你可以直接从 全景预览开始看起。

本项目的github地址: https://github.com/ConardLi/tpanorama

# 一、理清关系

# 1.1 OpenGL

OpenGL是用于渲染2D、3D量图形的跨语言、跨平台的应用程序编程接口(API)。

这个接口由近350个不同的函数调用组成,用来从简单的图形比特绘制复杂的三维景象。

OpenGL ES 是OpenGL三维图形API的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。

基于OpenGL,一般使用C或Cpp开发,对前端开发者来说不是很友好。

# 1.2 WebGL

WebGL把JavaScript和OpenGL ES 2.0结合在一起,从而为前端开发者提供了使用JavaScript编写3D效果的能力。

WebGL为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。

# 1.3 Canvas

Canvas是一个可以自由制定大小的矩形区域,可以通过JavaScript可以对矩形区域进行操作,可以自由的绘制图形,文字等。

一般使用Canvas都是使用它的2d的context功能,进行2d绘图,这是其本身的能力。

和这个相对的,WebGL是三维,可以描画3D图形,WebGL,想要在浏览器上进行呈现,它必须需要一个载体,这个载体就是Canvas,区别于之前的2dcontext,还可以从Canvas中获取webglcontext。

# 1.4 Three.js

我们先来从字面意思理解下:Three代表3D,js代表JavaScript,即使用JavaScript来开发3D效果。

Three.js是使用JavaScript 对 WebGL接口进行封装与简化而形成的一个易用的3D库。

直接使用WebGL进行开发对于开发者来说成本相对来说是比较高的,它需要你掌握较多的计算机图形学知识。

Three.js在一定程度上简化了一些规范和难以理解的概念,对很多API进行了简化,这大大降低了学习和开发三维效果成本。

下面我们来具体看一下使用Three.js必须要知道的知识。

# 二、Three.js基础知识

使用Three.js绘制一个三维效果,至少需要以下几个步骤:

  • 创建一个容纳三维空间的场景 — Sence

  • 将需要绘制的元素加入到场景中,对元素的形状、材料、阴影等进行设置

  • 给定一个观察场景的位置,以及观察角度,我们用相机对象(Camera)来控制

  • 将绘制好的元素使用渲染器(Renderer)进行渲染,最终呈现在浏览器上

拿电影来类比的话,场景对应于整个布景空间,相机是拍摄镜头,渲染器用来把拍摄好的场景转换成胶卷。

# 2.1 场景

场景允许你设置哪些对象被three.js渲染以及渲染在哪里。

我们在场景中放置对象、灯光和相机。

很简单,直接创建一个Scene的实例即可。

 _scene = new Scene();
@前端进阶之旅: 代码已经复制到剪贴板

# 2.2 元素

有了场景,我们接下来就需要场景里应该展示哪些东西。

一个复杂的三维场景往往就是由非常多的元素搭建起来的,这些元素可能是一些自定义的几何体(Geometry),或者外部导入的复杂模型。

Three.js 为我们提供了非常多的Geometry,例如SphereGeometry(球体)、 TetrahedronGeometry(四面体)、TorusGeometry(圆环体)等等。

在Three.js中,材质(Material)决定了几何图形具体是以什么形式展现的。它包括了一个几何体如何形状以外的其他属性,例如色彩、纹理、透明度等等,Material和Geometry是相辅相成的,必须结合使用。

下面的代码我们创建了一个长方体体,赋予它基础网孔材料(MeshBasicMaterial)

    var geometry = new THREE.BoxGeometry(200, 100, 100);
    var material = new THREE.MeshBasicMaterial({ color: 0x645d50 });
    var mesh = new THREE.Mesh(geometry, material);
            _scene.add(mesh);
@前端进阶之旅: 代码已经复制到剪贴板

能以这个角度看到几何体实际上是相机的功劳,这个我们 下面的章节再介绍,这让我们看到一个几何体的轮廓,但是感觉怪怪的,这并不像一个几何体,实际上我们还需要为它添加光照和阴影,这会让几何体看起来更真实。

基础网孔材料(MeshBasicMaterial)不受光照影响的,它不会产生阴影,下面我们为几何体换一种受光照影响的材料:网格标准材质(Standard Material),并为它添加一些光照:

    var geometry = new THREE.BoxGeometry(200, 100, 100);
    var material = new THREE.MeshStandardMaterial({ color: 0x645d50 });
    var mesh = new THREE.Mesh(geometry, material);
    _scene.add(mesh);
    // 创建平行光-照亮几何体
    var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
     directionalLight.position.set(-4, 8, 12);
    _scene.add(directionalLight);
    // 创建环境光
    var ambientLight = new THREE.AmbientLight(0xffffff);
    _scene.add(ambientLight);
@前端进阶之旅: 代码已经复制到剪贴板

有了光线的渲染,让几何体看起来更具有3D效果,Three.js中光源有很多种,我们上面使用了环境光(AmbientLight)和平行光(DirectionalLight)。

环境光会对场景中的所有物品进行颜色渲染。

平行光你可以认为像太阳光一样,从极远处射向场景中的光。它具有方向性,也可以启动物体对光的反射效果。

除了这两种光,Three.js还提供了其他几种光源,它们适用于不同情况下对不同材质的渲染,可以根据实际情况选择。

# 2.3 坐标系

在说相机之前,我们还是先来了解一下坐标系的概念:

在三维世界中,坐标定义了一个元素所处于三维空间的位置,坐标系的原点即坐标的基准点。

最常用的,我们使用距离原点的三个长度(距离x轴、距离y轴、距离z轴)来定义一个位置,这就是直角坐标系。

在判定坐标系时,我们通常使用大拇指、食指和中指,并互为90度。大拇指代表X轴,食指代表Y轴,中指代表Z轴。

这就产生了两种坐标系:左手坐标系和右手坐标系。

Three.js中使用的坐标系即右手坐标系。

我们可以在我们的场景中添加一个坐标系,这样我们可以清楚的看到元素处于什么位置:

 var axisHelper = new THREE.AxisHelper(600);
 _scene.add(axisHelper);
@前端进阶之旅: 代码已经复制到剪贴板

其中红色代表X轴,绿色代表Y轴,蓝色代表Z轴。

# 2.4 相机

上面看到的几何体的效果,如果不创建一个相机(Camera),是什么也看不到的,因为默认的观察点在坐标轴原点,它处于几何体的内部。

相机(Camera)指定了我们在什么位置观察这个三维场景,以及以什么样的角度进行观察。

# 2.4.1 两种相机的区别

目前Three.js提供了几种不同的相机,最常用的,也是下面插件中使用的两种相机是:PerspectiveCamera(透视相机)、 OrthographicCamera(正交投影相机)。

上面的图很清楚的解释了两种相机的区别:

右侧是 OrthographicCamera(正交投影相机)他不具有透视效果,即物体的大小不受远近距离的影响,对应的是投影中的正交投影。我们数学课本上所画的几何体大多数都采用这种投影。

左侧是PerspectiveCamera(透视相机),这符合我们正常人的视野,近大远小,对应的是投影中的透视投影。

如果你想让场景看起来更真实,更具有立体感,那么采用透视相机最合适,如果场景中有一些元素你不想让他随着远近放大缩小,那么采用正交投影相机最合适。

# 2.4.2 构造参数

我们再分别来看看两个创建两个相机需要什么参数:

_camera = new OrthographicCamera(left, right, top, bottom, near, far);
@前端进阶之旅: 代码已经复制到剪贴板

OrthographicCamera接收六个参数,left, right, top, bottom分别对应上、下、左、右、远、近的一个距离,超过这些距离的元素将不会出现在视野范围内,也不会被浏览器绘制。实际上,这六个距离就构成了一个立方体,所以OrthographicCamera的可视范围永远在这个立方体内。

_camera = new PerspectiveCamera(fov, aspect, near, far);
@前端进阶之旅: 代码已经复制到剪贴板

PerspectiveCamera接收四个参数,near、far和上面的相同,分别对应相机可观测的最远和最近距离;fov代表水平范围可观测的角度,fov越大,水平范围能观测到的范围越广;aspect代表水平方向和竖直方向可观测距离的比值,所以fov和aspect就可以确定垂直范围内能观测到的范围。

# 2.4.3 position、lookAt

关于相机还有两个必须要知道的点,一个是position属性,一个是lookAt函数:

position属性指定了相机所处的位置。

lookAt函数指定相机观察的方向。

实际上position的值和lookAt接收的参数都是一个类型为Vector3的对象,这个对象用来表示三维空间中的坐标,它有三个属性:x、y、z分别代表距离x轴、距离y轴、距离z轴的距离。

下面,我们让相机观察的方向指向原点,另外分别让x、y、z为0,另外两个参数不为0,看一下视野会发生什么变化:

_camera = new OrthographicCamera(-window.innerWidth / 2, window.innerWidth / 2, window.innerHeight / 2, -window.innerHeight / 2, 0.1, 1000);
 _camera.lookAt(new THREE.Vector3(0, 0, 0))

 _camera.position.set(0, 300, 600); // 1 - x为0

 _camera.position.set(500, 0, 600); // 2 - y为0

 _camera.position.set(500, 300, 0); // 3 - z为0
@前端进阶之旅: 代码已经复制到剪贴板

很清楚的看到position决定了我们视野的出发点,但是镜头指向的方向是不变的。

下面我们将position固定,改变相机观察的方向:

← 学会使用Graphviz绘制流程图持续集成 Travis CI →

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合