1 Star 0 Fork 0

lafen / threejs-html-demo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

Threejs

基本概念

  • 场景 Scene
  • 相机 Camera
  • 渲染器 Renderer

物体形状: 几何体 Geometry

  • 长方体 BoxGeometry
  • 圆柱体 CylinderGeometry
  • 球体 SphereGeometry
  • 圆锥 ConeGeometry
  • 矩形平面 PlaneGeometry
  • 圆平面 CircleGeometry

物体外观: 材质 Material

  • 网格基础材质 MeshBasicMaterial
  • 网格漫反射材质 MeshLambertMaterial
  • 网格高光材质 MeshPhongMaterial
  • 物理材质 MeshStandardMaterial | MeshPhysicalMaterial
  • 点材质 PointsMaterial
  • 线基础材质 LineBasicMaterial
  • 精灵材质 SpriteMaterial

物体: 网格模型 Mesh

// 传入几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material)

模型位置: .position

// 设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0, 0, 0)

添加网格模型到场景 scene.add

scene.add(mesh)

相机

  • OrthographicCamera 正投影相机
  • PerspectiveCamera 透视投影相机

PerspectiveCamera 透视投影相机

本质上是模拟人眼观察这个世界的规律,透视投影相机的四个参数 fov, aspect, near, far 构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。

宽高比 aspect = width / height

参数 含义 默认值
fov 相机视椎体竖直方向视野角度 50
aspect 相机视椎体水平方向和竖直方向长度比,一般设置为 Canvas 画布宽高比 width/height 1
near 相机视椎体近裁界面相对相机距离 0.1
far 相机视椎体远裁面相对相机距离,far-near构成了视椎体高度方向 2000
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera()

相机位置 .position

camera.position.set(200, 200, 200)

相机观察目标 .lookAt()

camera.lookAt(0, 0, 0)
camera.lookAt(mesh.position)

WebGL 渲染器 WebGLRenderer

创建渲染器对象

// 创建渲染器对象
const renderer = new THREE.WebGLRenderer()

设置 Canvas 画布尺寸 .setSize()

// 定义threejs输出画布的尺寸(单位:像素px)
const width = 800; //宽度
const height = 500; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)

渲染器 Canvas 画布属性 .domElement

渲染器 WebGLRenderer 通过属性 .domElement 可以获得渲染方法 .render() 生成的 Canvas 画布,.domElement 本质上就是一个 HTML 元素: Canvas 画布。

document.body.appendChild(renderer.domElement);

渲染器方法 .render()

渲染器 WebGLRenderer 执行渲染方法 .render() 就可以生成一个 Canvas画布(照片),并把三维场景 Scene 呈现在 canvas 画布上面,你可以把 .render() 理解为相机的拍照动作“咔”。

renderer.render(scene, camera); //执行渲染操作

让物体动起来

// 使用 requestAnimationFrame 渲染
const render = () => {
  requestAnimationFrame(render);
  mesh.rotation.x += 0.01;
  mesh.rotation.y += 0.01;
  renderer.render(scene, camera);
}
render();

三维坐标系

辅助观察坐标系

THREE.AxesHelper() 的参数表示坐标系坐标轴线段尺寸大小,你可以根据需要改变尺寸。

const axesHelper = new THREE.AxesHelper(150)
scene.add(axesHelper)

three.js 坐标轴颜色红R、绿G、蓝B分别对应坐标系的x、y、z轴,对于 three.js 的3D坐标系默认y轴朝上。

光源

基础材质不受光照影响,漫反射材质、高光材质、物理材质 受光照影响

  • 环境光 AmbientLight
  • 点光源 PointLight
  • 聚光灯光源 SpotLight
  • 平行光 DirectionalLight

生成光源

//点光源:两个参数分别表示光源颜色和光照强度
// 参数1:0xffffff是纯白光,表示光源颜色
// 参数2:1.0,表示光照强度,可以根据需要调整
const pointLight = new THREE.PointLight(0xffffff, 1.0);

光源位置

//点光源位置
pointLight.position.set(50, 0, 0); //点光源放在x轴上

添加光源到场景中

scene.add(directionalLight); //点光源添加到场景中

点光源辅助观察 PointLightHelper

通过点光源辅助观察对象 PointLightHelper 可视化光源

// 光源辅助观察
const pointLightHelper = new THREE.PointLightHelper(pointLight, 10)
scene.add(pointLightHelper)

相机控件 OrbitControls

开发时可以通过相机控件 OrbitControls 实现旋转缩放预览效果。需要另外引入轨道控制器扩展库OrbitControls.js。

  • 旋转: 拖动鼠标左键
  • 缩放: 滚动鼠标中键
  • 平移: 拖动鼠标右键
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
    // renderer.render(scene, camera); //执行渲染操作, 在render 里渲染了这里就不用重复了
    // 浏览器控制台查看相机位置变化
    console.log('camera.position',camera.position);
});//监听鼠标、键盘事件

OrbitControls 本质上就是改变相机的参数,比如相机的位置属性,改变相机位置也可以改变相机拍照场景中模型的角度,实现模型的360度旋转预览效果,改变透视投影相机距离模型的距离,就可以改变相机能看到的视野范围

全屏渲染

使用 window.innerWidth 、window.innerHeight 设置画布宽高。记得设置 css

body {
  overflow: hidden;
  margin: 0px;
}

画布大小变化

canvas 画布宽高动态变化,需要更新相机和渲染参数,否则无法正常渲染

// 窗口大小变化
window.resize = function() {
  // 重置渲染器尺寸
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 全屏下,设置观察范围长宽比 aspect 为窗口宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 渲染器执行 renderer 方法的时候会读取相机对象的投影矩阵属性 projectionMatrix
  // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵,节约计算资源
  // 如果相机的一些属性发生了变化,需要执行 updateProjectionMatrix() 方法更新相机的投影矩阵
  camera.updateProjectionMatrix();
}

stats.js 查看 threejs 渲染帧率

threejs 每执行 WebGL 渲染器的 .render() 方法一次,就在画布上得到一帧图像,所以场景越复杂则渲染性能越低,也就每秒钟执行 .render() 的次数越低。

通过 stats.js 库可以查看 threejs 当前的渲染性能,即渲染帧率(FPS),一般渲染达到每秒 60 次为最佳状态。

// 引入 stats.js
import Stats from 'three/addons/libs/stats.module.js';

// 创建 stats 对象
const stats = new Stats()
document.body.appendChild(stats.domElement)

// 渲染函数
// 使用 requestAnimationFrame 渲染
const render = () => {
  // 调用 stats.update
  stats.update();

  mesh.rotation.x += 0.01;
  mesh.rotation.y += 0.01;

  // light.rotation.x += 0.1;
  // light.rotation.y += 0.1;

  // 渲染
  renderer.render(scene, camera);
  window.requestAnimationFrame(render);
}
render();

stats.setMode(mode)

// stats.domElement显示:渲染帧率  刷新频率 和 一秒渲染次数 
stats.setMode(0);//默认模式
//stats.domElement显示:渲染周期 渲染一帧多长时间(单位:毫秒ms)
stats.setMode(1);

性能测试

控制长方体模型数量,增加或减少看看帧率变化,这也与电脑性能有关

const getRandomColor = () => {
  let hex = Math.floor(Math.random() * 16777216).toString(16);
  while(hex.length < 6) {
    hex = '0' + hex;
  }
  return '#' + hex;
}
// 随机创建大量的模型,测试渲染性能,调整 num 值查看页面帧率变化
const num = 10; //控制长方体模型数量
for (let i = 0; i < num; i++) {
  for (let j = 0; j < num; j++) {
    for (let k = 0; k < num; k++) {
      const geometry = new THREE.BoxGeometry(1, 1, 1);
      const material = new THREE.MeshLambertMaterial({
        color: getRandomColor(),
        transparent: true,
        opacity: 0.8,
      });
      const mesh = new THREE.Mesh(geometry, material);
      // 随机生成长方体xyz坐标
      const x = i * 2
      const y = k * 2
      const z = j * 2
      mesh.position.set(x, y, z)
      scene.add(mesh); // 模型对象插入场景中
    }
  }
}

几何体双面可见

threejs 的材质默认正面可见,反面不可见,对于矩形平面 PlaneGeometry、圆形平面 如果想看到两面,可以设置 side: THREE.DoubleSide

//默认只有正面可见
new THREE.MeshBasicMaterial({
  side: THREE.FrontSide,
});
// 设置 两面可见
new THREE.MeshBasicMaterial({
  side: THREE.DoubleSide,
});

高光材质

// 球体 几何体
const sphereGeometry = new THREE.SphereGeometry(2);
// 高光网格材质
// 模拟镜面反射,产生一个高光效果
const phongMaterial = new THREE.MeshPhongMaterial({
  color: 0xF80888,
  shininess: 40, //高光部分的亮度,默认30
  specular: 0xFFFFFF, //高光部分的颜色
});
// 网格模型
const mesh2 = new THREE.Mesh(sphereGeometry, phongMaterial);
// 网格模型位置,默认原点
mesh2.position.set(10, 20, 10);
scene.add(mesh2);

WebGL 渲染器设置

渲染器锯齿属性 .antialias

// 开启锯齿模糊,几何体过渡更加平滑自然
const renderer = new THREE.WebGLRenderer({
  antialias: true,
});
// 或者
renderer.antialias = true;

设备像素比 .setPixelRatio()

如果你遇到你的 canvas 画布输出模糊问题,注意设置 renderer.setPixelRatio(window.devicePixelRatio)

注意:注意你的硬件设备设备像素比window.devicePixelRatio刚好是1,那么是否执行.setPixelRatio()不会有明显差异,不过为了适应不同的硬件设备屏幕,通常需要执行该方法。

// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setPixelRatio(window.devicePixelRatio);

设置背景颜色 .setClearColor()

renderer.setClearColor(0x444444, 1); //设置背景颜色

gui.js 库 - 可视化改变三维场景

dat.gui.js 是一个前端js库,对HTML、CSS和JavaScript进行了封装,借助dat.gui.js可以快速创建控制三维场景的UI交互界面,场景中的参数往往需要以可视化的方式调试出来。

gui 实例主要包含以下方法:

  • .add(控制对象,对象具体属性,其他参数) 其他参数一般是对象具体属性可调试的数值区间
  • .name(属性命名) 设置属性命名
  • .step(步长) 设置步长
  • .addColor(控制对象, 'color') 生成颜色值改变的交互界面
  • .onChange((value) => {}) 属性改变时触发

.add 方法中的参数

  • 参数3和参数4 分别是数字,交互界面是拖动条
  • 参数3 是数组,则交互界面是下拉菜单
  • 参数3 是对象,则交互界面是下拉菜单
  • 如果 .add 改变属性的对应的数据类型如果是布尔值,则交互界面是一个单选框
// 引入dat.gui.js的一个类GUI
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

// 创建一个GUI
const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';
// 通过GUI改变对象属性,其余参数为数值
gui.add(pointLight, 'intensity', 0, 2.0).name('环境光强度');
gui.add(mesh.position, 'y', 0, 30).step(2).name('y轴');
// .add 的其余参数为对象 、 数组,gui界面为下拉选择
gui.add(material, 'transparent', { : true, : false}).name('开启透明');
gui.add(material, 'opacity', [0.2, 0.4, 0.6, 0.8, 1]).name('透明度');
// .add 的其余参数为 布尔值
const isMove = { bool: true };
gui.add(isMove, 'bool').name('矩形动画');
// 球体颜色
gui.addColor(phongMaterial, 'color').name('球体颜色').onChange(function(color) {
  // renderer.setClearColor(color, 1);
});

gui界面分组 .addFolder()

gui 页面分组可 嵌套

// 创建子菜单
const boxFolder = gui.addFolder('矩形');
// 折叠,对应的 .open() , 默认是 open
boxFolder.close();
boxFolder.add(mesh.position, 'y', 0, 30).step(2).name('y轴');
const isMove = { bool: true };
boxFolder.add(isMove, 'bool').name('矩形动画');
// 嵌套子菜单
const transparentFolder = boxFolder.addFolder('透明');
transparentFolder.add(material, 'transparent', { : true, : false}).name('开启透明');
transparentFolder.add(material, 'opacity', [0.2, 0.4, 0.6, 0.8, 1]).name('透明度');

// 创建子菜单
const sphereFolder = gui.addFolder('球体');
// 球体颜色
sphereFolder.addColor(phongMaterial, 'color').name('球体颜色').onChange(function(color) {
  // renderer.setClearColor(color, 1);
});

空文件

简介

threejs demo 展开 收起
JavaScript
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/lafen/threejs-html-demo.git
git@gitee.com:lafen/threejs-html-demo.git
lafen
threejs-html-demo
threejs-html-demo
master

搜索帮助