从0搭建一个3D立体场景:光影与交互全解析

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();
相关推荐
孟陬33 分钟前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端
Zhao-Jichao42 分钟前
AI Prompting for Everyone 课程笔记 - P17 图像生成 Imaging Generation
前端
Highcharts.js1 小时前
智能数据分析组件Orbit 正式发布与快速上手体验教程
前端·人工智能·信息可视化·数据分析系统·highcharts·orbit·智能可视化
螺丝钉tina2 小时前
[Playwright ][16]Playwright + TypeScript API 自动化测试实战:API测试
前端·javascript·typescript
Jmyd01232 小时前
文物3D数字化的技术选型指南:从WW/T 0115标准到落地工程,一次讲透采集、建档、管理与展示
3d·系统架构·博物馆·数字展厅·博物馆数字化
小天源3 小时前
智叟云集系统 · 架构与职责分层
服务器·前端·数据库
Highcharts.js4 小时前
React 中原生支持使用 JSX 组件配置自定义表格 Highcharts Grid
前端·javascript·react.js·前端框架·jsx·highcharts·自定义表格
薛定谔的猫-菜鸟程序员5 小时前
Electron开发超详细教程(从入门到放弃)
前端·javascript·electron
最强小杰5 小时前
DeepSeek V4 Flash + Codex CLI 接入教程:原生 Responses API 适配,从配置到跑通收藏这篇就够了(2026)
java·前端·python·ai
静水leo6 小时前
使用 Whistle 拦截接口并模拟后端响应
前端