3D场景的搭建框架的三要素
一个基础框架的搭建:相机,场景,渲染器;camera生成投影矩阵和视点矩阵,scene类似一个舞台,用来放我们要渲染的对象,renderer则是将我们的对象画到canvas中。

// 初始化相机、场景、渲染器等
const canvas = document.getElementById("webgl");
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 3000);
camera.position.set(100, 100, 100);
camera.lookAt(0, 0, 0);
// 创建场景
const scene = new THREE.Scene();
// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, canvas: canvas });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
控制器(OrbitControls)
控制器用来实现交互过程的,通过这个我们就可以实现动画的手动旋转,不加就是固定角度
// 创建控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.update();
创建渲染对象(mesh)
场景搭建好了,那么我们就开始要放进去我们要渲染的对象啦,这时候我们创建一个几何体,将它加入到场景中。
THREE.Mesh需要接收两个参数:几何体+材质
const geometry = new THREE.BoxGeometry(10, 10, 10);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
一个简单的立体就可以展示了:
通过渲染,恭喜你,一个简单的demo就完成了
renderer.render(scene, camera);

不够一般我们都会通过一个动画的函数来进行调用,让它动起来,通过下面这个函数,一个可交互的立方体就展示出来了。
// 动画循环
function animate() {
requestAnimationFrame(animate);
controls.update();
//让立方体旋转起来
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
光与阴影
想让一个物体具有真实的立体感,我们需要通过光面和阴影来进行一个完整的映射过程。
开启阴影
渲染阴影比较消耗性能,Three.js为了性能考虑,一般是关闭了阴影的效果,所以需要我们手动开启一下。
//开启阴影支持
renderer.shadowMap.enabled = true
//设置阴影类型,PCFSoftShadowMap 是软阴影(边缘带有模糊效果),PCFShadowMap 是硬阴影
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
//设置场景背景颜色 改为浅灰色 方便更好形成明暗对比
renderer.setClearColor(0x262626);
同时我们要保证我们的对象可以接收到阴影
const cube = new THREE.Mesh(geometry, material);
// 设置为投射阴影:即该物体挡住光线的时候可以产生阴影
cube.castShadow = true;
// 设置为接收阴影:即其他物体的影子可以投射在它的身上
cube.receiveShadow = true;
因为没有光照的情况下我们只能看到一个黑影,只有光照的情况下,才可以正常的渲染

开启光亮:
通过光照、光照的方向以及灯光布局的方式让物体变的有阴影。
光源包含环境光和平行光。环境光是一种均匀照亮场景中的光,用来充当补光的作用;平行光模拟的是主光源(类似太阳),用来使物体产生阴影和棱角的。
//布局灯光
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
//平行光:
const sunLight = new THREE.DirectionalLight(0xffffff, 1);
sunLight.position.set(1, 1, 1);
scene.add(sunLight);
//开启主光源的阴影
sunLight.castShadow = true;
创建地面
要看到物体的阴影,我们不仅需要一个物体对象,而且需要地面来进行展示,所以需要渲染一个地面对象,渲染方式和创建几何体一样:
const planeGeometry = new THREE.PlaneGeometry(100, 100);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x444444 });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -Math.PI / 2; // 使平面水平
plane.position.y = -5; // 地面位置在y轴-5 地面下沉到物体下方
// 地面必须设置为"接收阴影"
plane.receiveShadow = true;
scene.add(plane);
一个带有影子的立体几何就做出来了

源码:
安装three,创建ts文件,引入即可
// 一个3D立体的场景 需要灯光需要阴影才能呈现一个立体感
import "./style.css";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 初始化相机、场景、渲染器等
const canvas = document.getElementById("webgl");
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 3000);
camera.position.set(100, 100, 100);
camera.lookAt(0, 0, 0);
// 创建场景
const scene = new THREE.Scene();
// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, canvas: canvas });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// 创建控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.update();
//开启阴影支持
renderer.shadowMap.enabled = true
//设置阴影类型,PCFSoftShadowMap 是软阴影(边缘带有模糊效果),PCFShadowMap 是硬阴影
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
//设置场景背景颜色,改为浅灰色,方便更好形成明暗对比
renderer.setClearColor(0x262626);
// 创建一个简单的立方体
const geometry = new THREE.BoxGeometry(10, 10, 10);
// MeshBasicMaterial 基础材质,没有光照效果,需要更改为MeshStandardMaterial
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
// 设置为投射阴影:即该物体挡住光线的时候可以产生阴影
cube.castShadow = true;
// 设置为接收阴影:即其他物体的影子可以投射在它的身上
cube.receiveShadow = true;
scene.add(cube);
//布局灯光
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
//平行光:
const sunLight = new THREE.DirectionalLight(0xffffff, 1);
sunLight.position.set(1, 1, 1);
scene.add(sunLight);
//开启主光源的阴影
sunLight.castShadow = true;
// // 优化阴影的精细度
// // 默认的阴影贴图可能比较糊,这里将其分辨率调大一倍 (默认是 512x512)
// sunLight.shadow.mapSize.width = 1024;
// sunLight.shadow.mapSize.height = 1024;
//创建地面
const planeGeometry = new THREE.PlaneGeometry(100, 100);
const planeMaterial = new THREE.MeshStandardMaterial({
color: 0x444444,
roughness: 0.8, // 地面粗糙一点,不反光
metalness: 0.0
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -Math.PI / 2; // 使平面水平
plane.position.y = -10; // 地面位置在y轴-10 地面下沉到物体下方
// 地面必须设置为"接收阴影"
plane.receiveShadow = true;
scene.add(plane);
// 动画循环
function animate() {
requestAnimationFrame(animate);
controls.update();
//让立方体旋转起来
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();