Threejs基础

112 阅读18分钟

1. 本地搭建Threejs官方文档

  1. 去到Three.js官方文档中找到github地址并跳转
  2. 找到当前dev环境下的代码压缩包下载并解压
  3. 代码导入到vscode中并安装依赖
  4. npm run start || yarn start
  5. 鼠标点击生成的本地访问地址(在浏览器里手动敲击地址可能会出现http解析错误问题)

2. Parcel

  1. 首先环境准备 node npm | yarn, 并通过yarn init | npm init 创建一个环境
  2. 下载Parcel依赖 yarn add --dev parcel | npm install --save-dev parcel
  3. 配置package.json
  4. 加入 "source": "src/index.html",
  5. 并创建src目录以及index.html(快捷键: html:5)
  6. 加入 "scripts": { "start": "parcel", "build": "parcel build" },
  7. 此时可以跑起来了(空白页面)
  8. 安装threejs依赖 yarn add three --save | npm install three --save
  9. 在main.js中引入threejs import * as Three from "three";
  10. ok

3. 浅尝

1.基础用法
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; // 导入轨道控制器
console.log(THREE);

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45, // 角度
  window.innerWidth / window.innerHeight, // 长/宽比
  0.1, // 近端
  1000 // 远端
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建几何物体 - BoxGeometry(几何体: 长 宽 高)
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
// 设置物体材质 - MeshBasicMaterial(基础网格材质: )
const cubeMat = new THREE.MeshBasicMaterial({ color: 0xffff00 });
// 根据几何体和物体材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMat);

// 移动物体
// 修改物体的位置(距离x轴原点多远,y,z; 可以不用set方法单独设置)
// 其实物体的移动就是每次render的时候都去修改他的位置就是移动
cube.position.set(1, 1, 1);

// 缩放物体(x轴缩放多少倍, y, z; 可以不用set方法单独设置)
cube.scale.set(1, 1, 2); // 由原来的(1, 1, 1)=>(2, 1, 3)

// 旋转物体(x轴缩放多少倍, y, z; 可以不用set方法单独设置)
// 其实物体的旋转就是每次render的时候修改他的旋转
cube.rotation.set(Math.PI / 4, 0, 0); // Math.Pi : Π, 180°

// 把几何物体添加到场景中
scene.add(cube);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 使用渲染器, 通过相机将场景渲染出来
// renderer.render(scene, camera);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update

// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

//创建一个时钟
const clock = new THREE.Clock();

// 封装渲染函数
function render(time) {
  /**
   * 控制动画方式(一)
   * 利用请求动画帧参数控制物体移动
   * time: 请求动画帧requestAnimationFrame函数自带的参数
   * time: 计量单位是秒 time/1000获取到毫秒
   * 数学公式: s = v * t
   * t的作用是保证每次移动的距离都是一样的, 而不是根据浏览器刷新频率
   * 可以打印time看一下就知道了
   * 取模5: 只有这样才能循环的从0位置开始移动, 不然会一直在0的位置上
   * time不能总是被拿来做各种设置和控制, 所以我们可以用时间跟踪函数clock替换
   * 代码: let t = (time / 1000) % 5;
   *
   *
   * 控制动画方式(二)
   * 用时钟函数来控制物体的移动
   * getElapsedTime: 时钟运行的总时长
   * getDelta: 间隔时常
   * 代码: let t = clock.getElapsedTime() % 5
   *
   *
   * 控制动画方式(三)
   * 引入gsap第三方动画库
   * 优点: 不用再去自己根据时间做限制动画了, 把物体丢进去就行了
   */
  // 设置物体的移动
  cube.position.x = 1 * t;
  // 设置物体旋转
  cube.rotation.x += 0.1;
  if (cube.position.x > 5) {
    cube.position.x = 0;
  }
  // 设置控制器update
  controls.update();
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  /**
   * 请求动画帧函数: 浏览器自带的渲染函数,
   * 每一次浏览器渲染的时候都要渲染场景
   * 有的电脑144hz,一秒钟就渲染144次
   */
  requestAnimationFrame(render);
}
// 默认渲染一下
render();
2. gsap动画库集成
安装依赖
yarn add gsap | npm install gsap
引用gsap
import gsap from "gsap";

/**
 * 给物体cube设置动画
 * 1.沿x轴移动距离5, 时间为5秒, 速度先快后慢
 * 2.沿x轴旋转360°, 时间为5秒, 速度先快后慢
 * 3.这样在渲染函数里就不需要再写控制代码了, 每次渲染的时候都会自动执行
 * 4.repeat: 循环的次数 -1为一直循环
 * 5.yoyo: 往返运动
 * 6.delay: 延迟几秒才开始运动
 */
var animate1 = gsap.to(cube.position, {
  x: 5,
  duration: 5,
  ease: "power1.inOut",
  repeat: -1,
  yoyo: true,
  delay: 2,
  onComplete: () => {
    console.log("动画完成!");
  },
  onStart: () => {
    console.log("动画开始!");
  },
});
var animate2 = gsap.to(cube.rotation, {
  x: 2 * Math.PI,
  duration: 5,
  ease: "power1.inOut",
  repeat: -1,
  yoyo: true,
  onComplete: () => {
    console.log("动画完成!");
  },
  onStart: () => {
    console.log("动画开始!");
  },
});

// 双击控制暂停旋转或者继续
window.addEventListener("dblclick", () => {
  if (animate1.isActive()) animate1.pause();
  else animate1.resume();
});
3. 跟随画面变化更新渲染视图
// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  //设置渲染器的像素比(不同设备不同的像素比, 适应屏幕分辨率)
  renderer.setPixelRatio(window.devicePixelRatio);
});
4. js控制全屏或者退出全屏
// 双击控制全屏或退出全屏
window.addEventListener("dblclick", () => {
  let fullScreenElement = document.fullscreenElement;
  if (!fullScreenElement) renderer.domElement.requestFullscreen();
  else document.exitFullscreen();
});
5. 应用图形界面更改变量
安装依赖dat.gui
yarn add dat.gui --save | npm install dat.gui --save
import * as dat from "dat.gui"; // 导入可视化控制器

// 定义一个可视化界面函数
const gui = new dat.GUI();
/**
 * 给物体添加x轴移动的可视化
 * min: 最小值
 * max: 最大值
 * step: 每次移动的距离
 * name: 给当前命名
 */
gui
  .add(cube.position, "x")
  .min(0)
  .max(5)
  .step(0.01)
  .name("x轴移动")
  .onChange((value) => {
    console.log("值被修改为:", value);
  })
  .onFinishChange((val) => {
    console.log("完全停下来的值:", val);
  });

// 给物体添加一个设置颜色的可视化界面
const params = {
  color: "#ffff00",
  fn: () => {
    // 点击事件让物体运动起来
    gsap.to(cube.position, { x: 0, duration: 2, yoyo: true, repeat: -1 });
  },
};
// 添加颜色改变的修改事件
gui.addColor(params, "color").onChange((value) => {
  cube.material.color.set(value);
});
// 控制物体是否显示
gui.add(cube, "visible").name("是否显示");
// 给物体添加点击事件
gui.add(params, "fn").name("点击立方体运动");
// 创建一个文件夹(把事件等用文件夹来归拢)
var folder = gui.addFolder("设置几何立方体");
// 添加一个设置材质为线框的属性
folder.add(cube.material, "wireframe");

image.png

6. 基础用法总结
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; // 导入轨道控制器
import gsap from "gsap"; // 导入动画库
import * as dat from "dat.gui"; // 导入可视化控制器

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建几何体 - BoxGeometry(几何体: 长 宽 高)
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
// 设置物体材质 - MeshBasicMaterial(基础网格材质: )
const cubeMat = new THREE.MeshBasicMaterial({ color: 0xffff00 });
// 根据几何体和物体材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMat);

// 移动物体
cube.position.set(1, 1, 1);
// 缩放物体(x轴缩放多少倍, y, z; 可以不用set方法单独设置)
cube.scale.set(1, 1, 2); // 由原来的(1, 1, 1)=>(2, 1, 3)
// 旋转物体(x轴缩放多少倍, y, z; 可以不用set方法单独设置)
cube.rotation.set(Math.PI / 4, 0, 0); // Math.Pi : Π, 180°
// 把几何体添加到场景中
scene.add(cube);

// 定义一个可视化界面函数
const gui = new dat.GUI();
/**
 * 给物体添加x轴移动的可视化
 * min: 最小值
 * max: 最大值
 * step: 每次移动的距离
 * name: 给当前命名
 */
gui
  .add(cube.position, "x")
  .min(0)
  .max(5)
  .step(0.01)
  .name("x轴移动")
  .onChange((value) => {
    console.log("值被修改为:", value);
  })
  .onFinishChange((val) => {
    console.log("完全停下来的值:", val);
  });

// 给物体添加一个设置颜色的可视化界面
const params = {
  color: "#ffff00",
  fn: () => {
    // 点击事件让物体运动起来
    gsap.to(cube.position, { x: 0, duration: 2, yoyo: true, repeat: -1 });
  },
};
// 添加颜色改变的修改事件
gui.addColor(params, "color").onChange((value) => {
  cube.material.color.set(value);
});
// 控制物体是否显示
gui.add(cube, "visible").name("是否显示");
// 给物体添加点击事件
gui.add(params, "fn").name("点击立方体运动");
// 创建一个文件夹(把事件等用文件夹来归拢)
var folder = gui.addFolder("设置几何立方体");
// 添加一个设置材质为线框的属性
folder.add(cube.material, "wireframe");

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

/**
 * 给物体cube设置动画
 * 1.沿x轴移动距离5, 时间为5秒, 速度先快后慢
 * 2.沿x轴旋转360°, 时间为5秒, 速度先快后慢
 * 3.这样在渲染函数里就不需要再写控制代码了, 每次渲染的时候都会自动执行
 * 4.repeat: 循环的次数 -1为一直循环
 * 5.yoyo: 往返运动
 * 6.delay: 延迟几秒才开始运动
 */
var animate1 = gsap.to(cube.position, {
  x: 5,
  duration: 5,
  ease: "power1.inOut",
  repeat: -1,
  yoyo: true,
  delay: 2,
  onComplete: () => {
    console.log("动画完成!");
  },
  onStart: () => {
    console.log("动画开始!");
  },
});
var animate2 = gsap.to(cube.rotation, {
  x: 2 * Math.PI,
  duration: 5,
  ease: "power1.inOut",
  repeat: -1,
  yoyo: true,
  onComplete: () => {
    console.log("动画完成!");
  },
  onStart: () => {
    console.log("动画开始!");
  },
});

// 封装渲染函数
function render() {
  if (cube.position.x > 5) {
    cube.position.x = 0;
  }
  // 设置控制器update
  controls.update();
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

// 单击控制暂停旋转或者继续
window.addEventListener("click", () => {
  if (animate1.isActive()) animate1.pause();
  else animate1.resume();
});
// 双击控制全屏或退出全屏
window.addEventListener("dblclick", () => {
  let fullScreenElement = document.fullscreenElement;
  if (!fullScreenElement) renderer.domElement.requestFullscreen();
  else document.exitFullscreen();
});
// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  //设置渲染器的像素比(不同设备不同的像素比, 适应屏幕分辨率)
  renderer.setPixelRatio(window.devicePixelRatio);
});

4. Threejs基础

1. 几何体

创建一个具有50个面且每个面的颜色都是随机的几何体

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; // 导入轨道控制器

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
for (let i = 0; i < 50; i++) {
  // 创建几何体 - BufferGeometry
  const geometry = new THREE.BufferGeometry();
  // 创建三维坐标位置数组
  const positionArray = new Float32Array(9); 
  // [-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0,1.0, -1.0, -1.0, 1.0,]
  // 每一个三角形有3个顶点,每个顶点有3个坐标
  for (let j = 0; j < 9; j++) {
    positionArray[j] = Math.random() * 10 - 5;
  }
  // 将3维的坐标点位置属性赋值给几何体
  geometry.setAttribute(
    "position",
    new THREE.BufferAttribute(positionArray, 3)
  );
  let color = new THREE.Color(Math.random(), Math.random(), Math.random());
  // 设置物体材质 - MeshBasicMaterial(基础网格材质)
  const material = new THREE.MeshBasicMaterial({
    color: color, // 设置材质颜色
    opacity: 0.5, // 设置透明材质
    transparent: true, // 设置为true才可以透明
  });
  // 根据几何体和物体材质创建物体
  const mesh = new THREE.Mesh(geometry, material);
  // 把几何体添加到场景中
  scene.add(mesh);
}

const params = { color: "#ffff00" };

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

image.png

2. 材质
1. 导入纹理
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 导入轨道控制器

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建一个几何体
const cubeGeometry = new THREE.BoxBufferGeometry(1, 1, 1);
// 导入纹理加载器
const textureLoader = new THREE.TextureLoader();
// 导入一张纹理
const door = textureLoader.load("./textures/door/door.jpg");
// 材质
const basicMaterial = new THREE.MeshBasicMaterial({
  color: "#ffff00", // 设置颜色
  map: door, // 设置纹理
});
// 组合几何体和材质
const cube = new THREE.Mesh(cubeGeometry, basicMaterial);
// 把几何体添加到场景中
scene.add(cube);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

纹理图:

door.jpg

2.设置纹理旋转_偏移_重复及算法mipmap
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 导入轨道控制器

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建一个几何体
const cubeGeometry = new THREE.BoxBufferGeometry(1, 1, 1);
// 导入纹理加载器
const textureLoader = new THREE.TextureLoader();
// 导入一张纹理
const door = textureLoader.load("./textures/door/door.jpg");
/**
 * 设置纹理属性
 *
 * 设置纹理偏移
 * door.offset.x = 0.5; // (0 - 1.0)
 * door.offset.y = 0.5;
 * door.offset.set(0.5, 0.5);
 *
 * 设置中心原点
 * door.center.set(0.5, 0.5);
 *
 * 设置纹理旋转
 * door.rotation = Math.PI / 4; // 旋转45度: 旋转多少度,单位是弧度
 *
 * 设置纹理重复;
 * door.repeat.set(2, 3); // 水平重复2次, 竖直重复3次
 *
 * 设置纹理重复的模式;
 * door.wrapS = THREE.MirroredRepeatWrapping; // 水平重复模式: 镜像
 * door.wrapT = THREE.RepeatWrapping; // 竖直重复模式: 无限重复
 *
 * 纹理算法
 * 类似css中的自适应, 纹理图片的大小与当前的几何体的大小自适应方式
 * door.minFilter = THREE.NearestFilter; // 最接近纹素的值
 * door.magFilter = THREE.NearestFilter;
 * door.magFilter = THREE.LinearFilter; // 线性的
 */
// 材质
const basicMaterial = new THREE.MeshBasicMaterial({
  color: "#ffff00", // 设置颜色
  map: door, // 设置纹理
});
// 组合几何体和材质
const cube = new THREE.Mesh(cubeGeometry, basicMaterial);
// 把几何体添加到场景中
scene.add(cube);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();
3. 透明材质与透明纹理
import * as THREE from "three";
import { DoubleSide } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 导入轨道控制器

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建一个几何体
const cubeGeometry = new THREE.BoxBufferGeometry(1, 1, 1);
// 导入纹理加载器
const textureLoader = new THREE.TextureLoader();
// 导入一张纹理
const door = textureLoader.load("./textures/door/door.jpg");
// 导入透明纹理背景图
const doorAlpha = textureLoader.load("./textures/door/color.jpg");
// alphaMap就是要么黑要么白,所以这个背景图也需要是这个颜色的
// 材质
const basicMaterial = new THREE.MeshBasicMaterial({
  color: "#ffff00", // 设置颜色
  map: door, // 设置纹理
  alphaMap: doorAlpha, // 设置纹理透明背景
  transparent: true, // 允许透明的属性, 为true才可以透明
  // opacity: 0.5 // 设置纹理透明度, 类似css中的背景图透明度设置
  side: DoubleSide, // 设置渲染哪一面  DoubleSide: 渲染两面
});
// 组合几何体和材质
const cube = new THREE.Mesh(cubeGeometry, basicMaterial);
// 把几何体添加到场景中
scene.add(cube);

// 添加一个平面(材质还是用上边的透明纹理)
const plane = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1),
  basicMaterial
);
plane.position.set(3, 0, 0);
scene.add(plane);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

透明纹理图:

color.jpg

效果图: image.png

4. 遮挡贴图
import * as THREE from "three";
import { DoubleSide } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 导入轨道控制器

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建一个几何体
const cubeGeometry = new THREE.BoxBufferGeometry(1, 1, 1);
// 导入纹理加载器
const textureLoader = new THREE.TextureLoader();
// 导入一张纹理
const door = textureLoader.load("./textures/door/door.jpg");
// 导入透明纹理背景图
const doorAlpha = textureLoader.load("./textures/door/color.jpg");
// alphaMap就是要么黑要么白,所以这个背景图也需要是这个颜色的
// 导入遮挡贴图
const doorTietu = textureLoader.load("./textures/door/tietu.jpg");
// 材质
const basicMaterial = new THREE.MeshBasicMaterial({
  color: "#ffff00", // 设置颜色
  map: door, // 设置纹理
  alphaMap: doorAlpha, // 设置纹理透明背景
  transparent: true, // 允许透明的属性, 为true才可以透明
  // opacity: 0.5 // 设置纹理透明度, 类似css中的背景图透明度设置
  side: DoubleSide, // 设置渲染哪一面  DoubleSide: 渲染两面
  aoMap: doorTietu, // 设置贴图(贴图就是给纹理再加上一个背景贴图)
  aoMapIntensity: 0.5, // ao贴图的强度设置
});
// 组合几何体和材质
const cube = new THREE.Mesh(cubeGeometry, basicMaterial);
// 给cube设置贴图的uv
cubeGeometry.setAttribute(
  "uv2",
  new THREE.BufferAttribute(cubeGeometry.attributes.uv.array, 2)
);
// 把几何体添加到场景中
scene.add(cube);

// 添加一个平面(材质还是用上边的透明纹理)
const plane = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1),
  basicMaterial
);
plane.position.set(3, 0, 0);
scene.add(plane);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

贴图:

tietu.jpg

效果图: image.png

5.标准网格材质与灯光物理效果
import * as THREE from "three";
import { DoubleSide } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建一个几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
// 导入纹理加载器
const textureLoader = new THREE.TextureLoader();
// 导入一张纹理
const door = textureLoader.load("./textures/door/door.jpg");
// 导入透明纹理背景图
const doorAlpha = textureLoader.load("./textures/door/color.jpg");
// alphaMap就是要么黑要么白,所以这个背景图也需要是这个颜色的
// 导入遮挡贴图
const doorTietu = textureLoader.load("./textures/door/tietu.jpg");
// 材质
const standardMaterial = new THREE.MeshStandardMaterial({
  color: "#ffff00", // 设置颜色
  map: door, // 设置纹理
  alphaMap: doorAlpha, // 设置纹理透明背景
  transparent: true, // 允许透明的属性, 为true才可以透明
  // opacity: 0.5 // 设置纹理透明度, 类似css中的背景图透明度设置
  side: DoubleSide, // 设置渲染哪一面  DoubleSide: 渲染两面
  aoMap: doorTietu, // 设置贴图(贴图就是给纹理再加上一个背景贴图)
  aoMapIntensity: 0.5, // ao贴图的强度设置
});
// 组合几何体和材质
const cube = new THREE.Mesh(cubeGeometry, standardMaterial);
// 给cube设置贴图的uv
cubeGeometry.setAttribute(
  "uv2",
  new THREE.BufferAttribute(cubeGeometry.attributes.uv.array, 2)
);
// 把几何体添加到场景中
scene.add(cube);

// 添加一个平面(材质还是用上边的透明纹理)
const plane = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), standardMaterial);
plane.position.set(3, 0, 0);
scene.add(plane);

/**
 * 追加灯光
 * // 创建环境光
 * const light = new THREE.AmbientLight(0xffffff, 0.9); 
 * // 0.9: 光线强度,默认是1
 * // 将环境光添加到场景中
 * scene.add(light);
 *
 * // 创建平行光
 * const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
 * // 设置灯光位置
 * directionalLight.position.set(10, 10, 10);
 * // 将平行光添加到场景中
 * scene.add(directionalLight);
 */
// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5);
// 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置灯光位置
directionalLight.position.set(10, 10, 10);
// 将平行光添加到场景中
scene.add(directionalLight);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render()

效果图: image.png

6.置换贴图(具有深度上的感觉, 或者说有凹凸感)
import * as THREE from "three";
import { DoubleSide } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建一个几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1, 100, 100, 100);
// 导入纹理加载器
const textureLoader = new THREE.TextureLoader();
// 导入一张纹理
const door = textureLoader.load("./textures/door/door.jpg");
// 导入透明纹理背景图
const doorAlpha = textureLoader.load("./textures/door/color.jpg");
// 导入遮挡贴图
const doorTietu = textureLoader.load("./textures/door/tietu.jpg");
// 导入置换贴图
const doorDeep = textureLoader.load("./textures/door/deep.jpg");

// 材质
const standardMaterial = new THREE.MeshStandardMaterial({
  color: "#ffff00", // 设置颜色
  map: door, // 设置纹理
  alphaMap: doorAlpha, // 设置纹理透明背景
  transparent: true, // 允许透明的属性, 为true才可以透明
  // opacity: 0.5 // 设置纹理透明度, 类似css中的背景图透明度设置
  side: DoubleSide, // 设置渲染哪一面  DoubleSide: 渲染两面
  aoMap: doorTietu, // 设置贴图(贴图就是给纹理再加上一个背景贴图)
  aoMapIntensity: 0.5, // ao贴图的强度设置
  displacementMap: doorDeep, // 设置置换贴图, 使其具有深度上的效果
  displacementScale: 0.05, // 置换贴图的影响强度
});
// 组合几何体和材质
const cube = new THREE.Mesh(cubeGeometry, standardMaterial);
// 给cube设置贴图的uv
cubeGeometry.setAttribute(
  "uv2",
  new THREE.BufferAttribute(cubeGeometry.attributes.uv.array, 2)
);
// 把几何体添加到场景中
scene.add(cube);

// 添加一个平面(材质还是用上边的透明纹理)
const plane = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), standardMaterial);
plane.position.set(3, 0, 0);
scene.add(plane);

// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置灯光位置
directionalLight.position.set(10, 10, 10);
// 将平行光添加到场景中
scene.add(directionalLight);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

贴图:

deep.jpg

效果图: image.png

7.粗糙度贴图金属贴图法线贴图
import * as THREE from "three";
import { DoubleSide } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建一个几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1, 100, 100, 100);
// 导入纹理加载器
const textureLoader = new THREE.TextureLoader();
// 导入一张纹理
const door = textureLoader.load("./textures/door/door.jpg");
// 导入透明纹理背景图
const doorAlpha = textureLoader.load("./textures/door/color.jpg");
// 导入遮挡贴图
const doorTietu = textureLoader.load("./textures/door/tietu.jpg");
// 导入置换贴图
const doorDeep = textureLoader.load("./textures/door/deep.jpg");
// 导入粗糙度贴图
const doorRoughness = textureLoader.load("./textures/door/roughness.jpg");
// 导入金属贴图
const doorMetalness = textureLoader.load("./textures/door/metalness.jpg");
// 导入法线贴图
const doorNormal = textureLoader.load("./textures/door/normal.jpg");
// 材质
const standardMaterial = new THREE.MeshStandardMaterial({
  color: "#ffff00", // 设置颜色
  map: door, // 设置纹理
  alphaMap: doorAlpha, // 设置纹理透明背景
  transparent: true, // 允许透明的属性, 为true才可以透明
  // opacity: 0.5 // 设置纹理透明度, 类似css中的背景图透明度设置
  side: DoubleSide, // 设置渲染哪一面  DoubleSide: 渲染两面
  aoMap: doorTietu, // 设置贴图(贴图就是给纹理再加上一个背景贴图)
  aoMapIntensity: 0.5, // ao贴图的强度设置
  displacementMap: doorDeep, // 设置置换贴图, 使其具有深度上的效果
  displacementScale: 0.05, // 置换贴图的影响强度
  roughness: 0, // 设置粗糙度, 0: 非常光滑, 1: 非常粗糙
  roughnessMap: doorRoughness, // 设置粗糙度贴图(贴图内颜色越接近黑色的部分越光滑)
  metalness: 0.5, // 设置金属度, 0: 不像金属, 1: 像金属
  metalnessMap: doorMetalness, // 设置金属贴图
  normalMap: doorNormal, // 设置法线贴图
});
// 组合几何体和材质
const cube = new THREE.Mesh(cubeGeometry, standardMaterial);
// 给cube设置贴图的uv
cubeGeometry.setAttribute(
  "uv2",
  new THREE.BufferAttribute(cubeGeometry.attributes.uv.array, 2)
);
// 把几何体添加到场景中
scene.add(cube);

// 添加一个平面(材质还是用上边的透明纹理)
const plane = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), standardMaterial);
plane.position.set(3, 0, 0);
scene.add(plane);

// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置灯光位置
directionalLight.position.set(10, 10, 10);
// 将平行光添加到场景中
scene.add(directionalLight);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

roughness.jpg: roughness .jpg

metalness.jpg: metalness.jpg

normal.jpg: normal.jpg

粗糙贴图效果: 1680159703177.jpg

金属贴图效果: 1680159704767.jpg

法线贴图效果: 1680160168506.jpg

8.纹理加载进度
import * as THREE from "three";
import { DoubleSide } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 添加物体
// 创建一个几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1, 100, 100, 100);
// 设置加载管理器(除了纹理,包括模型等都可以进行管理)
const loadingManager = new THREE.LoadingManager();
loadingManager.onStart = function (url, itemsLoaded, itemsTotal) {
  console.log("开始加载...", url, itemsLoaded, itemsTotal);
};
loadingManager.onProgress = function (url, itemsLoaded, itemsTotal) {
  console.log("加载中...", url, itemsLoaded, itemsTotal);
};
loadingManager.onLoad = function () {
  console.log("开始完成...");
};
loadingManager.onError = function (url) {
  console.log("开始出错...", url);
};
// 导入纹理加载器
const textureLoader = new THREE.TextureLoader(loadingManager);
// 导入一张纹理
const door = textureLoader.load("./textures/door/door.jpg");
// 导入透明纹理背景图
const doorAlpha = textureLoader.load("./textures/door/color.jpg");
// 导入遮挡贴图
const doorTietu = textureLoader.load("./textures/door/tietu.jpg");
// 导入置换贴图
const doorDeep = textureLoader.load("./textures/door/deep.jpg");
// 导入粗糙度贴图
const doorRoughness = textureLoader.load("./textures/door/roughness.jpg");
// 导入金属贴图
const doorMetalness = textureLoader.load("./textures/door/metalness.jpg");
// 导入法线贴图
const doorNormal = textureLoader.load("./textures/door/normal.jpg");
// 材质
const standardMaterial = new THREE.MeshStandardMaterial({
  color: "#ffff00", // 设置颜色
  map: door, // 设置纹理
  alphaMap: doorAlpha, // 设置纹理透明背景
  transparent: true, // 允许透明的属性, 为true才可以透明
  // opacity: 0.5 // 设置纹理透明度, 类似css中的背景图透明度设置
  side: DoubleSide, // 设置渲染哪一面  DoubleSide: 渲染两面
  aoMap: doorTietu, // 设置贴图(贴图就是给纹理再加上一个背景贴图)
  aoMapIntensity: 0.5, // ao贴图的强度设置
  displacementMap: doorDeep, // 设置置换贴图, 使其具有深度上的效果
  displacementScale: 0.05, // 置换贴图的影响强度
  roughness: 0, // 设置粗糙度, 0: 非常光滑, 1: 非常粗糙
  roughnessMap: doorRoughness, // 设置粗糙度贴图(贴图内颜色越接近黑色的部分越光滑)
  metalness: 0.5, // 设置金属度, 0: 不像金属, 1: 像金属
  metalnessMap: doorMetalness, // 设置金属贴图
  normalMap: doorNormal, // 设置法线贴图
});
// 组合几何体和材质
const cube = new THREE.Mesh(cubeGeometry, standardMaterial);
// 给cube设置贴图的uv
cubeGeometry.setAttribute(
  "uv2",
  new THREE.BufferAttribute(cubeGeometry.attributes.uv.array, 2)
);
// 把几何体添加到场景中
scene.add(cube);

// 添加一个平面(材质还是用上边的透明纹理)
const plane = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), standardMaterial);
plane.position.set(3, 0, 0);
scene.add(plane);

// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置灯光位置
directionalLight.position.set(10, 10, 10);
// 将平行光添加到场景中
scene.add(directionalLight);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

image.png

9.环境贴图与背景贴图
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// RGBELoader加载器, 可用于导入rgbe或者hdr...等图片类型文件
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 导入环境贴图
const envTextures = new THREE.CubeTextureLoader()
  .setPath("textures/cubeMaps/")
  .load(["1.jpg", "2.jpg", "3.jpg", "4.jpg", "5.jpg", "6.jpg"]);
// 创建球星几何体
const geometry = new THREE.SphereGeometry(1, 20, 20);
// 创建标准网格材质
const material = new THREE.MeshStandardMaterial({
  metalness: 0.7,
  roughness: 0.1,
  // envMap: envTextures, // 环境纹理贴图(设置方式1)
});
// 给场景设置背景贴图 (设置方式1)
// scene.background = envTextures;

// 异步导入hdr类型的环境贴图(设置方式2)
const rgbeLoader = new RGBELoader();
rgbeLoader.loadAsync("textures/hdr/1.hdr").then((texture) => {
  // 设置纹理的映射方式 - 像地球一样映射
  texture.mapping = THREE.EquirectangularReflectionMapping;
  scene.background = texture; // 设置背景纹理
  scene.environment = texture; // 设置环境纹理
});
// 将材质和几何体
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置灯光位置
directionalLight.position.set(10, 10, 10);
// 将平行光添加到场景中
scene.add(directionalLight);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

效果图: image.png

10.灯光与阴影
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// RGBELoader加载器, 可用于导入rgbe或者hdr...等图片类型文件
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";

/**
 * 灯光与阴影
 * 1. 材质要满足能够对光照反应
 * 2. 设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;
 * 3. 设置光照投射阴影 directionalLight.castShadow = true;
 * 4. 设置物体投射阴影 sphere.castShadow = true;
 * 5. 设置物体接收阴影 plane.receiveShadow = true;
 */

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 创建球星几何体
const geometry = new THREE.SphereGeometry(1, 20, 20);
// 创建标准网格材质
const material = new THREE.MeshStandardMaterial();

// 异步导入hdr类型的环境贴图(设置方式2)
const rgbeLoader = new RGBELoader();
rgbeLoader.loadAsync("textures/hdr/1.hdr").then((texture) => {
  // 设置纹理的映射方式 - 像地球一样映射
  texture.mapping = THREE.EquirectangularReflectionMapping;
});
// 将材质和几何体
const sphere = new THREE.Mesh(geometry, material);
// 设置物体投射阴影
sphere.castShadow = true;
scene.add(sphere);

// 添加一个平面
const planeGeometry = new THREE.PlaneGeometry(10, 10);
const plane = new THREE.Mesh(planeGeometry, material);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
// 设置物体接收阴影
plane.receiveShadow = true;
scene.add(plane);

// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置灯光位置
directionalLight.position.set(10, 10, 10);
// 设置光照投射阴影
directionalLight.castShadow = true;
// 将平行光添加到场景中
scene.add(directionalLight);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 开始场景中的阴影贴图
renderer.shadowMap.enabled = true;
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

效果图: image.png

11.平行光阴影属性及相机原理
import * as dat from "dat.gui"; // 导入可视化控制器
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// RGBELoader加载器, 可用于导入rgbe或者hdr...等图片类型文件
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";

/**
 * 平行灯光与阴影
 * 1. 材质要满足能够对光照反应
 * 2. 设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;
 * 3. 设置光照投射阴影 directionalLight.castShadow = true;
 * 4. 设置物体投射阴影 sphere.castShadow = true;
 * 5. 设置物体接收阴影 plane.receiveShadow = true;
 */

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 创建球星几何体
const geometry = new THREE.SphereGeometry(1, 20, 20);
// 创建标准网格材质
const material = new THREE.MeshStandardMaterial({
  // metalness: 0.7,
  // roughness: 0.1,
});

// 异步导入hdr类型的环境贴图(设置方式2)
const rgbeLoader = new RGBELoader();
rgbeLoader.loadAsync("textures/hdr/1.hdr").then((texture) => {
  // 设置纹理的映射方式 - 像地球一样映射
  texture.mapping = THREE.EquirectangularReflectionMapping;
  // scene.background = texture; // 设置背景纹理
  // scene.environment = texture; // 设置环境纹理
});
// 将材质和几何体
const sphere = new THREE.Mesh(geometry, material);
// 设置物体投射阴影
sphere.castShadow = true;
scene.add(sphere);

// 添加一个平面
const planeGeometry = new THREE.PlaneGeometry(10, 10);
const plane = new THREE.Mesh(planeGeometry, material);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
// 设置物体接收阴影
plane.receiveShadow = true;
scene.add(plane);

// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置灯光位置
directionalLight.position.set(5, 5, 5);
// 设置光照投射阴影
directionalLight.castShadow = true;
// 设置阴影贴图模糊度
directionalLight.shadow.radius = 20;
// 设置阴影贴图分辨率
directionalLight.shadow.mapSize.set(2048, 2048); // 值越高越清晰
// 设置平行光投射像机的属性
directionalLight.shadow.camera.near = 0.5; // 近端
directionalLight.shadow.camera.far = 500; // 远端
directionalLight.shadow.camera.top = 5; // 上
directionalLight.shadow.camera.bottom = -5;
directionalLight.shadow.camera.left = -5;
directionalLight.shadow.camera.right = 5;
// 将平行光添加到场景中
scene.add(directionalLight);

const gui = new dat.GUI();
gui
  .add(directionalLight.shadow.camera, "near")
  .min(0)
  .max(10)
  .step(0.1)
  .onChange(() => {
    directionalLight.shadow.camera.updateProjectionMatrix();
  });

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 开始场景中的阴影贴图
renderer.shadowMap.enabled = true;
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

效果贴图: image.png

12.聚光灯各种属性与应用
import * as dat from "dat.gui"; // 导入可视化控制器
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// RGBELoader加载器, 可用于导入rgbe或者hdr...等图片类型文件
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";

/**
 * 聚光灯
 */

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 创建球星几何体
const geometry = new THREE.SphereGeometry(1, 20, 20);
// 创建标准网格材质
const material = new THREE.MeshStandardMaterial({
  // metalness: 0.7,
  // roughness: 0.1,
});

// 异步导入hdr类型的环境贴图(设置方式2)
const rgbeLoader = new RGBELoader();
rgbeLoader.loadAsync("textures/hdr/1.hdr").then((texture) => {
  // 设置纹理的映射方式 - 像地球一样映射
  texture.mapping = THREE.EquirectangularReflectionMapping;
  // scene.background = texture; // 设置背景纹理
  // scene.environment = texture; // 设置环境纹理
});
// 将材质和几何体
const sphere = new THREE.Mesh(geometry, material);
// 设置物体投射阴影
sphere.castShadow = true;
scene.add(sphere);

// 添加一个平面
const planeGeometry = new THREE.PlaneGeometry(50, 50);
const plane = new THREE.Mesh(planeGeometry, material);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
// 设置物体接收阴影
plane.receiveShadow = true;
scene.add(plane);

// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);
// 创建聚光灯
const spotLight = new THREE.SpotLight(0xffffff, 1);
// 设置灯光亮度
spotLight.intensity = 2;
// 设置灯光位置
spotLight.position.set(5, 5, 5);
// 设置光照投射阴影
spotLight.castShadow = true;
// 设置阴影贴图模糊度
spotLight.shadow.radius = 20;
// 设置阴影贴图分辨率
spotLight.shadow.mapSize.set(2048, 2048); // 值越高越清晰
// 设置投射目标(随着物体移动进行打光)
spotLight.target = sphere;
// 设置聚光灯的角度
spotLight.angle = Math.PI / 6; // (不要超过90°Math.PI / 2)
// 设置聚光灯能照多远(越远越暗)
spotLight.distance = 50;
// 聚光锥的半阴影效果(值为0 - 1, 默认0, 值越大阴影越小越暗, 就越像真实的聚光灯)
spotLight.penumbra = 0;
// 设置沿着光照距离的衰减量
spotLight.decay = 2;
// 设置透视相机的属性
spotLight.shadow.camera.near = 500; // 近端
spotLight.shadow.camera.far = 4000; // 远端
spotLight.shadow.camera.fov = 30; // 角度
// 将聚光灯添加到场景中
scene.add(spotLight);

const gui = new dat.GUI();
gui.add(sphere.position, "x").min(-5).max(5).step(0.1);
gui
  .add(spotLight, "angle")
  .min(0)
  .max(Math.PI / 2)
  .step(0.01);
gui.add(spotLight, "distance").min(0).max(100).step(0.01);
gui.add(spotLight, "penumbra").min(0).max(1).step(0.01);
gui.add(spotLight, "decay").min(0).max(5).step(0.01);
gui.add(spotLight, "intensity").min(0).max(2).step(0.01);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 开始场景中的阴影贴图
renderer.shadowMap.enabled = true;
// 使用物理上正确的光照模式(与decay有关)
renderer.useLegacyLights = true;
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);

// 封装渲染函数
function render() {
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

效果图: 1680248020125.jpg

13.点光源各种属性与应用
import * as dat from "dat.gui"; // 导入可视化控制器
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// RGBELoader加载器, 可用于导入rgbe或者hdr...等图片类型文件
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";

/**
 * 点光源
 */

// 创建一个场景
const scene = new THREE.Scene();

// 创建一个相机(透视相机)
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机的位置(x, y, z)
camera.position.set(0, 0, 10);
// 把相机添加到场景中
scene.add(camera);

// 创建球星几何体
const geometry = new THREE.SphereGeometry(1, 20, 20);
// 创建标准网格材质
const material = new THREE.MeshStandardMaterial();

// 异步导入hdr类型的环境贴图(设置方式2)
const rgbeLoader = new RGBELoader();
rgbeLoader.loadAsync("textures/hdr/1.hdr").then((texture) => {
  // 设置纹理的映射方式 - 像地球一样映射
  texture.mapping = THREE.EquirectangularReflectionMapping;
  // scene.background = texture; // 设置背景纹理
  // scene.environment = texture; // 设置环境纹理
});
// 将材质和几何体
const sphere = new THREE.Mesh(geometry, material);
// 设置物体投射阴影
sphere.castShadow = true;
scene.add(sphere);

// 添加一个平面
const planeGeometry = new THREE.PlaneGeometry(50, 50);
const plane = new THREE.Mesh(planeGeometry, material);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
// 设置物体接收阴影
plane.receiveShadow = true;
scene.add(plane);

// 创建环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // 0.9: 光线强度,默认是1
// 将环境光添加到场景中
scene.add(light);

// 创建一个小球
const smallBall = new THREE.Mesh(
  new THREE.SphereGeometry(0.1, 20, 20),
  new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
// 设置小球的位置
smallBall.position.set(2, 2, 2);
// 创建点光源
const pointLight = new THREE.PointLight(0xff0000, 1);
// 设置灯光亮度
pointLight.intensity = 2;
// 设置灯光位置
// pointLight.position.set(2, 2, 2);
// 设置光照投射阴影
pointLight.castShadow = true;
// 设置阴影贴图模糊度
pointLight.shadow.radius = 20;
// 设置阴影贴图分辨率
pointLight.shadow.mapSize.set(2048, 2048); // 值越高越清晰
// 设置点光源能照多远(越远越暗)
pointLight.distance = 50;
// 设置沿着光照距离的衰减量
pointLight.decay = 2;
// 设置透视相机的属性
// pointLight.shadow.camera.near = 500; // 近端
// pointLight.shadow.camera.far = 4000; // 远端
// pointLight.shadow.camera.fov = 30; // 角度
// 将点光源添加到小球上
smallBall.add(pointLight);
// 将点光源添加到场景中 - 将发光的小球添加到场景中
scene.add(smallBall);

const gui = new dat.GUI();
gui.add(pointLight.position, "x").min(-5).max(5).step(0.1);
gui.add(pointLight, "distance").min(0).max(100).step(1);
gui.add(pointLight, "decay").min(0).max(5).step(0.01);
gui.add(pointLight, "intensity").min(0).max(2).step(0.01);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 开始场景中的阴影贴图
renderer.shadowMap.enabled = true;
// 使用物理上正确的光照模式(与decay有关)
renderer.useLegacyLights = true;
// 将webgl渲染的canvas内容添加到body当中
document.body.append(renderer.domElement);

// 创建轨道控制器(围绕的相机, 渲染器)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼, 使其更加逼真, 比如具有惯性
controls.enableDamping = true; // 每次更新都要update
// 给场景添加坐标抽辅助线(x,y,z)
const axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);
// 设置时钟
const clock = new THREE.Clock();

// 封装渲染函数
function render() {
  let time = clock.getElapsedTime();
  smallBall.position.x = Math.sin(time) * 3; // 直线运动
  smallBall.position.z = Math.cos(time) * 3; // 圆周运动
  // smallBall.position.y = Math.cos(time) * 3; // 旋转运动
  smallBall.position.y = 2 + Math.sin(time * 10) / 2; // 跳跃运动
  controls.update();
  // 使用渲染器, 通过相机将场景渲染出来
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
// 默认渲染一下
render();

效果图: 1680250564087.jpg

5. 源码地址

链接