Three.js - 初试threeJS

不支持WebGL技术时创建3D场景需要依赖OpenGL的技术,比如unity3D或ue4开发一个桌面应用,但存在难以传播的问题,需要客户进行下载指定软件进行支持。

WebGL是一种javascript API或可编程接口,用于在网页中绘制交互式2D和3D图形

大致步骤:初始设置 → 创建场景 → 创建相机 → 创建可见对象 → 创建渲染器 → 创建场景

基本知识

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

3D引擎基本概念

场景 - scene => 小宇宙

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

是一个三维空间,是所有物品的容器,包含物体、相机和光源等,容纳着除渲染器以外的三维世界里的一切,如果没有场景对象,那么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个参数规定了相机示景体的左、右、上、下、前、后六个面的位置;

透视投影相机(PerspectiveCamera)

透视相机是现实世界中相机的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)
投影大小

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

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

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

js 复制代码
// 新建一个渲染器 
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)
    • 将平面添加到场景中前,还需要设置平面的位置,然后再将平面添加进场景中

      ts 复制代码
      // 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

网格是3D计算机图形学中最常见的可见对象,用于显示各种3D对象

js 复制代码
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. 等等等材质
js 复制代码
// 开始设置立方体,设置长宽高,立方体的框架
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(平行光,参考日光来理解)
    • 亮度与光源和物体之间的距离无关,只与平行光的角度和物体所在平面有关
  3. PointLight(点光源,参考灯泡来理解)
    • 一个点发出的光源,照到不同物体表面的亮度线性递减
  4. RectAreaLight(平面光光源,参考条形照明或明亮的窗户)

平面光光源从一个矩形平面上均匀地发射光线。这种光源可以用来模拟像明亮的窗户或者条状灯光光源。其不支持阴影,只支持MeshStandardMaterialMeshPhysicalMaterial 两种材质。你必须在你的场景中加入 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

优缺点分析

优点

  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零基础入门教程(郭隆邦)

相关推荐
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte6 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc