Three.js – 初试threeJS

不支持WebGL技术时创建3D场景需要依赖OpenGL的技术,比如unity3D或ue4开发一个桌面应用,但存在难以传播的问题,需要客户进行下载指定软件进行支持。
WebGL是一种javascript API或可编程接口,用于在网页中绘制交互式2D和3D图形

Three.js - 初试threeJS
大致步骤:初始设置 → 创建场景 → 创建相机 → 创建可见对象 → 创建渲染器 → 创建场景
Three.js - 初试threeJS

基本知识

  • threeJS基本步骤
    • 定义场景、相机、渲染器
      • 一个场景想要显示任何东西需要以下三种类型的组件
        • 摄像机:决定屏幕上哪些东西需要渲染
        • 光源:决定材质如何显示及用于产生阴影
        • 对象物体:是摄像机透视图里最主要的渲染对象,如方块、球体等
        • 渲染器:基于摄像机和场景提供的信息,调用底层图形API执行真正的场景绘制工作
      • 场景中添加一切事物如坐标轴、平面、物体、光源
      • 相机决定在场景中的物体是否展示出来
      • 渲染器最后负责渲染场景和相机
    • 添加坐标轴(axes)对象到场景中
    • 创建平面、物体等
    • 附加:通过设置材质、灯光、阴影等进行优化渲染
    • 将渲染器追加到指定的DOM节点上
    • 渲染器中渲染场景和相机

3D引擎基本概念

场景 – scene => 小宇宙

场景是在渲染时想使用的所有物体、光源的容器,是一切可以看到的一切的载体,可以间接理解成小宇宙
Three.js - 初试threeJS

是一个三维空间,是所有物品的容器,包含物体、相机和光源等,容纳着除渲染器以外的三维世界里的一切,如果没有场景对象,那么threeJS将无法渲染任何物体,其中场景元素采用右手笛卡尔坐标系;

Three.js - 初试threeJS
const scene = new THREE.Scene();

  • 场景中的雾化 → fog
    • 雾化的效果是:场景中的物体离摄像机越远就变得越模糊
    • 语法一:scene.fog = new THREE.Fog(0xffffff,0.015,100)
      • 后两个参数是用来定义雾化开始和结束的地方,以及加深的深度,使用THREE.Fog创建的对象,雾的浓度是线性增长的
    • 语法二:scene.fog = new THREE>FogExp2(0xffffff,0.01)
      • 该方法设置了雾的颜色和浓度,通过该方法设置的浓度不再是线性增长的,而是随着距离呈指数增长
相机 Camera => 指向小宇宙的望远镜

相机决定了可以在场景中看到什么,相机有正交投影相机和透视投影相机,正交投影则远近都是一样的大小,三维空间中平行的线,投影到二维空间也一定是平行的;透视投影跟人眼看到的世界是一样的,近大远小。大部分相机都采用透视投影相机;

正交投影相机(OrthographicCamera)

由6个参数确定:THREE.OrthographicCamera(left, right, top, bottom, near, far),这6个参数规定了相机示景体的左、右、上、下、前、后六个面的位置;

Three.js - 初试threeJS

透视投影相机(PerspectiveCamera)

Three.js - 初试threeJS

透视相机是现实世界中相机的3D等效物,其旨在匹配我们的眼睛看待世界的方式。
由四个参数确定:THREE.PerspectiveCamera(fov, aspect, near, far),fov是相机在竖直方向的张角,aspect则是宽高比,即width/height,near和far分别是近平面和远平面与相机的距离(能看多近,能看多远)。

  1. 视野角度(FOV):视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开);
  2. 长宽比(aspect ratio): 也就是你用一个物体的宽除以它的高的值,通常设为画布的宽高比;
  3. 近截面(near)和远截面(far):当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中;
  4. 渲染器不会绘制场景中不在平截头体(截头椎体)内的任何物体,即使有一部分不在,该部分也会被切掉;
    const camara=new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)

Three.js - 初试threeJS

投影大小

透视投影相机,相机与示景体近小远大,会导致投影效果在示景体的位置不同时产生近大远小的效果。

渲染器(render) => 将望远镜观察到的内容很快的绘制到canvas中

将相机(camera)在场景(scene)里看到的内容渲染到画布上,Three.js提供了重绘接口,用于实现动画效果,我们调用有两种方式,一种是setInterval,通过固定时间去调用,但是js是单线程的,这种方式不能100%保证相同时间间隔调用,有可能会存在延迟执行的问题;第二种方式是通过requestAnimationFrameAPI,让浏览器自行根据当前CPU情况决定何时重绘,达到最佳帧率;

// 新建一个渲染器 
const renderer=new THREE.WebGLRenderer(); 
// 设置渲染器的大小 
renderer.setSize(window.innerWidth,window.innerHeight)

当需要保持场景的大小不变,但是以较低的分辨率来渲染,就可以在调用setSize时将第三个参数设置为false,此时就会以当前应用程序一半的分辨率来进行渲染;
renderer.setSize(window.innerWidth,window.innerHeight,false)

平面(plane)
  • 平面的创建步骤
    • 定义平面大小:
      • 使用three.PlaneGeometry(宽,高)来定义平面的大小
        • var planeGeometry = new THREE.PlaneGeometry(60, 20)
    • 设置平面的外观(如颜色、透明度等)
      • threeJS中是通过材质对象来设置平面的外观,材质有很多种,如MeshBasicMaterial基本材质
        • var planeMaterial = new THREE.MeshBasicMaterial({color: 0xcccccc});
    • 将上述『 平面大小 』和『 平面外观 』组合进Mesh对象并赋值给平面变量
      • var plane = new THREE.Mesh(planeGeometry, planeMaterial)
    • 将平面添加到场景中前,还需要设置平面的位置,然后再将平面添加进场景中
      // rotate and position the plane
      plane.rotation.x = -0.5 * Math.PI;
      plane.position.x = 15;
      plane.position.y = 0;
      plane.position.z = 0;
      plane.position.set(15,0,0)
      
      // add the plane to the scene
      scene.add(plane);
      
物体

物体由几何形状(Geometry)和材质(Material)组成,同样的几何形状,不同的材质构成了不同的物体;

网格 Mesh

Three.js - 初试threeJS
网格是3D计算机图形学中最常见的可见对象,用于显示各种3D对象

import { Mesh } from 'three';
const mesh = new Mesh(geometry, material);
  • 创建网格前的必要元素
    • geometry: 几何体
    • material:材质
几何体(Geometry) => 定义了网格的形状

3D世界里的所有物体都是点组成面,面组成几何体;
const geometry=new THREE.BoxGeometry(1,1,1)

材质(Material) => 定义了网格表面的外观

材质一般应用在mesh上,用来模拟物体表面,在光线、阴影等因素的影响下最终展现出来的效果;比如常说得到高光材质、漫反射材质等等,其实都是在描述物体表面的光线是如何作用的;Three.js的内置材质有一下几种;
const material=new THREE.MeshBasicMaterial({color:0x00ff00})

  1. 基础材质(MeshBasicMaterial)
    • 材质是一种较为基础材质,且不会受光照的影响,所以物体看上去并没有很多棱角,而偏向扁平化
  2. 高光材质(MeshPhongMaterial)
    • 用来模拟一些高光效果。类似金属,塑料这种有高光斑点的材质
  3. 漫反射材质(MeshLambertMaterial)
    • 漫反射材质一般用来模拟表面较为粗糙,不会直接反射的表面,而是漫反射光线的材质。例如墙壁、衣服等
  4. 标准PBR材质(MeshStandardMaterial)
    • 一种pbr(Physically based rendering)材质,用来模拟物理的材质属性。一般使用金属性metalness和粗糙度roughness来控制最终外观的效果;
  5. 等等等材质

Three.js - 初试threeJS

// 开始设置立方体,设置长宽高,立方体的框架
const geometry=new THREE.BoxGeometry(1,1,1)
// 设置渲染材质,这个变量用来渲染立方体的表面。设置立方体的颜色为绿色。立方体的表面材质
const material=new THREE.MeshBasicMaterial({color:0x00ff00})
// 真正的立方体变量,通过THREE.Mesh来将材质和框架混合到一起
const cube=new THREE.Mesh(geometry,material)
// 将这个立方体添加到场景当中去。但是要记住,如果立方体直接进场景的话,我们的立方体就会和相机进行重叠。这样就不好了。
scene.add(cube)
// 所以我们这里将相机往上面调一点【这里ThreeJS和Unity一样 用的都是左手坐标系】
camara.position.z=5
// 立方体设置结束
灯光

3D引擎在没有手动创建光的情况下会默认有个环境光,不然什么都看不到;
常见的灯光类型有

  1. AmbientLight(环境光,没有方向全局打亮,不会产生明暗)
    • 所有角度看到的亮度都一样,通常为整个场景指定一个基础亮度
    • 通常不会将该类型的光源作为场景中唯一的光源,因为他会将场景中所有的物体都渲染成相同的颜色,不管是什么形状
  2. DirectionLight(平行光,参考日光来理解)
    • 亮度与光源和物体之间的距离无关,只与平行光的角度和物体所在平面有关
      Three.js - 初试threeJS
  3. PointLight(点光源,参考灯泡来理解)
    • 一个点发出的光源,照到不同物体表面的亮度线性递减
      Three.js - 初试threeJS
  4. RectAreaLight(平面光光源,参考条形照明或明亮的窗户)

平面光光源从一个矩形平面上均匀地发射光线。这种光源可以用来模拟像明亮的窗户或者条状灯光光源。其不支持阴影,只支持MeshStandardMaterial 和 MeshPhysicalMaterial 两种材质。你必须在你的场景中加入 RectAreaLightUniformsLib,并调用 init()

  1. SpotLight(聚光灯,参考舞台聚光灯)
    • 投射出的是类似圆锥形的光线
    • 基本材质不会对光源有任何反应,基本材质只会使用指定的颜色来渲染物体
    • 阴影的基本步骤是:开启灯光的阴影效果、指定产生阴影的元素、指定接收阴影的元素、配置阴影的效果等
    • 可以设置其位置(spotLight.position.set())、spotLight.castShadow(启用阴影功能)、spotLight.shadow.mapSize+spotLight.shadow.far+spotLight.shadow.near三个参数控制阴影的精细程度
    • 同时还需要开启renderer渲染器的阴影效果配置shadowMapEnabled为true;
    • 也需要设置接收阴影(receiveShadow)和产生阴影(castShadow)的元素,如设置场景中添加的物体进行阴影产生,平面进行阴影接收
      • 平面接收阴影:plane.receiveShadow = true
      • 物体产生阴影:cube.castSahdow = true
        Three.js - 初试threeJS

优缺点分析

优点

  1. Three.js通过对webGL的相关封装极大的降低了创建三维动画的门槛,通用的三维动画需要具备较高的数学和图形学等相关技术;
  2. Three.js掩盖了3D渲染的细节
    • 将WebGL的原生API的细节进行抽象化,将3D场景拆解为一些Three.js内置的对象种类;

拓展

PBR(基于物理的渲染)

这种渲染技术使用真实世界的物理学来计算表面对光的额反应方式,从而避免在场景中设置材质和照明时进行额外的计算和猜测,在threeJS中的PBR材质如MeshStandardMaterial

  • 即使使用PBR技术,现实世界和threeJS之间的额一个区别就是默认情况下对象不会阻挡光线,光路径上的每个物体都会收到照明,即使中间有一堵墙,墙后的物体也会被照到;

常见API

  • 基于renderer renderer = new THREE.WebGLRenderer()
    • renderer.setClearColorHex() → 将场景背景颜色设置为接近黑色

相关文献
暮志未晚 – three.js案例
WebGL零基础入门教程(郭隆邦)

原文链接:https://juejin.cn/post/7264920116864483385 作者:FE杂志社

(1)
上一篇 2023年8月8日 上午10:06
下一篇 2023年8月9日 上午10:05

相关推荐

发表回复

登录后才能评论