Three.js 实战【2】—— 船模型海上场景渲染

停止了好久没有更新three这方面的文章了,从上两年还是vue2,一下子都换到vue3了,下面这些three都是基于vue3来进行开发的哈,先看一下这篇文章实现的效果哈。其中关于模型什么的资源都放在Git上了

在这里插入图片描述

初始化场景

安装three就直接通过npm i three 安装到一个vue3项目当中即可。其中很多的内容可以参考该文:单击前往

<script lang="ts" setup>
import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';// 创建场景、创建相机
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.set(1, 1, 1);
scene.add(camera);// 环境光
const ambientLight = new THREE.AmbientLight('white', 1);
scene.add(ambientLight);const light = new THREE.DirectionalLight(0xffffff, 3);
scene.add(light);const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// xyz辅助坐标系
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);// 渲染
const render = () => {renderer.render(scene, camera);requestAnimationFrame(render);
};onMounted(() => {document.getElementById('home')?.appendChild(renderer.domElement);render();
});
</script><template><div id="home" class="w-full h-full"></div>
</template>

这里是vue3+ts搭建的项目,如果引入的three标红的话可以在根目录下的env.d.ts文件当中添加:

declare module 'three'
declare module 'three/examples/jsm/objects/Water2';
declare module 'three/examples/jsm/controls/OrbitControls';
// .... 还有什么别的就继续往里面加

初始化场景的效果:
在这里插入图片描述

加载模型

首先是获取模型的地址,可以在sketchfab获取一下glb或者gltf文件格式的模型。通过GLTFLoader加载glb模型,glb模型和gltf模型还是有点区别的,glb模型在响应之后需要通过gltf.scene.children[0]获取的才是模型。因为模型展示的太大了和朝向也不是理想的,这里对模型也进行了一些处理

  • 缩放scale
  • 旋转rotation
let model: {scale: { set: (arg0: number, arg1: number, arg2: number) => void; };rotation: { z: number; };traverse: (arg0: (item: { material: { name: string; }; }) => void) => void;position: { z: number; };
};
const addShip = () => {const gltfLoader = new GLTFLoader();gltfLoader.load('./src/assets/glb/pirate_ship.glb', (gltf: any) => {model = gltf.scene.children[0];const scale = 0.001;model.scale.set(scale, scale, scale);model.rotation.z = Math.PI;scene.add(model);});
};

在这里插入图片描述

渲染场景贴图

因为没有设置场景的背景,这个时候都是黑色的,这个可以直接加在一张HDR图片作为整个场景的外围贴图,这个和上一篇文章的加载HDR是一样的,就不过多赘述了。

纹理常量:映射模式

  • UVMapping 是默认值,纹理使用网格的坐标来进行映射
  • CubeReflectionMapping 和 CubeRefractionMapping 用于 CubeTexture —— 由6个纹理组合而成,每个纹理都是立方体的一个面。
  • EquirectangularReflectionMapping 和 EquirectangularRefractionMapping 用于等距圆柱投影的环境贴图,也被叫做经纬线映射贴图。等距圆柱投影贴图表示沿着其水平中线360°的视角,以及沿着其垂直轴向180°的视角。贴图顶部和底部的边缘分别对应于它所映射的球体的北极和南极。
import {RGBELoader} from 'three/examples/jsm/loaders/RGBELoader';const rgbLoader = new RGBELoader();const addHdr = () => {rgbLoader.loadAsync('./src/assets/hdr/sea_2k.hdr').then((texture: { mapping: any; }) => {// 图像将如何应用到物体(对象)上。默认值是THREE.UVMapping对象类型, 即UV坐标将被用于纹理映射。texture.mapping = THREE.EquirectangularReflectionMapping;scene.background = texture;scene.environment = texture;});
};

在这里插入图片描述

光照增强

虽然外围场景也加上了,但是船体还是黑乎乎的一片,原因在于前面设置的光照强度不够,将强度拉上来就可以看到船的颜色细节都渲染出来了。

const ambientLight = new THREE.AmbientLight('white', 50);
ambientLight.position.set(10, 10, 10);
scene.add(ambientLight);const light = new THREE.DirectionalLight('#fff', 50);
light.position.set(10, 10, 10);
scene.add(light);

船体模型纹理

有些时候我们想给模型设置一下别的纹理上去,那这个船体的纹理怎么设置呢?

全纹理

直接给model模型的material设置一个纹理,通过纹理加载器加载一张图片,并且设置其为EquirectangularRefractionMapping

网格材质 MeshPhongMaterial:该材质使用非物理的Blinn-Phong模型来计算反射率。 可以模拟具有镜面高光的光泽表面(例如涂漆木材)

  • envMap:环境贴图
  • refractionRatio:空气的折射率(IOR)(约为1)除以材质的折射率。它与环境映射模式CubeRefractionMapping和 EquirectangularRefractionMapping一起使用。
  • reflectivity:环境贴图对表面的影响程度
  • wireframe:将几何体渲染为线框
const addTexture = () => {const textureLoader = new THREE.TextureLoader().load('./src/assets/image/bg.jpg');textureLoader.mapping = THREE.EquirectangularRefractionMapping;return textureLoader;
};
model.material = new THREE.MeshPhongMaterial({color: 0xffffff,envMap: addTexture(),refractionRatio: 0.75,reflectivity: 0.99
});

分块纹理

在model模型当中还可以通过traverse方法去遍历对象或场景中的所有后代对象。拿到item之后我们通常会通过name属性去区分模型的块,比方说现在加载的模型的name取值是:Main、Sail、Mat、Polygon_Reduction_1__0、material这些,对应到模型就是主体、船帆、甲板、发动机、绳索,这里直接添加简单的颜色纹理上去看一下效果

// 加载模型之后通过该方法给模型当中不同的块进行材质的修改model.traverse((item: { material: { name: string; }; }) => {// Mat Sail Main Polygon_Reduction_1__0 materialconst name = item.material?.name || '';if (name.includes('Main')) {item.material = colorMaterial('#e7a23f');} else if (name.includes('Sail')) {item.material = colorMaterial('#fff');} else if (name.includes('Mat')) {item.material = colorMaterial('#826b48');} else if (name.includes('Polygon_Reduction_1__0')) {item.material = colorMaterial('#f40');} else if (name.includes('material')) {item.material = colorMaterial('#000');}
});const colorMaterial = (color: string) => {return new THREE.MeshLambertMaterial({color});
};

在这里插入图片描述

加载水面(Water&Water2)

Water

  • 首先是导入Water,在three当中有一个Water和一个Water2,需要注意区分一下

  • 平面缓冲几何体(PlaneGeometry)用来作为水面的载体

  • 创建water对象,其中属性当中主要是对纹理进行相关配置,主要是wrapS和wrapT

  • wrapS这个值定义了纹理贴图在水平方向上将如何包裹,默认值是THREE.ClampToEdgeWrapping,即纹理边缘将被推到外部边缘的纹素。 其它的两个选项分别是THREE.RepeatWrapping和THREE.MirroredRepeatWrapping。

    • ClampToEdgeWrapping 纹理中的最后一个像素将延伸到网格的边缘
    • RepeatWrapping 纹理将简单地重复到无穷大
    • MirroredRepeatWrapping 纹理将重复到无穷大,在每次重复时将进行镜像
  • wrapT这个值定义了纹理贴图在垂直方向上将如何包裹

  • 在最后需要通过water.material.uniforms[‘time’].value += 1.0 / 60.0启动水的运动动画

import {Water} from 'three/examples/jsm/objects/Water';
let water: any;
const addWater = () => {// 创建水面const waterGeometry = new THREE.PlaneGeometry(10000, 10000);water = new Water(waterGeometry,{textureWidth: 512,textureHeight: 512,waterNormals: new THREE.TextureLoader().load('./src/Water.jpg', (texture: any) => {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;}),sunDirection: new THREE.Vector3(),sunColor: 0xffffff,waterColor: 0xffffff,distortionScale: 3.7});water.rotation.x = -Math.PI / 2;water.position.y = -0.4;scene.add(water);
};const render = () => {renderer.render(scene, camera);water.material.uniforms['time'].value += 1.0 / 60.0;requestAnimationFrame(render);
};

Water2

在使用water2需要注意的是normalMap0和normalMap1配置,没有配的话会报错。这是因为

源码中是:const normalMap0 = options.normalMap0 || textureLoader.load( ‘textures/water/Water_1_M_Normal.jpg’ );
但是three源码并没有这个两个纹理图片。所以可以通过手动给这两个属性赋值。
另一种方式是,直接将这两个图片放在:public/textures/water目录下,因为public下的文件是不会被编译的,这样也能找到这两个图片了。

import {Water} from 'three/examples/jsm/objects/Water2';
const addWater = () => {// 创建水面const waterGeometry = new THREE.CircleBufferGeometry(300, 64);const water = new Water(waterGeometry, {textureWidth: 1024,textureHeight: 1024,// color: 0x0080ff,color: '#fff',flowDirection: new THREE.Vector2(1, 1),scale: 1,reflectivity: 0.3,normalMap0: new THREE.TextureLoader().load('./src/Water.jpg'),normalMap1: new THREE.TextureLoader().load('./src/Water.jpg')});water.rotation.x = -Math.PI / 2;water.position.y = -0.4;scene.add(water);
};

在这里插入图片描述

视口角度限制

在实际开发过程当中会发现,我们不想整个视口是可以360度和无论多远多近都能看到的,视口应该在一个合理的范围当中。这时需要调整一下controls。

OrbitControls (轨道控制器)可以使得相机围绕目标进行轨道运动。

  • enableDamping 将其设置为true以启用阻尼(惯性),这将给控制器带来重量感。
  • maxPolarAngle 你能够垂直旋转的角度的上限,范围是0到Math.PI,其默认值为Math.PI。
  • minDistance 你能够将相机向内移动多少,默认为0。
  • maxDistance 你能够将相机向外移动多少,和minDistance仅适用于PerspectiveCamera 透视相机
  • update 更新控制器。必须在摄像机的变换发生任何手动改变后调用,
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.maxPolarAngle = Math.PI * 0.45;
controls.minDistance = 5.0;
controls.maxDistance = 15.0;
controls.update();

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

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

相关文章

springboot系列十: 自定义转换器,处理JSON,内容协商

文章目录 自定义转换器基本介绍应用实例查看源码注意事项和细节 处理JSON需求说明应用实例 内容协商基本介绍应用实例debug源码优先返回xml注意事项和细节 ⬅️ 上一篇: springboot系列九: 接收参数相关注解 &#x1f389; 欢迎来到 springboot系列十: 自定义转换器&#xff0c…

ssh远程登录另一台linux电脑

大部分的博客内容所说的安装好ssh服务后&#xff0c;terminal输入 ssh -p port_number clientnameserver_ip 之后输入密码等等就可以登上别人的电脑 但是这是有一个前提的&#xff0c;就是这两台电脑要在同一个局域网下面。 如果很远呢&#xff1f; 远到不在同一个网下面怎么办…

1.JavaWeb开发简介(Tomcat安装使用+Servlet简介)

文章目录 一.web开发简介1.概念:2.特点:3.常用技术:4.服务架构5.web应用开发模式6.HTTP协议1)概念:2)HTTP最基本的过程是:3)IP/域名4)HTTP协议请求方式 7.JavaWeb的相关技术8.Java Web服务器 二、安装配置Tomcat1.简介2.Tomcat目录结构 三.Servlet的入门应用1.使用步骤2.使用注…

ABAP使用SQL直接更新数据库与使用IN UPDATE TASK的区别

1. 背景 刚接触ABAP的小伙伴常常会有这样的疑问&#xff0c;为什么不直接使用Open SQL直接更新数据库&#xff0c;而要把对DB的操作封装到IN UPDATE TASK中呢&#xff1f; 对于这个问题&#xff0c;比较常见的解释是&#xff0c;IN UPDATE TASK的方式会保证数据更新的一致性。…

接口开发:Orcal数据库的批量修改sql

场景&#xff1a;在日常的CURD中一定会用到批量修改。在我们的项目中&#xff0c;使用的数据库是Orcal&#xff0c;由于之前基本都是使用Mysql的&#xff0c;使用的sql语句也基本都是用mysql的。但是在这次的接口编写时用mysql的批量修改出了问题&#xff0c;刚开始我还以为是写…

如何每天不用动手就可以自动加人

只需要设置一次&#xff0c;批量导入客户号码或是微信号并设置好添加规则&#xff0c;系统就会自动进行添加。

Elastic 线下 Meetup 将于 2024 年 7 月 27 号在深圳举办

2024 Elastic Meetup 深圳站活动&#xff0c;由 Elastic、腾讯、新智锦绣联合举办&#xff0c;现诚邀广大技术爱好者及开发者参加。 时间地点 2024年 7 月 27 日 13:30-18:00 活动地点 中国深圳 南山区海天二路 33 号腾讯滨海大厦 北塔 3 楼多功能厅 ​ 活动流程 14:00-15…

HTTP请求走私漏洞原理与利用手段分析

文章目录 前言Http请求走私1.1 漏洞诞生场景1.2 漏洞基本原理1.3 HTTP1.1与2.0 请求走私分类2.1 CL.TE类型实例2.2 TE.CL类型实例2.3 TE.TE混淆实例2.4 漏洞检测工具&#xff1f; 请求走私利用3.1 绕过前端安全控制3.2 揭示前端请求重写3.3 捕获他人请求内容3.4 走私构造反射XS…

从数据湖到湖仓一体:统一数据架构演进之路

文章目录 一、前言二、什么是湖仓一体&#xff1f;起源概述 三、为什么要构建湖仓一体&#xff1f;1. 成本角度2. 技术角度 四、湖仓一体实践过程阶段一&#xff1a;摸索阶段(仓、湖并行建设)阶段二&#xff1a;发展阶段方式一、湖上建仓(湖在下、仓在上)方式二&#xff1a;仓外…

MySQL运维实战之Clone插件(10.1)使用Clone插件

作者&#xff1a;俊达 clone插件介绍 mysql 8.0.17版本引入了clone插件。使用clone插件可以对本地l或远程的mysql实例进行clone操作。clone插件会拷贝innodb存储引擎表&#xff0c;clone得到的是原数据库的一个一致性的快照&#xff0c;可以使用该快照数据来启动新的实例。cl…

SpringMVC注解全解析:构建高效Web应用的终极指南 (下)

一. 引言 在上篇文章中&#xff0c;我们介绍了几个重要的SpringMVC注解&#xff1a; SpringBootApplication&#xff1a;Spring Boot项目的启动类注解。RequestMapping&#xff1a;用于映射URL到控制器类或方法&#xff0c;支持多种请求方式。RequestParam&#xff1a;用于绑…

UniVue@v1.5.0版本发布:里程碑版本

前言 以后使用UniVue都推荐使用1.5.0以后的版本&#xff0c;这个版本之后&#xff0c;更新的速度将会放缓。 希望这个框架能够切实的帮助大家更好的开发游戏&#xff0c;做出一款好游戏&#xff01;本开源项目采用的开源协议为MIT协议&#xff0c;完全开源化&#xff0c;以后也…

基于Python+Django+MySQL的心理咨询预约系统

心理咨询预约系统 DjangoMySQL 基于PythonDjangoMySQL的心理咨询预约系统 项目主要依赖Django3.2&#xff0c;MySQL 支持随机验证码生成与登录验证 简介 基于PythonDjangoMySQL的心理咨询预约系统通过连接数据库获取数据&#xff0c;登录新增随机数字验证码验证。具体可以看…

【机器学习】机器学习与图像分类的融合应用与性能优化新探索

文章目录 引言第一章&#xff1a;机器学习在图像分类中的应用1.1 数据预处理1.1.1 数据清洗1.1.2 数据归一化1.1.3 数据增强 1.2 模型选择1.2.1 卷积神经网络1.2.2 迁移学习1.2.3 混合模型 1.3 模型训练1.3.1 梯度下降1.3.2 随机梯度下降1.3.3 Adam优化器 1.4 模型评估与性能优…

Qt支持LG高级汽车内容平台

Qt Group与LG 电子&#xff08;简称LG&#xff09;正携手合作&#xff0c;将Qt软件框架嵌入其基于 webOS的ACPLG车载娱乐平台&#xff0c;用于应用程序开发。该合作旨在让原始设备制造商&#xff08;OEM&#xff09;的开发者和设计师能为汽车创建更具创新性的沉浸式汽车内容流媒…

【深度学习】inpaint图像中的alpha混合图的边缘处理

比如原图是&#xff1a; 红圈内就是文字水印&#xff0c;经过inpaint后得到图和原图混合&#xff0c;如何处理边界呢&#xff0c;这个代码可以干这事&#xff1a; 越是中心就直接用inpaint图&#xff0c;否则就用原图&#xff0c;这样进行alpha混合。 import numpy as np i…

uniapp:国家、省市区,4级联动

使用uview的Select 列选择器 选择器完成国家&#xff0c;省市区&#xff0c;4级联动 要求后台数据格式&#xff1a; list: [{label: 中国,value: 1,children: [{label: 河南省,value: 2,children: [{label: 郑州市,value: 3,children: [{label: 中原区,value: 4},{label: 郑东…

Re:从零开始的C++世界——类和对象(下)

文章目录 前言1.再谈构造函数&#x1f34e;构造函数体赋值&#x1f34e;初始化列表&#x1f34e;特性&#x1f34c;特性一&#x1f34c;特性二&#x1f34c;特性三&#x1f34c;特性四&#x1f34c;特性五 &#x1f34e;explicit 关键字 2.static成员&#x1f34e;概念&#x1…

2.4G收发芯片XL2412P,集成单片机 ,通信距离可达110米

XL2412P芯片是一款高性能低功耗的SOC集成无线收发芯片&#xff0c;由RF芯片和32位M0核MCU集成&#xff0c;工作在2.400~2.483GHz世界通用ISM频段。XL2412P为SSOP16封装&#xff0c;正常工作电压范围&#xff1a;1.7~3.6V&#xff0c;正常工作温度范围-40~85℃。XL2412P发射输出…

MQTT服务端EMQX开源版安装和客户端MQTTX介绍

一、EMQX是什么 EMQX 是一款开源的大规模分布式 MQTT 消息服务器&#xff0c;功能丰富&#xff0c;专为物联网和实时通信应用而设计。EMQX 5.0 单集群支持 MQTT 并发连接数高达 1 亿条&#xff0c;单服务器的传输与处理吞吐量可达每秒百万级 MQTT 消息&#xff0c;同时保证毫秒…