探索三维世界【2】:Three.js 的 Texture 纹理

news2025/1/11 2:53:41

缤纷三维世界大揭秘:探索 Three.js 的 Texture 纹理

  • 1、Texture纹理
  • 2、TextureLoader 纹理加载器
    • 2.1、创建纹理加载器
    • 2.2、纹理属性设置
    • 2.3、设置纹理渲染
    • 2.4、打光
  • 3、完整代码与展示

1、Texture纹理

Texture 是 three.js 中的“纹理”概念。纹理是指将一张图像映射到 three.js 场景中的物体表面上的过程。通过 Texture,可以在 three.js 场景中应用各种图像效果,并让物体的表面看起来更真实。

Texture 主要有以下子类:

  • DataTexture:可以存储任意格式的数据。这对于高度自定义的定制场景非常有用。
  • CompressedTexture:可以压缩图像以减少显存占用。这对于需要使用大量图片的场景非常有用。
  • CubeTexture:可以在物体表面上实现立体效果,让场景更加真实。
  • VideoTexture:可以将视频应用于场景中的物体表面上。
  • Texture 类的属性和方法,可以在 three.js 中实现各种纹理效果。例如,可以使用 Texture.repeat 和 Texture.wrapS 等属性来控制纹理的重复和环绕方式,使用 Texture.offset 来控制纹理的偏移量,使用 Texture.minFilter 和 Texture.magFilter 来控制纹理的缩放方式等等。

2、TextureLoader 纹理加载器

那么好,上面说明了Texture纹理,那么TextureLoader 纹理加载器就顾名思义是指加载纹理的对象咯。

TextureLoader 是 three.js 内置的一个类,用于加载纹理文件并创建 Texture 对象。你可以使用 TextureLoader 加载网页中的图像,然后在场景中创建一个新的纹理对象,并将其应用到任何需要的物体表面上。在加载过程中,实际上是使用 Texture 和其子类来创建不同类型的纹理对象。例如,TextureLoader 可以加载普通的图片来创建基本的 Texture 对象,或者加载 .dds 文件来创建压缩的 CompressedTexture 对象。

因此,TextureLoader 和 Texture 以及其子类之间是一种解耦的关系,TextureLoader 负责纹理的加载和创建工作,而 Texture 及其子类则负责实现具体的纹理效果和属性。

2.1、创建纹理加载器

在进行创建纹理加载器时,直接通过THREE父类进行创建,之后通过load方法进行加载图片到对应的纹理对象上。并且这里我们也并不关心图片何时加载上去,以及加载成功或失败的问题,后面三个回调函数就不必通过函数进行传递

.load ( url : String, onLoad : Function, onProgress : Function, onError : Function ) : Texture

  • url — 文件的URL或者路径,也可以为 Data URI.
  • onLoad — 加载完成时将调用。回调参数为将要加载的texture.
  • onProgress — 将在加载过程中进行调用。参数为XMLHttpRequest实例,实例包含total和loaded字节。
  • onError — 在加载错误时被调用。
import TREE from './assets/img/tree.png'
import SHIP from './assets/img/ship.png'

const textureLoader = new THREE.TextureLoader()
const treeloader = textureLoader.load(TREE)
const shiploader = textureLoader.load(SHIP)

2.2、纹理属性设置

  • .offset : 贴图单次重复中的起始偏移量,分别表示U和V。 一般范围是由0.0到1.0
  • .center : 旋转中心点。(0.5, 0.5)对应纹理的正中心。默认值为(0,0),即左下角。
  • .rotation : 纹理将围绕中心点旋转多少度,单位为弧度(rad)。正值为逆时针方向旋转,默认值为0。
  • .repeat:决定纹理在表面的重复次数,两个方向分别表示U和V,如果重复次数在任何方向上设置了超过1的数值, 对应的Wrap需要设置为THREE.RepeatWrapping或者THREE.MirroredRepeatWrapping来 达到想要的平铺效果。
  • .wrapS : 这个值定义了纹理贴图在水平方向上将如何包裹,在UV映射中对应于U。默认值是THREE.ClampToEdgeWrapping,即纹理边缘将被推到外部边缘的纹素。 其它的两个选项分别是THREE.RepeatWrapping和THREE.MirroredRepeatWrapping。
    • 使用RepeatWrapping,纹理将简单地重复到无穷大。
    • 使用MirroredRepeatWrapping, 纹理将重复到无穷大,在每次重复时将进行镜像。
  • .wrapT : 这个值定义了纹理贴图在垂直方向上将如何包裹,在UV映射中对应于V。同上wrapS
// 偏移
// treeloader.offset.x = 0.5
// treeloader.offset.y = 0.5
treeloader.offset.set(0.5, 0.5)
// 设置中心点和旋转角度
treeloader.center.set(0.5, 0.5)
// treeloader.rotation = Math.PI / 4
// 设置重复展示 需要设置包裹模式wrapS、wrapT
treeloader.wrapS = THREE.RepeatWrapping
treeloader.wrapT = THREE.RepeatWrapping
treeloader.repeat.set(2, 4)


// shiploader.offset.set(0.5, 0.5)
shiploader.center.set(0.5, 0.5)
// shiploader.wrapS = THREE.RepeatWrapping
// shiploader.wrapT = THREE.RepeatWrapping
// shiploader.repeat.set(2, 4)
// 纹理显示    低像素展示
shiploader.minFilter = THREE.NearestFilter
shiploader.magFilter = THREE.NearestFilter

2.3、设置纹理渲染

在前面一章当中(探索三维世界:从Hello World开始的Three.js入门之旅)已经简单说明了如何创建一个简单的立体物体与材质,我们只需要给MeshBasicMaterial或者其他的材质设置上纹理也就完成了纹理贴图。

先看上一篇设置的MeshBasicMaterial基础网格材质,只给其设置了颜色

const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );

这里我们可以通过alphaMap与map进行设置纹理

  • .alphaMap : Texture纹理类型 alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。
  • .map : Texture纹理类型 颜色贴图。
  • .transparent : 定义此材质是否透明。
const material = new THREE.MeshBasicMaterial({
    color: 'yellow',
    map: treeloader,
    alphaMap: treeloader,
    // transparent: true,
    // 渲染两面(外面、里面)
    side: THREE.DoubleSide
    // opacity: 0.5
});

2.4、打光

添加平行光

const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(-10, 10, 10)
scene.add(directionalLight);

3、完整代码与展示

在这里插入图片描述

import * as THREE from 'three'
import {
    OrbitControls
} from 'three/examples/jsm/controls/OrbitControls.js'
import TREE from './assets/img/tree.png'
import SHIP from './assets/img/ship.png'
// 场景
const scene = new THREE.Scene();
// 相机 (透视相机)  角度、宽高比、近端面、远端面
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
scene.add(camera);

// 使用纹理
const textureLoader = new THREE.TextureLoader()
const treeloader = textureLoader.load(TREE)
const shiploader = textureLoader.load(SHIP)

// 纹理属性
// 偏移
// treeloader.offset.x = 0.5
// treeloader.offset.y = 0.5
treeloader.offset.set(0.5, 0.5)
// 设置中心点和旋转角度
treeloader.center.set(0.5, 0.5)
// treeloader.rotation = Math.PI / 4
// 设置重复展示 需要设置包裹模式wrapS、wrapT
treeloader.wrapS = THREE.RepeatWrapping
treeloader.wrapT = THREE.RepeatWrapping
treeloader.repeat.set(2, 4)


// shiploader.offset.set(0.5, 0.5)
shiploader.center.set(0.5, 0.5)
shiploader.wrapS = THREE.RepeatWrapping
shiploader.wrapT = THREE.RepeatWrapping
// shiploader.repeat.set(2, 4)
// 纹理显示    低像素展示
shiploader.minFilter = THREE.NearestFilter
shiploader.magFilter = THREE.NearestFilter

// 几何体与材质
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({
    color: 'yellow',
    map: treeloader,
    alphaMap: treeloader,
    // transparent: true,
    // 渲染两面(外面、里面)
    side: THREE.DoubleSide
    // opacity: 0.5
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

const planeGeometry = new THREE.PlaneGeometry(1, 1)
const plane = new THREE.Mesh(
    new THREE.PlaneGeometry(1, 1),
    material
)
plane.position.set(1, 0, 0)
// 第二套UV 环境渲染
planeGeometry.setAttribute(
    "uv2",
    new THREE.BufferAttribute(planeGeometry.attributes.uv.array, 2)
)
scene.add(plane)

// 标准网格材质
const mgeometry = new THREE.BoxGeometry(1, 1, 1);
const meshStandardMaterial = new THREE.MeshStandardMaterial({
    color: 0x00ff00,
    map: shiploader,
    alphaMap: shiploader,
    // 渲染两面(外面、里面)
    side: THREE.DoubleSide
});
const mCube = new THREE.Mesh(mgeometry, meshStandardMaterial);
mCube.position.set(4, 0, 0)
scene.add(mCube);

// 加上灯光 环境光不能用来投射阴影,因为它没有方向。 入参 颜色的rgb数值  光照的强度
// const light = new THREE.AmbientLight('red', 0.5);
// scene.add(light);
// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(0, 10, 10)
scene.add(directionalLight);

// 坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

// 渲染
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 新增轨迹控制器
const controls = new OrbitControls(camera, renderer.domElement);

// 使用渲染器   通过相机将场景渲染
function render(time) {
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

render()

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

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

相关文章

ESP8266基于Lua开发使用U8g2模块驱动 i2c ssd1306 OLED显示

ESP8266基于Lua开发使用U8g2模块驱动 i2c ssd1306 OLED显示 📍相关篇《ESP8266基于Lua开发点灯示例》 📖U8g2对应的API接口函数:https://nodemcu.readthedocs.io/en/release/modules/u8g2/ 📺驱动显示效果: &#…

Winform从入门到精通(38)——StatusStrip(史上最全)更新中

一、属性 1、Name 获取StatusStrip控件对象 2、AllowDrop 允许用户拖拽数据到控件上 3、AllowItemReorder 当用于按下alt键时,是否允许对项进行排列,如下图: 4、AllowMerge 5、Anchor 6、AutoSize 7、BackColor 设置StatusStrip的背景色 8、BackgroundImage 设置背…

解决wordpress 没有“add new“按钮

文章目录 问题描述解决方案两个参数的详细解释DISALLOW_FILE_EDITDISALLOW_FILE_MODS 问题描述 新安装的wordpress发现没有“add new“按钮,很奇怪。 解决方案 修改wp-config.php文件,增加如下两行即可修复问题: define(‘DISALLOW_FILE_E…

【实战详解】如何快速搭建接口自动化测试框架?:Python + Requests

摘要: 本篇文章将介绍如何基于Python和Requests库快速搭建一个简单而高效的接口自动化测试框架。您将会了解到设计测试用例、准备测试数据、编写自动化脚本等步骤,以及如何使用断言来检查测试结果,并最终构建一个可重用、易扩展的自动化测试…

【前端每日一问002】jquery中each与data方法的用法与概念

在 jQuery 中,.each() 方法和 .data() 方法都是常用的工具。这两个方法的用法和概念如下: 🌙一、.each() 方法: .each() 方法是 jQuery 对象的方法,用于遍历匹配元素集合中的所有元素,并对每个元素执行一个…

【LeetCode】1000题挑战(225/1000)

1000题挑战 没有废话,直接开刷! 目录 1000题挑战 没有废话,直接开刷! 第一题:202. 快乐数 - 力扣(Leetcode) 题目接口: 解题思路: 代码: 过过过过啦…

基于W1R3S的渗透测试

您被雇来对W1R3S做渗透测试,他们要求您获得root权限并找到标志(位于/root目录中)。 目标:得到root权限&找到flag.txt 目录 1、信息收集 (1)定位靶机IP (2)端口扫描 (3)脚本…

【HTMLCSSJS】写实验发现的一些注意点

🎊专栏【 前端易错合集】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【如愿】 大一同学小吉,欢迎并且感谢大家指出我的问题🥰 目录 🚥innerHtml和innerText的区别 &#x1f3f…

28-Servlet API

1.HttpServlet 我们写 Servlet 代码的时候,⾸先第⼀步就是先创建类,继承⾃ HttpServlet,并重写其中的某些⽅法。 1.1.核心方法 实际开发的时候主要重写 doXXX ⽅法,很少会重写 init / destory / service。 这些⽅法的调⽤时机&…

c++基础-运算符

目录 1关系运算符 2运算符优先级 3关系表达式的书写 代码实例&#xff1a; 下面是面试中可能遇到的问题&#xff1a; 1关系运算符 C中有6个关系运算符&#xff0c;用于比较两个值的大小关系&#xff0c;它们分别是&#xff1a; 运算符描述等于!不等于<小于>大于<…

2 异或位运算大厂必刷题

文章目录 如何不用额外变量交换两个数一个数组中有一种数出现了奇数次&#xff0c;其他数都出现了偶数次&#xff0c;怎么找到并打印这种数怎么把一个int类型的数&#xff0c;提取出最右侧的1来怎么把一个int类型的数,获取位数为1的数量一个数组中有两种数出现了奇数次&#xf…

开发问题记录20230502

4 Docker普通用户无权限 普通用户执行docker命令提示信息&#xff1a; docker images docker ps -adocker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post “http://%2Fvar%2Frun%2Fdocker.sock/v1.24/c…

Java 的简要介绍及开发环境的搭建(超级详细)

图片来源于互联网 目录 | CONTENT Java 简介 一、什么是 Java 二、认识 Java 版本 三、选择哪个版本比较好 搭建 Java 开发环境 一、下载 Java 软件开发工具包 JDK 二、配置环境变量 自动配置 手动配置 三、下载合适的 IDE IntelliJ IDEA Visual Studio Code Eclip…

Flutter 组件使用:使用 Stack 替代 GlobalKey 的定位 tip-widget 实现

场景 有时候需要在指定位置进行 tip-widget 的弹出与展示&#xff0c;常见的方式是通过给指定位置上的指定 widget 添加 GlobalKey 来实现&#xff1b; 但是&#xff0c;使用这种方式的话&#xff0c;【一】大多数时候都需要进行全局定位转换&#xff08;localToGlobal&#…

c++ 11标准模板(STL) std::vector (三)

定义于头文件 <vector> template< class T, class Allocator std::allocator<T> > class vector;(1)namespace pmr { template <class T> using vector std::vector<T, std::pmr::polymorphic_allocator<T>>; }(2)(C17…

Winform从入门到精通(36)——ColorDialog(史上最全)

文章目录 前言一、属性1、AllowFullOpen2、AnyColor3、Color4、FullOpen5、ShowHelp6、SolidColorOnly7、Tag二、事件1、HelpRequest前言 当我们需要设置某个控件的颜色时,并且需要弹出一个可以选择颜色的对话框时,这时候就需要使用ColorDialog 一、属性 1、AllowFullOpen…

LoadRunner 安装指南:详解安装步骤和常见问题解决方法

目录&#xff1a;导读 引言 LoadRunner安装 LoadRunner的安装 结语 引言 作为一款领先的性能测试工具&#xff0c;LoadRunner 被广泛应用于各种企业级应用程序和系统的性能测试中。然而&#xff0c;对于初学者来说&#xff0c;正确安装 LoadRunner 并不是一件容易的事情。…

Spring 填充属性和初始化流程源码剖析及扩展实现

前言 在上一篇博文 讲解 Spring 实例化的不同方式及相关生命周期源码剖析 介绍了 Spring 实例化的不同方式&#xff0c;本文主要围绕实例化过后对象的填充属性和初始化过程进行详细流程剖析 回顾前言知识&#xff0c;doCreateBean->createBeanInstance&#xff0c;通过 S…

沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟

目录 沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟 CH32V 存储容量命名方式 在介绍下面的内容前, 先看一下CH32V系列和存储相关的命名格式, 以CH32V203为例, 前面的CH32V203代表一个系列, 后面的字…

剑指offer(C++)-JZ47:礼物的最大价值(算法-动态规划)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 在一个m\times nmn的棋盘的每一格都放有一个礼物&#xff0c;每个礼物都有一定的价值&#xff08;价值大于…