【Three.js】知识梳理十:Three.js纹理贴图

1. 纹理贴图

在Three.js中,纹理贴图是一种将二维图像贴到三维物体表面的技术,以增强物体的视觉表现。纹理贴图可以使物体表面更加真实、细腻,为场景增色不少。

在Three.js中,纹理贴图的加载主要通过THREE.TextureLoader类实现。下面是一个简单的加载纹理的示例:

const loader = new THREE.TextureLoader();
loader.load('path/to/your/texture.png', function(texture) {
  // 创建一个材质对象并设置纹理贴图
  const material = new THREE.MeshBasicMaterial({map: texture});
  // 创建一个物体并为其添加纹理贴图
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);
});

2. 纹理过滤

纹理过滤是一种处理技术,用于决定当纹理图像被映射到比其原始分辨率大或小的像素时,如何从纹理中采样颜色。主要有三种类型的纹理过滤:线性过滤、最近邻过滤和mipmap过滤。

  • 线性过滤(Linear Filtering) :这种过滤方法使用了纹理中最近的四个像素的加权平均值,以得到一个新的颜色值。这种方法产生的效果通常比较平滑,但在处理高对比度纹理时,可能会产生模糊的效果。
  • 最近邻过滤(Nearest Filtering) :这种过滤方法简单地选择纹理中最近的一个像素的颜色。这种方法在处理像素艺术和其他需要保持锐利边缘的纹理时非常有用,但可能会导致锯齿状边缘。
  • Mipmap过滤:这种过滤方法在加载纹理时,会创建纹理的多个缩小版本(称为mipmap),然后根据纹理在屏幕上的大小,选择合适大小的mipmap进行采样。这种方法可以在不同距离都保持纹理的良好表现,但会增加内存使用量。

在Three.js中,我们可以通过设置纹理的minFiltermagFilter属性来控制纹理过滤。

minFilter属性控制当纹理被缩小时使用的过滤方法,magFilter属性控制当纹理被放大时使用的过滤方法。这两个属性的默认值都是THREE.LinearMipmapLinearFilter,即使用mipmap过滤。

以下是一个简单的示例,展示了如何在Three.js中设置纹理过滤:

var loader = new THREE.TextureLoader();
​
// 加载纹理
loader.load('textures/yourTexture.png', function(texture) {
    // 设置纹理过滤
    texture.minFilter = THREE.NearestFilter;
    texture.magFilter = THREE.LinearFilter;
​
    // 创建材质
    var material = new THREE.MeshBasicMaterial({map: texture});
​
    // 创建网格
    var mesh = new THREE.Mesh(geometry, material);
​
    // 将网格添加到场景
    scene.add(mesh);
});

在这个例子中,我们首先加载了纹理,然后设置minFilter属性为THREE.NearestFiltermagFilter属性为THREE.LinearFilter。这表示当纹理被缩小时,我们使用最近邻过滤,当纹理被放大时,我们使用线性过滤。

3. UV映射原理

在三维图形中,UV坐标是用于将二维纹理映射到三维模型上的。这个名字中的"U"和"V"代表的是纹理坐标的两个维度,它们与三维空间的"X"、"Y"和"Z"坐标是独立的。

在UV映射中,"U"对应于纹理的水平(宽度)方向,"V"对应于纹理的垂直(高度)方向。UV坐标的范围通常是从0到1,其中(0,0)表示纹理的左下角,(1,1)表示纹理的右上角。

几何体有两组UV坐标,第一组组用于.map.normalMap.specularMap等贴图的映射,第二组用于阴影贴图.lightMap的映射

image.png

3.1 纹理UV坐标

在Three.js中,UV坐标是通过THREE.GeometryTHREE.BufferGeometry对象的.uv属性来定义的。每个面(或者是三角形)都有自己的UV坐标集合,这些集合是一个包含两个元素(U和V)的THREE.Vector2对象的数组。

以下是一个简单的示例,展示了如何在Three.js中定义UV坐标:

var geometry = new THREE.Geometry();
​
// 创建顶点
var v1 = new THREE.Vector3(0,0,0);
var v2 = new THREE.Vector3(1,0,0);
var v3 = new THREE.Vector3(0,1,0);
var v4 = new THREE.Vector3(1,1,0);
​
geometry.vertices.push(v1);
geometry.vertices.push(v2);
geometry.vertices.push(v3);
geometry.vertices.push(v4);
​
// 创建面
var face1 = new THREE.Face3(0, 1, 2);
var face2 = new THREE.Face3(1, 2, 3);
​
// 创建UV坐标
var uv1 = new THREE.Vector2(0, 0);
var uv2 = new THREE.Vector2(1, 0);
var uv3 = new THREE.Vector2(0, 1);
var uv4 = new THREE.Vector2(1, 1);
​
// 将UV坐标添加到每个面
geometry.faces.push(face1);
geometry.faceVertexUvs[0].push([uv1, uv2, uv3]);
​
geometry.faces.push(face2);
geometry.faceVertexUvs[0].push([uv2, uv3, uv4]);

在这个例子中,我们首先创建了一个新的THREE.Geometry对象,然后添加了四个顶点和两个面。然后,我们定义了每个面的UV坐标,并将它们添加到geometry.faceVertexUvs[0]数组。

3.2 纹理映射

现在我们有了几何体和UV坐标,下一步就是创建和加载纹理。在Three.js中,我们可以使用THREE.TextureLoader来加载纹理图片。以下是一个简单的例子:

var loader = new THREE.TextureLoader();
​
// 加载纹理
loader.load('textures/yourTexture.png', function(texture) {
    // 创建材质
    var material = new THREE.MeshBasicMaterial({map: texture});
​
    // 创建网格
    var mesh = new THREE.Mesh(geometry, material);
​
    // 将网格添加到场景
    scene.add(mesh);
});

在上述代码中,我们首先创建一个新的THREE.TextureLoader实例,然后调用它的.load()方法来加载纹理。加载完成后,我们创建了一个新的THREE.MeshBasicMaterial对象,并将加载的纹理作为地图属性传递给它。然后,我们使用几何体和材质创建了一个新的THREE.Mesh对象,并将它添加到场景中。

为了更好地控制纹理贴图的映射,可以通过以下方法:

  • 改变纹理的偏移量:texture.offset = new THREE.Vector2(x, y);
  • 改变纹理的缩放比例:texture.repeat = new THREE.Vector2(x, y);

4. 纹理阵列,偏移和旋转

4.1 纹理阵列

在某些情况下,你可能希望在物体表面上重复使用一张纹理。比如,当你创建一片草地或墙壁时,你可能需要在模型上多次平铺相同的纹理。这就是纹理阵列的作用。

在Three.js中,我们可以通过设置纹理的repeat属性来实现纹理阵列。repeat属性是一个THREE.Vector2对象,表示纹理在U和V方向上的重复次数。默认情况下,这个值是(1, 1),表示纹理只在每个方向上显示一次。

以下是一个简单的示例,展示了如何在Three.js中创建纹理阵列:

var loader = new THREE.TextureLoader();
​
// 加载纹理
loader.load('textures/yourTexture.png', function(texture) {
    // 设置纹理阵列
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set(4, 4);
​
    // 创建材质
    var material = new THREE.MeshBasicMaterial({map: texture});
​
    // 创建网格
    var mesh = new THREE.Mesh(geometry, material);
​
    // 将网格添加到场景
    scene.add(mesh);
});

在这个例子中,我们首先加载了纹理,然后设置了wrapSwrapT属性为THREE.RepeatWrapping,表示我们希望纹理在两个方向上都能重复。接着,我们使用texture.repeat.set(4, 4)来设置纹理在U和V方向上重复4次。

4.2 纹理偏移

如前所述,纹理偏移可以通过调整纹理的offset属性来实现。offset属性是一个THREE.Vector2对象,表示纹理在U和V方向上的偏移量。默认情况下,这个值是(0, 0),表示没有偏移。

以下是一个简单的示例,展示了如何在Three.js中设置纹理偏移:

texture.offset.set(0.5, 0.5);

在这个例子中,我们将纹理的偏移设置为(0.5, 0.5),表示纹理在U和V方向上都向正方向偏移了一半的距离。

4.3 纹理旋转

Three.js中的纹理旋转可以通过修改纹理的rotation属性来实现。

rotation属性是一个以弧度为单位的角度值,用于指定纹理的旋转角度。默认情况下,这个值是0,表示没有旋转。

以下是一个简单的示例,展示了如何在Three.js中设置纹理旋转:

// 旋转纹理90度
texture.rotation = Math.PI / 2;

在这个例子中,我们将纹理的旋转角度设置为Math.PI / 2,即90度。需要注意的是,纹理旋转是以纹理的中心点为轴进行的。

5. UV动画

在Three.js中,我们可以通过修改纹理的offset属性来改变纹理的UV坐标。offset属性是一个THREE.Vector2对象,代表了纹理在U和V方向上的偏移量。我们可以在每一帧中稍微改变这个值,来实现纹理的移动效果。

下面是一个简单的示例,展示了如何在Three.js中创建一个UV动画:

// 加载纹理
var loader = new THREE.TextureLoader();
var texture = loader.load('textures/yourTexture.png');
​
// 创建材质
var material = new THREE.MeshBasicMaterial({map: texture});
​
// 创建网格
var mesh = new THREE.Mesh(geometry, material);
​
// 将网格添加到场景
scene.add(mesh);
​
// 在渲染循环中更新纹理偏移
function animate() {
    requestAnimationFrame(animate);
​
    // 每一帧稍微移动纹理
    material.map.offset.y -= 0.01;
​
    // 渲染场景
    renderer.render(scene, camera);
}
​
animate();

在这个例子中,我们首先加载了纹理,然后创建了一个包含该纹理的材质和一个使用该材质的网格。然后,在我们的渲染循环中,我们每一帧都稍微改变纹理的offset.y值,从而使纹理在V方向上移动,产生动态效果。

附送250套精选项目源码

源码截图

 源码获取:关注公众号「码农园区」,回复 【源码】,即可获取全套源码下载链接

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode | 26.删除有序数组中的重复项

在我接触到这道题的时候想的就是一次遍历,设置两个变量记录当前遍历到的数字和对应原数组应该修改的index,在运行过程中,因为原数组已经是有序的了,只不过会存在重复的数字,但是这些重复的数字也是挨在一起的&#xff…

RT-Thread系统使用STM32H7芯片串口5不工作

使用stm32h743芯片串口5不工作,其他串口都正常,TX5->PC12,RX5->PD2 drv_usart.c里面串口5的TX和RX反了,将TX和RX对调后解决。

opencv学习笔记 -- 如何扫描图像

本节主要解决以下几个问题: 如何遍历图像的每一个像素如何存储opencv的矩阵如何衡量算法的性能查询表是什么并且为何要使用该表 举一个例子 如果是使用RGB的格式,数据格式采用unsigned char来进行储存,则每个像素点有256个不同的值&#x…

如何给自己的项目实现在线测试的接口文档knife4j

配置实现Knife4j在线接口测试文档 为什么要是实现这个东西呢?肯定是对我们有用的,后端主要编写的就是接口,然后我们将接口编写好了之后肯定还是需要进行调试看是否能够正常使用且按照规范返回对应的数据。相信大家测试都是基本上使用的是一些…

【紧急警示】Locked勒索病毒利用最新PHP远程代码执行漏洞大规模批量勒索!文末附详细加固方案

1. Locked勒索病毒介绍 locked勒索病毒属于TellYouThePass勒索病毒家族的变种,其家族最早于2019年3月出现,擅长利用高危漏洞被披露后的短时间内,利用1Day对暴露于网络上并存在有漏洞未修复的机器发起攻击。该家族在2023年下半年开始&#xf…

【CS.PL】Lua 编程之道: 基础语法和数据类型 - 进度16%

2 初级阶段 —— 基础语法和数据类型 文章目录 2 初级阶段 —— 基础语法和数据类型2.0 关键字(keywords) 🔥2.1 注释与标识符2.1.1 注释2.1.2 标识符 2.2 变量与赋值2.2.1 所有变量默认是全局变量 ≠ local, 有一个例外2.2.2 local变量是局部变量, 以end作为边界2.…

ARM32开发--RTC内置实时时钟

知不足而奋进 望远山而前行 目录 系列文章目录 文章目录 前言 学习目标 学习内容 RTC时钟介绍 RTC结构框图 RTC原理图 RTC时钟电源 RTC的配置流程 RTC时钟 开发流程 RTC初始化 时钟配置 时钟获取 BCD格式转化 完整代码 RTC时钟备份寄存器 总结 前言 在嵌入式…

【CS.DB】深度解析:ClickHouse与Elasticsearch在大数据分析中的应用与优化

文章目录 《深入对比:在大数据分析中的 ClickHouse和Elasticsearch》 1 介绍 2 深入非关系型数据库的世界2.1 非关系型数据库的种类2.2 列存储数据库(如ClickHouse)2.3 搜索引擎(如Elasticsearch)2.4 核心优势的归纳 3…

准研究生了解内容:如何挑选论文并下载

本文主要纪录自己从0开始摸索如何找论文,下载论文等的过程。 前言 (一点想法)## 作为准研究生,上岸后一直非常颓废,除了给人补课挣了点money,剩下时间都是打游戏,被老姐训诫后决定继续学习。毕…

跟着AI学AI_07张量、数组、矩阵

说明这三个概念不是一个范畴的东西,但是很容易混淆,因此放到一起进行说明。 张量(Tensor) 张量是一个多维数组的通用概念,用于表示具有任意维度的数值数据。在数学和计算机科学中,张量是广泛用于表示数据的…

【星海随笔】云解决方案学习日志篇(一) ELK,kibana,Logstash安装

心路历程 本来想最近再研究研究DPDK的。但是自己做一个东西很多时候没有回报。因为自己的低学历问题,类似工作的面试都没有。所以很多东西学了很快就忘了,没有地方可以用。 今天看到了一个大佬,除了发型外,很多想法还是很共鸣的。 Shay Banon 决定开始跟…

【JavaScript】简单数据类型 与 复杂数据类型 ① ( 堆内存和栈内存 | 简单数据类型内存存储 | 复杂数据类型内存存储 )

文章目录 一、简单数据类型1、简单数据类型简介2、简单数据类型 null 空类型的特殊性 二、复杂数据类型三、堆内存和栈内存 一、简单数据类型 1、简单数据类型简介 JavaScript 中 , " 简单数据类型 “ 又称为 ” 基本数据类型 " 或 " 值类型 " , 与 简单数…

MySQL-分组函数

041-分组函数 重点:所有的分组函数都是自动忽略NULL的 分组函数的执行原则:先分组,然后对每一组数据执行分组函数。如果没有分组语句group by的话,整张表的数据自成一组。 分组函数包括五个: max:最大值mi…

Ecovadis认证准则

Ecovadis准则是一个国际性的企业社会责任(CSR)评估平台,旨在帮助企业、投资者、供应商和利益相关者等评估和管理其全球供应链的社会和环境影响。该准则涵盖了可持续性、人权、劳工权利、环境保护等方面的评估内容,为企业提供了全面的评估标准和管理工具&…

从客户端WebAPI视角下解读前端学习

API 应用程序接口(API,Application Programming Interface)是基于编程语言构建的结构,使开发人员更容易地创建复杂的功能。它们抽象了复杂的代码,并提供一些简单的接口规则直接使用。 JavaScript VS 客户端 API VS 客…

Buffer

Buffer 概念 在Node.js中,Buffer是一个非常重要的内置全局对象,Node.js是基于Chrome V8引擎构建的,V8引擎本身不支持处理二进制数据,因此Node.js引入Buffer来弥补这一不足,Buffer中文译为【缓冲区】,是一…

视觉系统辅助引导在激光导航AGV中应用

agv 在全球经济步入“寒冬”的大背景下,大量传统制造业企业开始谋划转变。通过引入AGV系统提升厂内物流效率、降低运营成本,已经成为制造业升级的趋势之一。 AGV是移动机器人的一个重要分支,具有并行作业、自动化、智能化和柔性化等优势&…

centos8 中文打印报错,解决

sudo yum install -y glibc-locale-source sudo localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8 sudo yum install -y fontconfig

入门Consul注册、配置中心(代码演示)

1、安装与使用 2、注册服务到consul 3、调用consul上注册的服务 4、配置中心 1、安装与使用 官网地址:Install | Consul | HashiCorp Developer 下载对应的系统 解压缩后文件 打开命令行运行 consul.exe agent -dev 即可运行 可以编写一个bat脚本每次运行ba…

bdcn手顺

GitHub链接 https://github.com/pkuCactus/BDCN 环境配置(Prerequisites) Python 3.8 contourpy1.1.1 cycler0.12.1 filelock3.14.0 fonttools4.53.0 fsspec2024.6.0 importlib_resources6.4.0 intel-openmp2021.4.0 Jinja23.1.4 kiwisolver1.4.5 Mark…