用three.js做一个3D汉诺塔游戏(下)

为桌台添加材质纹理

为物体添加适当的材质纹理,可以使其视觉效果产生质的飞跃。接下来,我们将为桌台添加一种木质纹理,用到的纹理贴图来自Pixabay.com。

我们使用 TextureLoader 来加载纹理贴图,其 load 方法第1个参数为贴图的 URL 字符串,该方法返回一个纹理对象,可直接赋值给材质对象的颜色贴图属性 map。代码实现如下:

class Table {constructor({ width, height, depth }) {const geometry = new THREE.BoxGeometry(width, height, depth);// 纹理贴图const url = 'https://cdn.pixabay.com/photo/2016/12/26/13/47/fresno-1932211_1280.jpg';const material = new THREE.MeshLambertMaterial({ color: '#cccca6',map: new THREE.TextureLoader().load(url)  // 纹理贴图});return new THREE.Mesh(geometry, material);}
}

然而,我们发现这样做并不完美:由于纹理贴图存在网络加载延时,所以在贴图加载完成前,桌台始终是黑色的,只有贴图加载完成后,桌台才一瞬间有了外观。如下图所示:

对此,我们需要在技术上做出一些改进,来解决纹理贴图加载前后变化的突兀感。这里有2种改进方案:

  1. 预加载,等纹理贴图加载完成后,再生成带纹理效果的桌台;
  2. 渐进式加载,桌台先显示默认颜色,等纹理贴图加载完成后,再附加纹理效果。

这里我们选择方案2,因为方案2不会阻塞桌台的渲染,有着更好的用户体验。渐进式加载的原理就是在贴图加载完成后,标记材质对象的 needsUpdate 属性为 true,这样渲染器会在下一个渲染循环动态更新材质的纹理。核心代码如下:

const material = new THREE.MeshLambertMaterial({ color: '#cccca6' });// 动态更新材质纹理
new THREE.TextureLoader().load(url, (texture) => {material.needsUpdate = true;material.map = texture;
});

加载效果如下图所示:

优化光照效果

在 three.js 中,反光材质的物体表面会因为光照的不同而呈现出不同的明暗效果,其中光源的强弱、照射面和光线夹角等参数都会对物体的渲染效果产生影响。目前我们的场景效果并不理想:柱杆看上去灰蒙蒙的,盘子则是透出一股廉价的塑料味,都缺乏真实感。正所谓,效果不够,光照来凑,我们来调整光源参数,优化光照效果,让场景更加自然、真实。

让我们先对 Lights 类进行改造,新增一个距离参数,作为调整光源位置的基准值。我们将桌台长度、柱杆高度和桌台宽度分别作为光源在 x、y、z 方向上的位置基准值进行传递,以便于更加精确地设置光源位置,达到更好的照明效果。

class Lights {constructor({ directionX, directionY, directionZ }) {...}
}const presenter = {init() {...const lights = new Lights({directionX: model.tableSize.width,directionY: model.pillarSize.height,directionZ: model.tableSize.depth});}...
};

接下来,我们需要对之前已有的平行光源位置进行调整。为了更直观地调试光照效果,我们可以添加 DirectionalLightHelper 来帮助我们更好地观察光源位置平面和光照方向。

class Lights {constructor({ directionX, directionY, directionZ }) {const ambientLight = new THREE.AmbientLight('#fff', 1);  // 环境光const directLight = new THREE.DirectionalLight('#fff', 3);  // 平行光directLight.position.set(-directionX / 3, directionY * 4, directionZ * 1.5);const directLightHelper = new THREE.DirectionalLightHelper(directLight, 1, '#f00');return [ambientLight, directLight, directLightHelper];}
}

经过这一步平行光源的位置调整,我们看到柱杆和盘子已经变得光滑透亮。(下图中的红线为平行光源辅助观察线)

最后我们再添加一个米黄色的聚光灯光源,中和下场景的“高冷”基调。

class Lights {constructor(...) {...const spotLight = new THREE.SpotLight('#fdf4d5');spotLight.position.set(5, directionY * 4, 0);spotLight.angle = Math.PI / 2;  // 光线照射范围角度spotLight.power = 2000;  // 光源功率(流明)const spotLightHelper = new THREE.SpotLightHelper(spotLight, '#00f');return [ambientLight, directLight, directLightHelper, spotLight, spotLightHelper];}
}

完成后的效果如下图所示:(下图中的蓝线为聚光灯光源辅助观察线)

开启阴影效果

伴随着光源一起的自然是阴影,开启阴影能显著增强物体的立体效果。在现实世界中,阴影的产生需要光源、被照射物体和显示阴影的地方,这三者缺一不可。

在 three.js 中,出于性能考虑,实时渲染的阴影默认是关闭的,如果想要实现阴影效果,需要进行一番设置。与现实世界阴影的生成相似,这些设置都与光源、被照射物和阴影显示物有关,下面我们来逐一进行设置。

  1. 渲染器 开启阴影渲染支持

    const rendererView = {init(...) {...this.renderer.shadowMap.enabled = true;this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;},...
    };
    

    THREE.PCFSoftShadowMap 是 Three.js 中的一种阴影映射技术,它使用了 Percentage Closer Filtering (PCF) 和 Soft Shadows 技术来实现更加真实的阴影效果。PCF 技术可以减少阴影的锯齿感,Soft Shadows 技术可以让阴影边缘更加柔和。

  2. 光源 开启阴影投射,使被照射物体产生阴影

    directLight.castShadow = true;  // 为平行光源开启阴影投射
    
  3. 调整光源的 阴影相机 参数,控制阴影的渲染范围到合适大小

    超出阴影相机范围的阴影不会被渲染,所以要将阴影相机的范围扩大到能完整包含柱杆和盘子。使用 CameraHelper 辅助对象可以帮助我们更好的观测阴影相机的视野范围。

    directLight.shadow.camera.left = -directionX;
    directLight.shadow.camera.right = directionX;
    directLight.shadow.camera.top = directionZ;
    directLight.shadow.camera.bottom = -directionZ;const shadowCamera = new THREE.CameraHelper(directLight.shadow.camera);
    
  4. 允许 被照射物体 产生阴影

    这里设置允许柱杆和盘子产生阴影,并且允许其他物体产生的阴影可以投射到它们表面(接收阴影)。需要注意,castShadow 和 receiveShadow 要设置到 Mesh 对象上,不能设置到 Group 上。

    /* 柱杆 */
    class Pillar {constructor(...) {...const body = new THREE.Mesh(geometry, material);body.castShadow = true;  // 允许产生阴影body.receiveShadow = true;  // 允许接收阴影...},...
    }/* 盘子阴影设置同上 */
    clas

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/803614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux服务器上搭建深度学习环境(安装anaconda、创建虚拟环境、安装pytorch)

Linux服务器的搭配 Linux服务器上安装anaconda创建虚拟环境linux上安装pytorchxshell连接服务器 Linux服务器上安装anaconda 链接 创建虚拟环境 参考教程:此处 linux上安装pytorch 链接 xshell连接服务器 链接

科技动态人工智能应用太空探索生物科技

根据最新的科技资讯,以下是一些值得关注的科技动态: 人工智能领域 智能体热潮 :随着大模型的研发热潮,AI智能体的发展迅速,它们被用作认知核心,具备强大的学习和迁移能力。智能体的架构和交互方式也在不断进…

python课后习题三

题目&#xff1a; 解题过程&#xff1a; 模式A&#xff1a; num int(input("&#xff08;模式A&#xff09;输入数字&#xff1a;")) for i in range(num): for j in range(num): if j < i 1: …

MQ的延迟队列

1&#xff0c;场景 1.定时发布文章 2.秒杀之后&#xff0c;给30分钟时间进行支付&#xff0c;如果30分钟后&#xff0c;没有支付&#xff0c;订单取消。 3.预约餐厅&#xff0c;提前半个小时发短信通知用户。 A -> 13:00 17:00 16:30 延迟时间&#xff1a; 7*30 * 60 * …

Excel·VBA考勤打卡记录整理

看到一个帖子《excel吧-考勤一天四次打卡&#xff0c;快速找出缺卡》&#xff0c;每个人每天有4次打卡记录&#xff0c;需要整理出所有缺少的打卡记录 与之前的文章《ExcelVBA考勤打卡记录统计结果》结果形式类似 与之前的文章《ExcelVBA考勤打卡记录数据整理》查找上下班打卡…

Linux、Docker、Brew、Nginx常用命令

Linux、Docker、Brew、Nginx常用命令 Linuxvi编辑器文件操作文件夹操作磁盘操作 DockerBrewNginx参考 Linux vi编辑器 Vi有三种模式。命令模式、输入模式、尾行模式&#xff0c;简单的关系如下&#xff1a; i -- 切换到输入模式&#xff0c;在光标当前位置开始输入文本。&a…

【go从入门到精通】初识struct结构体

作者简介&#xff1a; 高科&#xff0c;先后在 IBM PlatformComputing从事网格计算&#xff0c;淘米网&#xff0c;网易从事游戏服务器开发&#xff0c;拥有丰富的C&#xff0c;go等语言开发经验&#xff0c;mysql&#xff0c;mongo&#xff0c;redis等数据库&#xff0c;设计模…

虚拟网络设备性能优化

在现代网络架构中&#xff0c;虚拟网络设备扮演着越来越重要的角色&#x1f310;&#xff0c;特别是在云计算☁️和容器化技术&#x1f4e6;广泛应用的背景下。虚拟网络设备如虚拟以太网设备&#xff08;veth&#xff09;、虚拟交换机&#xff08;vSwitch&#xff09;、和虚拟路…

适用于 Mac 的 10 大数据恢复工具,具有优点、缺点

数据丢失很常见&#xff0c;并且可能由于许多不同的原因而发生。这种情况在我和我们团队的其他成员身上发生过很多次&#xff0c;即使我们格外小心我们的个人存储设备。 幸运的是&#xff0c;数据恢复软件在大多数情况下都可以工作。但是&#xff0c;由于数据丢失场景彼此之间…

【CKA模拟题】边车容器Shared-Volume的具体用法

Useful Resources: Persistent Volumes Claim , Pod to Use a PV 题干 For this question, please set this context (In exam, diff cluster name) kubectl config use-context kubernetes-adminkubernetes An existing nginx pod, my-pod-cka and Persistent Volume Claim…

macOS制作C/C++ app

C/C制作macOS .app 一、 .app APP其实是一个文件夹结构&#xff0c;只不过mac的界面中让它看起来像一个单独的文件。 在shell终端或者右键查看包结构即可看到APP的目录结构。 通常的app目录结构如下&#xff1a; _CodeSignature, CodeResources 一般为Mac APP Store上架程序…

【aws】在DBeaver上用终端节点连接Redshift

碎碎念 最近想要尝试redshift的一个叫做重新定位的功能&#xff0c;重新定位触发之后会停止当前的集群&#xff0c;转而在同一个区域的另一个可用区中启动一个一样的集群&#xff0c;这个过程视情况会花上10到60分钟不等。 但是目前项目中连接到redshift用的是私有ip&#xf…

保研线性代数复习4

一.范数&#xff08;Norms&#xff09; 1.什么是范数&#xff1f; 范数是一个向量空间V的函数&#xff0c;每一个属于向量空间V的向量x都匹配了一个实数&#xff08;它的长度&#xff09;&#xff1a; 2.范数的性质&#xff1f; 齐次性&#xff1a; 正定性&#xff1a; 三…

大创项目推荐 深度学习 机器视觉 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …

【Python】基础(专版提升1)

Python基础 1. 导学1.1 学习理念1.1.1 弱语法&#xff0c;重本质1.1.2 是技术&#xff0c;更艺术 1.2 学习方法1.2.1 当天知识必须理解 2. Python 简介2.1 计算机基础结构2.1.1 硬件2.1.2 软件 2.2 基础知识2.2.1 Python介绍2.2.1.1定义2.2.1.2优势2.2.1.3从业岗位 2.2.2 Pytho…

openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警

文章目录 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 Plan Hint的结果会体现在计划的变化上&#xff0c;可以通过explain来查看变化。 …

负荷预测 | Matlab基于TCN-GRU-Attention单输入单输出时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于TCN-GRU-Attention单输入单输出时间序列多步预测&#xff1b; 2.单变量时间序列数据集&#xff0c;采用前12个时刻预测未来96个时刻的数据&#xff1b; 3.excel数据方便替换&#xff0c;运行环境matlab20…

[法规规划|数据概念]数据要素市场三月速递

“ 代表关注&#xff0c;市场活跃&#xff0c;发展迅速” 01—听听两会代表怎么说 在2024年的全国两会期间&#xff0c;数据要素作为新型的生产要素受到广泛关注&#xff0c;众多代表围绕数据要素市场化、立法、安全监管、人才培养及基础设施建设等方面&#xff0c;积极建言献策…

P8602 [蓝桥杯 2013 省 A] 大臣的旅费【树的直径】

P8602 [蓝桥杯 2013 省 A] 大臣的旅费 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<iostream> #include <algorithm> #include <vector> using namespace std; #define int long long const int N5e5100; int n; int res0; typedef pair<int,…

植物大战僵尸Python版,附带源码注解

目录 一、实现功能 二、安装环境要求 三、如何开始游戏 四、怎么玩 五、演示 六、部分源码注释 6.1main.py 6.2map.py 6.3Menubar.py 七、自定义 7.1plant.json 7.2zombie.json 一、实现功能 实施植物&#xff1a;向日葵、豌豆射手、壁桃、雪豆射手、樱桃炸弹、三…