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://xiahunao.cn/news/3248986.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

GuLi商城-商品服务-API-品牌管理-品牌分类关联与级联更新

先配置mybatis分页&#xff1a; 品牌管理增加模糊查询&#xff1a; 品牌管理关联分类&#xff1a; 一个品牌可以有多个分类 一个分类也可以有多个品牌 多对多的关系&#xff0c;用中间表 涉及的类&#xff1a; 方法都比较简单&#xff0c;就不贴代码了

000007 - HDFS DataNode

HDFS DataNode 1. DataNode工作机制2. DataNode的数据完整性3. 掉线时限参数设置 1. DataNode工作机制 &#xff08;1&#xff09;一个数据块在 DataNode 上以文件形式存储在磁盘上&#xff0c;包括两个文件&#xff0c;一个是数据本身&#xff0c;一个是元数据包括数据块的长度…

【C++】类与对象的学习(中)

目录 一、默认成员函数&#xff1a; 二、构造函数&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 三、析构函数&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 四、拷贝构造&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 五、运算符的重载&…

夏令营入门组day5

目录 一. 城市距离 二. 史莱姆 一. 城市距离 &#xff08;1&#xff09;思路 每次询问&#xff0c;对于每一个点都判断与下一个点是否为临近点会超时&#xff0c;因此预处理&#xff0c;预先判断每一个点的临近点&#xff0c;然后将花费存入前缀和数组&#xff0c;这样在每次询…

对redis进行深入学习

目录 1. 什么是redis&#xff1f;1.1 为什么使用redis作为缓存&#xff1f;1.1.0 数据库&#xff08;MySQL&#xff09;与 redis1. 存储介质不同&#xff08;408选手应该都懂hh&#xff09;2. 数据结构优化3. I/O模型差异4. CPU缓存友好性5. 单线程与多线程差异6. 持久化与缓存…

哈尔滨网站建设注意哪些问题

在进行哈尔滨网站建设时&#xff0c;需要注意以下几个问题&#xff1a; 首先&#xff0c;要明确网站的定位和目标。网站建设的首要任务是明确网站的定位和目标&#xff0c;确定网站所要传达的信息和服务内容&#xff0c;以及面向的目标用户群体。哈尔滨作为一个具有浓厚地域特色…

Linux脚本:如何编写bash脚本统计多个相关进程的CPU占用率,以此统计系统中指定多进程的总的CPU使用率

目录 一、需求 二、分析 三、脚本示例 1、创建脚本 2、编写脚本 3、脚本编写注意事项 &#xff08;1&#xff09;CPU占用率列 &#xff08;2&#xff09;多进程实例 &#xff08;3&#xff09;权限 四、运行脚本 1、给予脚本可执行权限 2、运行脚本 五、优化脚本 …

linux live555编译以及rtsp服务器搭建

一、live555源码 下载&#xff1a;点击跳转 二、编译 1、往文件 config.linux里的 COMPILE_OPTS 添加以下两个参数 -DNO_STD_LIB 和 -DNO_OPENSSL1 &#xff0c;修改后如下&#xff1a; COMPILE_OPTS $(INCLUDES) -I/usr/local/include -I. -O2 -DNO_STD_LIB -DNO_OPENSS…

大数减法c++

这里写目录标题 key key 检查减数和被减数的大小&#xff0c;大的放前&#xff0c;小的放后确定结果是正数&#xff0c;还是负数&#xff0c;即符号位从低位开始减如果a[i]<b[i]&#xff0c;则向高位借1当10&#xff0c;a[i1]–;a[i]10 #include <iostream> #include…

【python】OpenCV—Coordinates Sorted Clockwise

文章目录 1、需求介绍2、算法实现3、完整代码 1、需求介绍 调用 opencv 库&#xff0c;绘制轮廓的矩形边框&#xff0c;坐标顺序为右下→左下→左上→右上&#xff0c;我们实现一下转化为熟悉的 左上→右上→右下→左下 形式 按照这样的顺序组织边界框坐标是执行透视转换或匹…

采用反相正基准电压电路的反相运算放大器(运放)

采用反相正基准电压电路的反相运算放大器(运放) 采用反相正基准电压电路的同相运算放大器&#xff08;运放&#xff09; 设计目标 输入ViMin输入ViMax输出VoMin输出VoMax电源电压Vcc电源电压Vee电源电压Vref-5V-1V0.05V3.3V5V0V5V 设计说明1 此设计使用具有反相正基准的反…

gite+picgo+typora打造个人免费笔记软件

文章目录 1️⃣个人笔记软件2️⃣ 配置教程2.1 使用软件2.2 node 环境配置2.3 软件安装2.4 gite仓库设置2.5 配置picgo2.6 测试检验2.7 github教程 &#x1f3a1; 完结撒花 1️⃣个人笔记软件 最近换了环境&#xff0c;没有之前的生产环境舒适&#xff0c;写笔记也没有劲头&…

盒须图boxplot 展示第6条线

正常情况下,盒须图是有5条线的,但是实际产品场景是需要6条线,看了下echarts官网,没看到可配置的地方,只能自己骚操作了,效果图如下: 重点:用两条x轴,第6条线挂在第二条x轴上,且第二条x轴不展示。 option = {...,xAxis: [{type: category,data: [Class1, Class2, Cl…

Web前端网页设计与制作(想起来哪里写哪里版)

本文技术栈基于HtmlCssJavaScript制作web页面以及功能实现的部分设计与展示&#xff0c;实际的网站开发会涉及更多的细节&#xff0c;包括但不限于用户认证、数据库存储、前端框架的使用、响应式设计、安全性措施等。 废话不说&#xff0c;直接看源码 1.index 首页&#xff1a…

【漏洞复现】泛微e-cology9 WorkflowServiceXml SQL注入漏洞

文章目录 前言漏洞描述影响范围 漏洞复现nuclei脚本 安全修复 前言 泛微协同管理应用平台e-cology是一套兼具企业信息门户、知识文档管理、工作流程管理、人力资源管理、客户关系管理、项目管理、财务管理、资产管理、供应链管理、数据中心功能的企业大型协同管理平台。 漏洞…

算法学习day16——刷题(仍然是数组)

一、图片平滑器 图像平滑器 是大小为 3 x 3 的过滤器&#xff0c;用于对图像的每个单元格平滑处理&#xff0c;平滑处理后单元格的值为该单元格的平均灰度。 每个单元格的 平均灰度 定义为&#xff1a;该单元格自身及其周围的 8 个单元格的平均值&#xff0c;结果需向下取整…

使用llama-cpp-python制作api接口

文章目录 概要整体操作流程技术细节小结 概要 使用llama-cpp-python制作api接口&#xff0c;可以接入gradio当中&#xff0c;参考上一节。 llama-cpp-python的github网址 整体操作流程 下载llama-cpp-python。首先判断自己是在CPU的环境下还是GPU的环境下。以下操作均在魔搭…

应用层——HTTP

像我们电脑和手机使用的应用软件就是在应用层写的&#xff0c;当我们的数据需要传输的时候换将数据传递到传输层。 应用层专门给用户提供应用功能&#xff0c;比如HTTP,FTP… 我们程序员写的一个个解决我们实际的问题都在应用层&#xff0c;我们今天来聊一聊HTTP。 协议 协议…

Java案例遍历集合中的自定义对象

目录 一&#xff1a;案例要求&#xff1a; 二案例分析&#xff1a; ​编辑三&#xff1a;具体代码&#xff1a; 四&#xff1a;运行结果&#xff1a; 一&#xff1a;案例要求&#xff1a; 二案例分析&#xff1a; 三&#xff1a;具体代码&#xff1a; Ⅰ&#xff1a; pack…

pyinstaller用法详解3

本文使用创作助手。 大家好&#xff0c;时隔多日&#xff0c;我又更新了pyinstaller的用法详解&#xff01; 当然&#xff0c;这一次要比之前更详细&#xff0c;十分详细。 谢谢大家的支持&#xff0c;我们现在开始&#xff01; 一、快速开始使用pyinstaller 我之前的文章…