最佳ThreeJS实践 · 实现赛博朋克风格的三维图像气泡效果

embedded/2024/10/21 9:20:06/

在现代计算机图形学和游戏开发中,创建引人入胜且逼真的三维场景是至关重要的。赛博朋克风格,以其鲜艳的色彩、充满未来感的细节以及复杂的光影效果,成为了许多开发者和艺术家的热门选择。在本文中,我们将深入探讨如何利用 Three.js 创建一个高质量的赛博朋克风格三维场景,特别是如何优化纹理的清晰度和材质设置,以实现最佳的视觉效果。

Three.js 简介

Three.js 是一个开源的 JavaScript 库,用于在网页上创建和显示三维图形。它提供了强大的工具和功能,使得开发者可以轻松地创建复杂的三维场景。Three.js 支持多种材质和纹理配置,使得开发者能够对每个细节进行精确控制。

请在此添加图片描述

整体思路

赛博朋克风格

赛博朋克风格源于对未来科技与破碎社会之间关系的描绘。这种风格通常包括霓虹灯光、复杂的建筑结构和阴暗的背景。为了捕捉这种独特的美学,我们需要精心设计场景的每一个细节,从背景色彩到纹理质量,每一部分都需要与赛博朋克风格的主题相辅相成。

创建赛博朋克风格场景

在创建赛博朋克风格场景时,我们首先需要搭建基本的 Three.js 环境。

初始化项目

🌶️ 创建一个文件夹叫ThreeJsDemo,然后在当前的这个文件夹下面执行如下命令:

javascript">npm init -y

🌶️ 安装Three.js

javascript">npm install three

将Vite安装成开发时依赖,使用vite启动开发服务

javascript">npm i vite -D

纹理优化

为了在赛博朋克风格场景中实现最佳的视觉效果,我们需要关注纹理的清晰度。以下几个参数对纹理的显示效果有显著影响:

过滤方式: minFilter 和 magFilter 控制纹理的缩小和放大效果。我们选择了 THREE.LinearMipMapLinearFilter 和 THREE.LinearFilter,这能在不同的缩放比例下提供更平滑的效果,避免了锯齿状的边缘。
各向异性过滤: anisotropy 设置了纹理的各向异性过滤等级。通过 renderer.capabilities.getMaxAnisotropy() 自动获取最大等级,确保在远处或倾斜视角下纹理仍然清晰。
编码方式: encoding 参数设置了纹理的颜色编码方式。THREE.sRGBEncoding 用于处理 gamma 校正,使得纹理颜色更加准确和生动。

调整图片大小和气泡感效果

为了增强赛博朋克风格的视觉效果,我们在代码中实现了动态调整图片大小和发光效果。adjustImageSizes 函数用于根据摄像机与图片之间的距离调整图片的缩放和发光强度。最近的图片会被放大并增强发光效果,而较远的图片则会缩小并减弱发光效果,这种效果能够增强场景的深度感和立体感。

请在此添加图片描述

构建一个赛博朋克风格的三维场景

使用 Three.js 构建一个赛博朋克风格的三维场景,并且在该场景中创建一种“气泡感”的动态效果。该效果能够根据相机的位置动态调整图片的大小和发光强度,给用户带来沉浸式的视觉体验。具体实现过程如下:

一、场景搭建

首先,我们利用 Three.js 构建基本的三维场景。在这个场景中,添加了相机、渲染器、光照以及一个赛博朋克风格的背景渐变。该背景渐变使用 CanvasTexture 创建,颜色范围从深紫色渐变到亮粉色,营造出一种赛博朋克特有的霓虹灯氛围。

javascript">// 创建赛博朋克风格的背景渐变
const gradientTexture = new THREE.CanvasTexture(createGradientCanvas()); // 创建渐变纹理
scene.background = gradientTexture; // 将背景设置为渐变纹理

函数 createGradientCanvas 用于创建渐变背景:

javascript">// 创建渐变背景
function createGradientCanvas() {const canvas = document.createElement('canvas'); // 创建一个 canvas 元素canvas.width = 512; // 设置 canvas 的宽度canvas.height = 512; // 设置 canvas 的高度const context = canvas.getContext('2d'); // 获取 2D 上下文const gradient = context.createLinearGradient(0, 0, 512, 512); // 创建线性渐变gradient.addColorStop(0, '#2c003e'); // 渐变开始颜色(深紫色)gradient.addColorStop(1, '#ff007d'); // 渐变结束颜色(亮粉色)// gradient.addColorStop(0, '#FFFFFF'); // 渐变开始颜色(深紫色)// gradient.addColorStop(1, '#EEE000'); // 渐变结束颜色(亮粉色)context.fillStyle = gradient; // 设置填充样式为渐变context.fillRect(0, 0, 512, 512); // 填充整个 canvasreturn canvas; // 返回创建的 canvas
}

二、添加光照

为了增强赛博朋克风格的灯光效果,场景中加入了环境光和方向光。环境光用来提供基础的整体照明,方向光则用来模拟从某个方向照射的光源,增加物体的立体感。

javascript">// 添加环境光
// const ambientLight = new THREE.AmbientLight(0x444444); // 创建环境光,颜色较暗
const ambientLight = new THREE.AmbientLight(0xffffff); // 创建环境光,颜色较暗
scene.add(ambientLight); // 将环境光添加到场景中// 添加方向光
// const directionalLight = new THREE.DirectionalLight(0x00ffff, 1); // 创建方向光,颜色为青色
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 创建方向光,颜色为青色
directionalLight.position.set(10, 10, 10).normalize(); // 设置光源的位置并归一化
scene.add(directionalLight); // 将方向光添加到场景中

三、加载图片并设置材质

场景的核心元素是均匀分布在球体表面的图片。这些图片作为网格(Mesh)添加到场景中,并且使用 CircleGeometry 创建圆形几何体来显示图片。

javascript">  const geometry = new THREE.CircleGeometry(circleRadius, 32); // 创建圆形几何体const texture = textureLoader.load(url); // 加载纹理// 设置纹理的过滤方式texture.minFilter = THREE.LinearMipMapLinearFilter;texture.magFilter = THREE.LinearFilter;// 设置各向异性过滤texture.anisotropy = renderer.capabilities.getMaxAnisotropy();// 设置纹理的颜色编码方式texture.encoding = THREE.sRGBEncoding;const material = new THREE.MeshStandardMaterial({map: texture,emissive: new THREE.Color(0x000000), // 默认不发光emissiveIntensity: 0, // 默认发光强度为0side: THREE.DoubleSide, // 双面渲染roughness: 0.2, // 低粗糙度metalness: 0.5, // 适度金属光泽});

为了保持视觉效果的一致性,配置了纹理的过滤方式(minFiltermagFilter),并设置了最大各向异性过滤(anisotropy),确保在不同视角和距离下纹理显示清晰。

四、相机控制与自适应窗口大小

使用 OrbitControls 实现相机的平滑控制,用户可以自由旋转、缩放和移动场景。同时,通过监听窗口的大小变化,自适应调整相机和渲染器的尺寸,确保场景始终保持最佳比例。

javascript">// 创建 OrbitControls 实例,用于相机的平滑控制
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 启用平滑阻尼效果
controls.dampingFactor = 0.25; // 设置阻尼因子
controls.enableZoom = true; // 启用缩放
controls.enableRotate = true; // 启用旋转// 自适应窗口大小
window.addEventListener('resize', () => {const width = window.innerWidth;const height = window.innerHeight;renderer.setSize(width, height); // 调整渲染器大小camera.aspect = width / height; // 调整相机的宽高比camera.updateProjectionMatrix(); // 更新相机投影矩阵
});

五、动态调整图片大小和发光效果

场景的核心是“气泡感”效果,它通过根据相机与图片之间的距离动态调整图片的大小和发光强度。最近的图片会逐渐变大并增强发光效果,而较远的图片会缩小,营造出一种动态的深度感。

实现该效果的关键是相机视锥体(Frustum)的使用。首先计算相机的视锥体,然后检查每个图片网格是否在视锥体内,最后根据距离调整图片的缩放和发光效果:

javascript">// 调整图片大小和气泡感效果
function adjustImageSizes() {let closestCircle = null; // 存储距离相机最近的图片let minDistance = Infinity; // 初始设置为无穷大// 找到距离相机最近且在视锥体内的图片circles.forEach((circle) => {const distance = camera.position.distanceTo(circle.position); // 计算相机到图片的距离// 检查图片是否在相机视锥体内const circleBoundingBox = new THREE.Box3().setFromObject(circle); // 获取图片的包围盒if (frustum.intersectsBox(circleBoundingBox)) { // 检查包围盒是否与视锥体相交if (distance < minDistance) { // 如果距离更近,更新最近的图片minDistance = distance;closestCircle = circle;}}});// 为每个图片设置缩放效果circles.forEach((circle) => {if (circle === closestCircle) {// 最近的图片放大到 1.8 倍,使用缓动效果circle.scale.lerp(new THREE.Vector3(1.8, 1.8, 1.8), 0.1);// circle.material.emissive = new THREE.Color('#ff007d'); // 设置发光颜色circle.material.emissiveIntensity = 0.5; // 设置发光强度} else {// 其他图片缩小到 0.5 倍,模拟气泡挤压感circle.scale.lerp(new THREE.Vector3(0.5, 0.5, 0.5), 0.1);circle.material.emissive = new THREE.Color('#000000'); // 无发光效果circle.material.emissiveIntensity = 0; // 发光强度为0}});
}

该函数通过缓动(lerp)效果平滑地调整图片大小,保证视觉效果的连贯性。最靠近相机的图片会被放大到 1.8 倍,并且增强其发光效果,而其他图片则逐渐缩小,模拟出类似气泡挤压的效果。

总结

通过利用 Three.js 的丰富功能,我们能够轻松实现一个具有赛博朋克风格的动态三维场景。本文重点介绍了如何通过材质、纹理和光照的优化,来提升场景的视觉效果。同时,基于相机位置的动态调整图片大小和发光效果,为场景添加了更具沉浸感的气泡效果。

无论是用于游戏开发、虚拟现实项目,还是网页三维可视化,Three.js 都是一个强大且灵活的工具。


http://www.ppmy.cn/embedded/124367.html

相关文章

【微服务】组件、基础工程构建(day2)

组件 服务注册和发现 微服务模块中&#xff0c;一般是以集群的方式进行部署的&#xff0c;如果我们调用的时候以硬编码的方式&#xff0c;那么当服务出现问题、服务扩缩容等就需要对代码进行修改&#xff0c;这是非常不好的。所以微服务模块中就出现了服务注册和发现组件&…

《大规模语言模型从理论到实践》第一轮学习--第四章分布式训练

基础知识 5分钟看懂电脑硬件配置 - 知乎 (zhihu.com) 显存 定义&#xff1a;显存是显卡上的专用高速缓存&#xff0c;用于存储图形处理器&#xff08;GPU&#xff09;在处理图像和视频数据时所需的临时数据。 功能&#xff1a;显存的主要作用是提供GPU快速访问的数据存储&a…

[3.4]【机器人运动学MATLAB实战分析】PUMA560机器人逆运动学MATLAB计算

PUMA560是六自由度关节型机器人,其6个关节都是转动副,属于6R型操作臂。各连杆坐标系如图1,连杆参数如表1所示。 图1 PUMA560机器人的各连杆坐标系 表1 PUMA560机器人的连杆参数 用代数法对其进行运动学反解。具体步骤如下: 1、求θ1 PMUMA56

一文看懂计算机中的大小端(Endianess)

文章目录 前言一、什么是大小端二、如何判断大小端三、大小端的转换3.1 使用标准库函数3.2 手动实现大小端转换 前言 本文主要探讨计算机中大小端的相关概念以及如何进行大小端的判断和转换等。 一、什么是大小端 大小端&#xff08;Endianess&#xff09;是指计算机系统在存…

我的第一个AI视频(通义万相)

背景需求&#xff1a; 今天试试通义万相的AI视频功能——免费5秒&#xff0c; 一、文生视频 关键词&#xff1a;一只可爱的小猫咪穿着厨师的服装正在厨房里烤鱼&#xff0c;流口水 大约生成了10分钟&#xff0c;视频是5秒、消耗灵感值5分 20241007星火讯飞视频猫厨师烤鱼 猫…

项目最后优化(十五)

一. wifi连接太慢 void Serial::wifi_Connect(int *flag,const QString &command) {// 创建 QProcess 对象QProcess *process new QProcess(this); // this 是 Serial 类的实例&#xff0c;继承自 QObject// 设置进程的可执行文件// process->setProgram(command);//…

view deign 和 vue2 合并单元格的方法

1.vue版本和view design 版本 {"vue": "^2.6.11","view-design": "^4.7.0", }2.Data中定义数据 spanArr: [], // 某一列下需要合并的行数 pos: 0// 索引// 注意点&#xff1a; 在获取列表前&#xff0c;需要重置 this.spanArr [] 注…

Mysql中的事务

目录&#xff1a; 一&#xff1a;事务的ACID特性及为什么要使用事务 二&#xff1a;如何使用事务 三&#xff1a;事务的隔离级别 一&#xff1a;事务的ACID特性及为什么要使用事务 &#xff1a; 1.事务的ACID特性&#xff1a; 事务的ACID特性指的是 Atomicity (原子性)&#…