three.js基于物理的场景和渲染

创建物理大小场景

为了使物理上正确的照明准确,需要构建物理大小的场景,three.js 中的大小单位是米

  • 2×2×2的立方体的每边长为两米
  • camera.far = 100表示看到一百米的距离
  • camera.near = 0.1表示距离相机十厘米以内的物体将不可见

使用米为单位是一种约定,而不是规则。如果不遵循它,那么除了物理上精确的照明之外的一切都仍然有效。如果想要物理上准确的照明,那么必须使用1单位=1米的公式将场景构建到真实世界的规模。

three.js 中的光照

要打开物理上正确的照明,只需启用渲染器的 physicallyCorrectLights属性,将其设置为true。

vue 复制代码
import { WebGLRenderer } from 'three';
// 创建渲染器
const renderer = new WebGLRenderer();
// 启用物理正确的照明
renderer.physicallyCorrectLights = true;

默认情况下禁用此设置是为了保持向后兼容性。但是,打开它没有缺点,因此可以将始终启用它。还需要调整一些参数,以使颜色和照明以物理上正确的方式工作。

three.js 中的灯光类型

如果在一个黑暗的房间里打开一个灯泡,那个房间里的物体会以两种方式接收到光:

  1. 直接照明:直接来自灯泡并撞击物体的光线。
  2. 间接照明:光线在击中物体之前已经从墙壁和房间内的其他物体反弹,每次反弹都会改变颜色并失去强度。

与之匹配,three.js 中的灯光类分为两种类型:

  1. 直接光照,模拟直接光照
  2. 环境光,这是廉价且可信的间接照明方式

可以轻松模拟直接照明。直接光线从光源出来并沿直线继续,直到它们击中或不击中物体。然而,间接照明很难模拟,因为这样做需要计算从场景中所有表面永远反射的无限数量的光线。没有足够强大的计算机来做到这一点,即使限制仅计算几千条光线,每条光线只产生几次反弹,实时计算通常仍然需要很长时间。因此,如果想要场景中的真实光照,需要某种方式来伪造间接光照。在 three.js 中有几种技术可以做到这一点,其中环境光就是其中之一。其他的几种技术分别是基于图像的照明 (IBL) 和光探测器。

直接照明

three.js 中总共有四种直接光源类型可用,每一种都模拟一个常见的现实世界光源:

  • DirectionalLight => 阳光
  • PointLight => 灯泡
  • RectAreaLight => 条形照明或明亮的窗户
  • SpotLight => 聚光灯

默认情况下禁用阴影。即使使用基于物理的渲染,现实世界和 three.js 之间的一个区别是默认情况下对象不会阻挡光线。光路径中的每个物体都会收到照明,即使路上有一堵墙。

我们可以逐个对象的、逐个光照的手动启用阴影。但是如此一来很麻烦,因此通常只为一盏灯或两盏灯启用阴影,尤其是当场景需要在移动设备上工作时。只有直接光类型可以投射阴影,环境光不能

DirectionalLight

DirectionalLight设计的目的是模仿遥远的光源,例如太阳。DirectionalLight的光线不会随着距离而消失。场景中的所有对象都将被同样明亮地照亮,无论它们放在哪里,即使是在灯光后面

DirectionalLight的光线是平行的,从一个位置照向一个目标。默认情况下,目标放置在我们场景的中心(点(0,0,0)),所以当我们移动周围的光线时,它总是会向中心照射。

创建灯光

创建light实例对象,DirectionalLight构造函数有两个参数,颜色color 和强度intensity。此处创建一个强度为 8 的纯白光:

vue 复制代码
import { DirectionalLight } from 'three';
const light = new DirectionalLight('white', 8);
// 将灯光添加到场景中
scene.add(light)

所有 three.js 灯都有颜色和强度设置,继承自 Light基类。

创建灯光后并将其添加到场景中,向场景中添加灯光就像添加网格一样。

scene.add(mesh,light);调用中就添加了灯光和网格。可以添加任意数量的对象,用逗号分隔。

定位灯光

灯光从light.position照向light.target.position。灯光和目标的默认位置都是场景的中心(0,0,0)。这意味着光线当前正在从(0,0,0)照向(0,0,0)。 这确实有效,但看起来不太好。可以通过调整light.position来改善灯光的外观。通过将位置设置为(10,10,10)来达到向左、向上和朝向用户移动它的效果。

js 复制代码
import { DirectionalLight } from 'three';
const light = new DirectionalLight('white', 8);
// 灯光从(10,10,10)照向(0,0,0)
light.position.set(10, 10, 10);

基于物理的材质

MeshBasicMaterial这种材质会忽略场景中的任何灯光。 MeshBasicMaterial是 three.js 中提供的最基本的材料,它根本不会对灯光做出反应,并且网格的整个表面都用单一颜色着色。不执行基于视角或距离的着色,因此对象看起来甚至不是三维的,而只是一个二维轮廓。

可以使用MeshStandardMaterial,这是一种高质量、通用、物理精确的材质,可以使用真实世界的物理方程对光做出反应。所以MeshStandardMaterial可以是几乎所有情况下的首选标准材质。

所有材质基于Material基类,但不能直接使用Material。而必须始终使用它的派生类中的某一个,例如MeshStandardMaterial或者MeshBasicMaterial

更改材质的颜色

设置材质参数与盒子几何体等其他类略有不同,必须需要使用具有命名参数的规范对象:

js 复制代码
const spec = {
color: 'purple',
}
const material = new MeshStandardMaterial(spec);
// 或者内联声明对象
const material = new MeshStandardMaterial({ color: "purple" });

旋转立方体

旋转立方体,这样就不再直视它了。调整对象的旋转与设置位置(平移)的方式大致相同。用于变换物体的方法有平移、旋转和缩放。

vue 复制代码
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import {
  BoxGeometry,
  Color,
  Mesh,
  MeshStandardMaterial,
  PerspectiveCamera,
  Scene,
  DirectionalLight,
  WebGLRenderer,
} from 'three';
const canvas = ref<HTMLElement | null>(null);
onMounted(() => {
// 创建场景
const scene = new Scene();
// 设置场景的背景颜色
scene.background = new Color('gold');
// 创建相机并设置其位置
const fov = 35;
const aspect = canvas.value?.clientWidth / canvas.value?.clientHeight;
const near = 0.1;
const far = 100;
const camera = new PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 0, 10);
// 创建2*2*2盒子形状的几何体
const geometry = new BoxGeometry(2, 2, 2);
// 创建默认材质
const material = new MeshStandardMaterial({color:'white'});
// 创建网格
const mesh = new Mesh(geometry, material);
// 设置对象旋转
mesh.rotation.set(-0.5, -0.1, 0.8);
// 创建灯光
const light = new DirectionalLight('white', 8);
// 灯光从(10,10,10)照向(0,0,0)
light.position.set(10, 10, 10);
// 将网格和灯光添加到场景中
scene.add(mesh,light);
// 创建渲染器
const renderer = new WebGLRenderer();
// 设置渲染器的大小
renderer.setSize(canvas.value?.clientWidth, canvas.value?.clientHeight);
// 设置设备像素比(DPR)
renderer.setPixelRatio(window.devicePixelRatio);
// 添加canvas元素在页面中
canvas.value?.append(renderer.domElement);
// 渲染场景
renderer.render(scene, camera);
});
</script>

<template>
  <div ref="canvas" id="canvas"></div>
</template>

<style scoped lang="scss">
#canvas {
  width: 100vw;
  height: 100vh;
}
</style>
相关推荐
Nan_Shu_6142 天前
学习: Threejs (15)& Threejs (16)
学习·three.js
Charlie_lll2 天前
学习Three.js–材质(Material)
前端·three.js
答案—answer6 天前
开源项目:Three.js3D模型可视化编辑系统
javascript·3d·开源·开源项目·three.js·three.js编辑器
贝格前端工场6 天前
困在像素里:我的可视化大屏项目与前端价值觉醒
前端·three.js
全栈王校长7 天前
Three.js 材质进阶
webgl·three.js
全栈王校长7 天前
Three.js Geometry进阶
webgl·three.js
烛阴7 天前
3D字体TextGeometry
前端·webgl·three.js
全栈王校长8 天前
Three.js 开发快速入门
three.js
全栈王校长8 天前
Three.js 环境搭建与开发初识
three.js
DaMu8 天前
Dreamcore3D ARPG IDE “手搓”游戏引擎,轻量级实时3D创作工具,丝滑操作,即使小白也能轻松愉快的创作出属于你自己的游戏世界!
前端·架构·three.js