1.介绍

Three.js是基于原生WebGL封装运行的三维引擎,在所有WebGL引擎中,Three.js是国内文资料最多、使用最广泛的三维引擎。

2.应用场景

  • 智慧城市
  • 智慧园区
  • 大屏数据可视化
  • 3D看房
  • 小游戏

 

3.使用 

3.1下载Three.js

// 通过CDN方式引入
<script src="https://cdn.bootcss.com/three.js/92/three.js"></script>

// 使用npm下载
npm install --save three
// 在要使用的页面中引入three.js
import * as THREE from 'three'

3.2程序结构

3.3开始使用

<template>
  <div id="my-three" ref="screenDom"></div>
</template>

<script setup>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { onMounted, ref, onBeforeUnmount } from "vue";
//导入dat.gui
import * as dat from "dat.gui";

let screenDom = ref(null);

onMounted(() => {
  // 1.创建场景
  const scene = new THREE.Scene();

  // 2.创建透视投影相机
  const camera = new THREE.PerspectiveCamera(
    50,
    screenDom.value.clientWidth / screenDom.value.clientHeight,
    0.1,
    1000
  );
  // 设置相机位置
  camera.position.set(5, 10, 10);

  // 3.创建WebGLRenderer渲染器
  const renderer = new THREE.WebGLRenderer();
  // 通过setSize()方法设置渲染的长宽
  renderer.setSize(screenDom.value.clientWidth, screenDom.value.clientHeight);
  // 设置渲染位置
  screenDom.value.appendChild(renderer.domElement);

  // 4.创建一个长、宽、高均为5个单位的立方体
  const geometry = new THREE.BoxGeometry(5, 5, 5);

  // 5.创建Lambert网格材质
  const materialBasic = new THREE.MeshLambertMaterial({
    color: 0x00ff00, // 绿色
    wireframe: true, //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
  });

  // 6.创建一个网格模型对象
  const mesh = new THREE.Mesh(geometry, materialBasic); //网络模型对象Mesh
  // 把网格模型添加到三维场景
  scene.add(mesh);
  // 设置相机看向物体的方向(默认指向三维坐标系的原点)
  camera.lookAt(0, 0, 0);
  // 修改几何体位置
  mesh.position.set(3, 0, 0);

  // 7.创建光源
  const spotLight1 = new THREE.SpotLight(0xffffff, 1); //(光照颜色, 光照强度)
  // 设置光源位置
  spotLight1.position.set(10, 10, 10);
  const spotLight2 = new THREE.SpotLight(0xffffff, 1); //(光照颜色, 光照强度)
  // 设置光源位置
  spotLight2.position.set(-10, -10, -10);
  // 将光源添加到场景中
  scene.add(spotLight1, spotLight2);

  // 8.为了方便观察3D图像,添加三维坐标系对象
  const axes = new THREE.AxesHelper(8); // 坐标系轴长设置为8
  // 把三维坐标系 添加到场景中
  scene.add(axes);

  // 9.添加控制器
  let control = new OrbitControls(camera, renderer.domElement);

  // 11.开启gui控制面板
  // let gui = new dat.GUI()
  // gui
  //     .add(mesh.position, 'x')
  //     .min(0)
  //     .max(5)
  //     .step(0.1)
  //     .name("移动x轴")
  //     .onChange((value) => {
  //         console.log("值被修改了:", value);
  //     })
  //     .onFinishChange((value) => {
  //         console.log("完全停下来:", value);
  //     })

  // 结合场景和相机进行渲染,就是相机拍下此刻的场景(最后一步)
  // renderer.render(scene, camera);

  // 10.动态渲染
  function render() {
    //循环调用
    requestAnimationFrame(render);
    //渲染
    renderer.render(scene, camera);
  }
  render();
});
</script>

<style lang="scss" scoped>
#my-three {
  width: 100%;
  height: 100%;
}
</style>

4.步骤讲解

4.1. 核心三要素(场景,相机,渲染器)

  • 场景(scene)

    场景是一个三维空间,是存放所有物品的容器,可以把场景想象成一个空房间,房间里面可以放置要呈现的物体、相机、光源等。

// 创建场景
const scene = new THREE.Scene()
  • 相机(camera)

    相机用来确定观察位置、方向、角度,相机看到的内容,就是我们最终在屏幕上看到的内容。在程序运行过程中,可以调整相机的位置、方向、角度。

        1.透视投影相机(perspectiveCamera)近大远小

// 创建透视投影相机
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// 设置相机位置
camera.position.set(5, 10, 10);
参数介绍
fov视野:表示摄像机能看到的视野。推荐默认值50
aspect指定渲染结果水平方向和竖直方向长度的比值,推荐默认值为窗口的宽高比,即window.innerWidth/window.innerHeight,如果比例设置的不对,会发现渲染出来的画面有拉伸或者压缩的感觉。
near近端渲染距离:指定从距离摄像机多近的位置开始渲染,推荐默认值0.1
far远端距离:指定摄像机从它所在的位置最远能看到多远,太小场景中的远处不会被渲染,太大会浪费资源影响性能,推荐默认值1000。

2.正交投影相机(OrthographicCamera ) 远近一样大

// 创建正交投影相机
const camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
// 设置相机位置
camera.position.set(5, 10, 10);
参数介绍
left可被渲染空间的左端面
right可被渲染空间的右端面
top可被渲染空间的上端面
bottom可被渲染空间的下端面
near基于相机所在位置,可被渲染空间的近端面
far基于相机所在位置,可被渲染空间的远端面
  • 渲染器(renderer)

渲染器的作用就是将相机拍摄出的画面在浏览器中呈现出来。渲染器决定了渲染的结果应该画在页面的什么元素上面,并且以怎样的方式来绘制。

// Three.js中有很多种类的渲染器,例如webGLRenderer、canvasRenderer、SVGRenderer,通常使用的是WebGLRenderer渲染器。
// 创建WebGLRenderer渲染器
const renderer = new THERR.WebGLRenderer();
// 通过setSize()方法设置渲染的长宽
renderer.setSize(window.innerWidth, window.innerHeight); 
// 设置渲染位置
document.body.appendChild(renderer.domElement);
// 结合场景和相机进行渲染,就是相机拍下此刻的场景(最后一步)
renderer.render(scene, camera);

4.2. 基本两要素(物体,光源)

1.物体(拍摄对象)

在计算机世界里,3D世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角形面,在 Three.js中 将任何物体(拍摄对象)结构为一个个小三角形。无论是二维图形还是三维图形,都可以用小三角形作为结构最小单位。而结构出来的就是我们拍摄对象的一个网格。

  • 几何模型(Geometry)

        在Three.js中预设了一些二维和三维几何体模型

        二维几何:

        1.PlaneGeometry(平面几何体)

        2.CircleGeometry(圆形几何体)

        3.RingGeometry(圆环几何体)

        三维几何:

        1.BoxGeometry(立方几何体)

        2.SphereGeometry(球几何体)

        3.CylinderGeometry(圆柱几何体)

        4.TorusGeometry(圆环几何体)

// 实例化几何体
// 创建一个长、宽、高均为1个单位的立方体
const geometry = new THREE.BoxGeometry(1, 1, 1); 
  • 材质(Material)

        几何体的皮肤

        1.基础网格材质(MeshBasicMaterial)【常用】(最基础的材质,不受光照的影响)

        2.Lambert网格材质(MeshLambertMaterial)【常用】(模拟木头,石头,不能模拟镜面反光)

// 创建基础网格材质
var materialBasic = new THREE.MeshBasicMaterial({
    color: 0xffffff, // 白色
    wireframe: true // //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
}); 
  • 网格(Mesh)

        当我们拥有了几何体模型和材质之后,我们需要通过一个网格(Mesh)将两者结合起来,创建我们正在的拍摄对象。

// 创建一个网格模型对象
const mesh = new THREE.Mesh(geometry, materialBasic);//网络模型对象Mesh
// 把网格模型添加到三维场景
scene.add(mesh);
// 设置相机看向物体的方向(默认指向三维坐标系的原点)
camera.lookAt(cube.position);

2.光源(Light)

  • 环境光(AmbientLight)

        环境光是一种基本光源,它会均匀的照亮场景中的所有物体,环境光没有特定的来源方向,且不会产生阴影。

  • 聚光灯(SpotLight)

        聚光灯(类似手电筒、舞台聚光灯)是从一个方向上的一个点发出,沿着一个圆锥体,它离光越远,它的尺寸就越大。这种光源会产生阴影。

  • 平行光(DirectionalLight)

        平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光 的效果; 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。这种光源会产生阴影。

// 创建光源
const spotLight = new THREE.SpotLight(0xffffff,5);	//(光照颜色,光照强度)
// 设置光源位置
spotLight.position.set(0, 20, 20);
// 将光源添加到场景中
scene.add(spotLight);

4.3. 添加辅助线

为了我们方便观察物体,可以添加三条辅助线辅助我们观察

// 为了方便观察3D图像,添加三维坐标系对象
const axes = new THREE.AxisHelper(4); // 坐标系轴长设置为 4
// 把三维坐标系 添加到场景中
scene.add(axes);

4.4. 添加控制器

为了能用鼠标控制物体

// 添加控制器
let control = new OrbitControls(camera, renderer.domElement)

4.5. 动画渲染

这个时候发现物体还是不能拖动,这是因为渲染函数只执行了一次,所以我们要写一个动态渲染函数,让它每一帧都调用渲染函数,这样就可以拖动物体了

// 动画渲染
function render() {
    //循环调用动画渲染
	requestAnimationFrame(render);
    //结合场景和相机进行渲染
	renderer.render(scene, camera)
}
render()

Logo

前往低代码交流专区

更多推荐