Three.js 纹理贴图的实现

在线工具推荐: 3D数字孪生场景编辑器  -  GLTF/GLB材质纹理编辑器  -  3D模型在线转换  -  Three.js AI自动纹理开发包  -  YOLO 虚幻合成数据生成器  -  三维模型预览图生成器  -  3D模型语义搜索引擎

纹理贴图简介

当我们创建一个网格时,比如我们不起眼的立方体,我们传入两个组件:几何体和材质。

网格需要两个子组件:几何体和材料

const mesh = new Mesh(geometry, material);

几何形状定义了网格的形状,材料定义了网格的各种表面属性,特别是它对光的反应。几何体和材质,以及影响网格的任何光影,在渲染场景时控制网格的外观。目前,我们的场景包含一个网格,其形状由 a 定义,曲面由 a 定义,颜色参数设置为紫色。这由单个 照亮,当我们渲染场景时,结果就是这个简单的紫色框。BoxBufferGeometryMeshStandardMaterialDirectionalLight

由 unsplash 的 @christianfregnan 提供

由混凝土制成的立方体。

将其与现实世界中的混凝土盒子进行比较 - 或木箱,或金属箱,或由几乎任何物质制成的盒子,除了光滑的塑料,我们可以立即看到我们的3D盒子根本不现实。现实世界中的物体通常是划伤、破损和肮脏的。但是,应用于我们盒子的材料看起来不是这样的。相反,它由平滑地应用于网格的整个表面的单一颜色组成。除非我们希望我们所有的作品看起来像全新的塑料,否则这是行不通的。

除了颜色之外,材质还有许多参数,我们可以用这些参数来调整物体表面的各种属性,如粗糙度、金属度、不透明度等。但是,就像颜色参数一样,这些参数均匀地应用于网格的整个表面。例如,如果我们增加材料的属性,物体的整个表面将变得更加粗糙。如果我们将 设置为红色,则整个对象将变为红色。.roughness.color

相比之下,大多数真实世界对象的表面属性从一个点到另一个点会发生变化。考虑一个代表人脸的网格。再一次,它由几何形状和材料组成,就像我们的立方体网格一样。大比例特征(如眼睛、鼻子、耳朵、颈部和下巴)由几何图形定义。然而,要创建逼真的面孔,不仅仅是精心制作的几何图形。仔细观察皮肤,我们可以看到有很多小肿块、皱纹和毛孔,更不用说眉毛、嘴唇和轻微的胡须了。在创建像人脸这样的复杂模型时,艺术家必须决定使用几何图形表示模型的哪些部分,以及在材质级别表示哪些部分,请记住,使用材料表示事物通常比几何图形便宜。当模型必须在移动设备上运行时,这是一个特别重要的考虑因素,因为高性能至关重要。例如,虽然可以在几何形状上对眉毛上的每根头发进行建模,但这样做会使该模型不适合在除最强大的设备之外的所有设备上实时使用。相反,我们必须在材质级别表示头发等小特征,并为眼睛、鼻子和耳朵等大比例特征保留几何图形。

另请注意,此面由单个几何图形组成。我们通常希望避免将几何体拆分得过多,因为每个网格只能有一个几何体,因此每个单独的几何体都对应于场景中的新网格。场景中的对象越少,性能越好,开发人员和 3D 美术师也更容易使用。换句话说,我们不想被迫为耳朵和眼睛创造不同的几何形状。无论如何,这是不切实际的。仔细观察嘴唇,我们可以看到嘴唇的红色和下巴的肤色之间没有明显的区别。这意味着我们需要某种方法来修改材料属性,以便它们可以在物体表面上平滑地变化。我们需要能够这样说:

  • 构成嘴唇的几何形状部分是红色的
  • 构成下巴的几何形状部分是肤色,上面覆盖着轻微的胡须
  • 构成眉毛的几何形状部分是头发颜色的

...等等。这不仅适用于颜色。例如,皮肤比头发和嘴唇更有光泽。因此,我们还需要能够指定其他属性(如粗糙度)如何在几何体中从一个点变化到下一个点。

李-佩里-史密斯-颜色.jpg

此颜色纹理使用 UV 映射映射到面部几何体上

这就是纹理映射的用武之地。用最简单的术语来说,纹理映射意味着拍摄图像并将其拉伸到 3D 对象的表面上。我们将以这种方式使用的图像称为纹理,我们可以使用纹理来表示颜色、粗糙度和不透明度等材质属性。例如,要更改几何体某个区域的颜色,我们将位于顶部的纹理区域的颜色更改为颜色,如附着在面部模型上的颜色纹理所示。

虽然获取 2D 纹理并将其拉伸到像立方体这样的规则形状上很容易,但对于像脸这样的不规则几何体来说,要做到这一点要困难得多,多年来,已经开发了许多纹理映射技术。也许最简单的技术是投影映射,它将纹理投射到物体(或场景)上,就好像它通过电影放映机照射一样。想象一下,把你的手放在电影放映机前,看到图像投射到你的皮肤上。

将 UV 坐标<br>明确写入纹理的测试纹理。

将 UV 坐标显式写入纹理的测试纹理。

虽然投影映射和其他技术仍然广泛用于创建阴影(或模拟投影仪)等操作,但这不适用于将面部的颜色纹理附加到面部几何体上。取而代之的是,我们使用一种称为UV映射的技术,它允许我们在几何体上的点和面上的点之间创建连接。使用UV贴图,我们将纹理划分为带有点的2D网格(0,0)在左下角和点(1,1)在右上角。然后,重点(0. 5,0.5)将位于图像的确切中心。同样,几何体中的每个点在网格的 3D 局部空间中都有一个位置。因此,UV 贴图是将纹理中的 2D 点分配给几何体中的 3D 点的过程。例如,假设面部模型中的嘴唇位于该点(0,0,0 ).我们可以看到纹理中的嘴唇靠近中心,在周围(0. 5,0.5).因此,我们将创建一个映射:

(0. 5,0.5)⟶(0,0,0 )

现在,当我们将纹理指定为材质中的颜色映射表时,纹理的中心将映射到嘴唇上。接下来,我们必须对几何体中的许多其他点执行相同的操作,将耳朵、眼睛、眉毛、鼻子和下巴分配给纹理的适当点。如果这听起来像是一个令人生畏的过程,请不要担心,因为手动执行此操作很少见。对于此模型,UV 贴图是在外部程序中创建的,通常,这是创建 UV 贴图的推荐方法。

表示UV贴图的数据存储在几何体上。像 这样的Three.js几何体已经设置了UV贴图,在大多数情况下,当您加载在外部程序中创建的模型(如面)时,它也将准备好UV贴图以供使用。在本章的后面,我们将更详细地探讨盒子几何体的UV贴图,并将黑白测试纹理分配给盒子网格。BoxBufferGeometry

一旦我们有了带有UV贴图的几何体,我们就可以获取任何纹理并将其应用于几何体,它就会立即起作用。但是,可能很难找到其他纹理在面部模型中看起来不错,因为必须仔细协调UV贴图才能将纹理与面部上的正确点相匹配,而做好这项工作是熟练的3D艺术家的工作。但是,对于像立方体这样的简单形状,我们可以使用几乎任何图像作为纹理,将盒子变成木箱、混凝土箱或板条箱,等等。

可以存储在纹理中的数据类型

在本章中,我们将重点介绍如何使用纹理来表示颜色。我们将获取 uv-test-bw.png 纹理,您可以在编辑器的 /assets/textures/ 文件夹中找到它,并将其拉伸到我们的立方体上。当我们这样做时,默认情况下,three.js 会在立方体的每个面上拉伸一个纹理副本,总共六个副本。

在计算机图形学的早期,纹理仅用于存储对象的颜色。然而,如今,纹理可用于存储各种数据,例如颜色、凹凸、不透明度、表面上的小阴影(称为环境光遮蔽)、照明、金属度和粗糙度,仅举几例。例如,不同的材质接受不同种类和组合的纹理,因此 不接受所有相同的纹理。我们将在本书后面更详细地介绍可以存储在纹理中的数据类型。MeshBasicMaterialMeshStandardMaterial

纹理类型

uv-test-bw.png 是一个以 PNG 格式存储的普通 2D 图像文件,下面,我们将使用 加载它,它将返回 Texture 类的实例。您可以以相同的方式使用浏览器支持的任何图像格式,例如 PNG、JPG、GIF、BMP。这是我们将遇到的最常见和最简单的纹理类型:存储在简单 2D 图像文件中的数据。TextureLoader

还有用于 HDR、EXR 和 TGA 等专用图像格式的加载器,它们具有相应的加载器,如 TGALoader。同样,一旦加载,我们将得到一个实例,我们可以以与加载的PNG或JPG图像大致相同的方式使用它。Texture

除此之外,three.js 还支持许多其他类型的纹理,这些纹理不是简单的 2D 图像,例如视频纹理、3D 纹理、画布纹理、压缩纹理、立方体纹理、等距柱状投影纹理等。同样,我们将在本书后面更详细地探讨这些内容。在本章的其余部分,我们将重点介绍以 PNG 或 JPG 格式存储的 2D 纹理。

Texture类

该类是 HTML 图像元素的包装器,其中包含一些与用作纹理而不是普通图像相关的额外设置。我们可以在 下访问原始图像。它是我们在处理纹理时最常用的类,尽管有几个派生类(如 VideoTexture 或 CubeTexture)用于处理其他类型的纹理。不过,通常我们不会直接创建一个,因为会自动为我们创建一个,我们将在下面看到。Textureimage.textureTextureTextureLoader

通过纹理类提供的设置示例包括 和 ,它们控制纹理到达边缘时的换行方式(例如,它是重复、简单地停止,还是将纹理的边缘拉伸到网格的边缘?我们还可以指定各种过滤(using 和 )来控制在远处或近距离看到纹理时的过滤方式。换句话说,这些设置控制用于放大或缩小图像的算法。.wrapS.wrapT.minFilter.magFilter

还有几个属性,如 ,,允许我们控制纹理的位置。另外两个重要设置是 ,它沿.offsetcenter.rotation.flipYY-axis(用于与在某些外部程序中创建的模型兼容)和属性,正如我们稍后将看到的,必须正确设置该属性才能获得最佳结果。.encoding

花几分钟时间浏览文档页面,并查看使用纹理时可用的选项。我们将在本书后面更详细地探讨其中的大多数。

创建纹理

有许多方法可以准备图像以用作纹理,但最简单的方法是拍摄对象的照片。例如,如果您拍摄了一张砖墙的照片并将其分配给材质的颜色槽,您将在场景中看到与 3D 墙的相似性。我们可以通过使用原始图像为其他材质属性(如凹凸或粗糙度)创建额外的纹理来改进这一点。在 freepbr.com 上查看这组纹理,以作个例子(选择虚幻引擎版本用于Three.js,请注意反照率颜色的另一个术语)。我们将在本书的后面部分探索使用一组这样的纹理来创建逼真的材质。

虽然拍摄平坦墙壁的照片是一件简单的事情,但像脸、树或兔子这样的曲面会带来更大的挑战。对于这样的表面,艺术家必须拼合照片,并将拼合图像中的每个点连接到 3D 模型上的相应点,再次使用 UV 贴图。这通常是在外部建模程序中完成的,而不是在 three.js 中完成的。

对于砖墙和木地板等常见表面,您可以在网络上找到高质量的纹理集(如上图),其中许多是免费的。在本书中,我们将使用来自Three.js存储库和 freepbr.com 或 Quixel megascan 等站点的纹理。

纹理术语

在继续加载纹理并将其应用于立方体之前,让我们回顾一下在处理纹理时将使用的所有技术术语。

图像和纹理有什么区别?

您会在计算机图形学文献中看到很多术语纹理图像。这些甚至通常以相同的格式存储,例如 PNG 或 JPG。有什么区别?

  • 图像是设计供人类查看的 2D 图片。
  • 纹理是专门准备的数据,用于 3D 图形中的各种目的

构成图像的各个像素表示颜色。另一种看待这个问题的方式是,图像是一个二维的颜色数组。在计算机图形学的早期,纹理也是如此,但随着时间的推移,纹理的用途越来越多,现在更正确的说法是纹理是数据的二维数组。此数据可以表示任何内容。如今,甚至可以将几何图形或动画存储在纹理中。

当纹理以 PNG 或 JPG 等图像格式存储时,我们可以在任何图像查看器中打开它。在本章中,我们将加载的纹理表示颜色数据,因此如果我们在查看器中打开它,它将看起来像图像。但是,用于其他目的的纹理(例如凹凸贴图、不透明度贴图、光照贴图等)通常看起来不像任何特别的东西,直到它们被应用于材质并由渲染器解释。

纹理贴图

虽然在技术上不正确,但纹理通常也被称为贴图,甚至是纹理贴图,尽管贴图在为材质分配纹理时最常用。当使用纹理来表示颜色时,我们会说我们正在将纹理分配给材质上的颜色映射表槽。下面,我们将向您展示如何将 uv-test-bw.png 纹理分配给 .MeshStandardMaterial

Pixel 和 Texel

数字图像是像素的 2D 数组,每个像素都是一个包含单一颜色的小点。我们的屏幕也由一个由小点组成的 2D 数组组成,每个小点都显示一种颜色,我们也称这些像素为像素。然而,构成屏幕的像素是实际的物理对象,LED或OLED或其他一些高科技设备,而构成图像的像素只是存储在文件中的数字。

为了避免混淆,我们将继续将构成屏幕像素的点称为,但我们将构成纹理的点称为纹素

UV映射

UV 贴图是一种将 2 维纹理映射到 3 维几何体上的方法。想象一下纹理顶部的 2D 坐标系,其中(0,0)在左下角和(1,1)在右上角。由于我们已经使用了字母X,Y和Z对于我们的 3D 坐标,我们将使用字母来指代 2D 纹理坐标U和V.这就是UV贴图这个名字的由来。

以下是UV贴图中使用的公式:

( u,v)⟶(x,y,z)

(u,v)表示纹理上的一个点,并且(x,y,z)表示几何体上的一个点,在局部空间中定义。从技术上讲,几何体上的点称为顶点

UV 将纹理映射到“BoxBufferGeometry”上
UV 将纹理映射到BoxBufferGeometry

在上图中,纹理的左上角已映射到具有坐标的立方体角上的顶点(−1,1,1):

( 0,1)⟶(−1,1,1)

对立方体的其他五个面进行了类似的映射,从而在立方体的六个面中的每一个面上都生成一个完整的纹理副本:

请注意,该点没有映射(0. 5,0.5),纹理的中心。只有纹理的角被映射到立方体的八个角上,其余的点都是从这些角中“猜测”出来的。相比之下,像人脸这样的复杂模型必须定义更多的UV坐标,才能将表示鼻子、耳朵、眼睛、嘴唇等的纹理部分映射到几何体的正确点。

一旦我们更深入地了解了几何体的工作原理,我们将在本书的后面回到UV贴图。幸运的是,我们很少需要手动设置 UV 贴图,因为所有Three.js 几何体(包括 )都内置了 UV 贴图。我们只需要加载纹理并将其应用到我们的材料上,一切都会起作用。BoxBufferGeometry

在本章的其余部分,我们将向您展示如何做到这一点。

重要提示:从现在开始,如果您在本地工作, 则需要设置一个 Web 服务器,否则,由于浏览器安全限制,您将无法加载纹理。

对于使用内联代码编辑器的每个人来说,一切照旧。让我们继续前进。

班级Texture

该类是 HTML 图像元素的包装器,其中包含一些与用作纹理而不是普通图像相关的额外设置。Texture

加载纹理

现在我们已经掌握了所有的理论,加载纹理并将其应用于我们的立方体很简单。我们在本章中添加的所有代码都将进入 cube.js 模块。我们将使用 three.js TextureLoader 类来加载纹理,因此请添加到 cube.js 顶部的导入列表中:TextureLoader

cube.js:导入TextureLoader

import {BoxBufferGeometry,MathUtils,Mesh,MeshStandardMaterial,TextureLoader,
} from 'three';

将材料设置移动到单独的功能中

为了防止函数变得太大,让我们将材质创建移动到一个新函数中:createCube

cube.js:将材质设置移动到新函数中

function createMaterial() {
// create a "standard" material
const material = new MeshStandardMaterial({ color: 'purple' });return material;
}function createCube() {
const geometry = new BoxBufferGeometry(2, 2, 2);const material = createMaterial();const cube = new Mesh(geometry, material);...
}

创建实例TextureLoader

接下来,在新函数的顶部创建一个新实例:TextureLoadercreateMaterial

cube.js:创建纹理加载器实例

function createMaterial() {
// create a texture loader.
const textureLoader = new TextureLoader();// create a "standard" material using
const material = new MeshStandardMaterial({ color: 'purple' });return material;
}

用于加载纹理TextureLoader.load

TextureLoader.load 方法可以加载任何标准图像格式的纹理,例如 PNG、JPEG、GIF、BMP 等。在这里,我们将从 assets/textures 文件夹中加载 uv-test-bw.png 文件:

cube.js:加载纹理

function createMaterial() {
// create a texture loader.
const textureLoader = new TextureLoader();// load a texture
const texture = textureLoader.load(
'/assets/textures/uv-test-bw.png',
);// create a "standard" material using
const material = new MeshStandardMaterial({ color: 'purple' });return material;
}

当我们调用时,会发生一些有趣的事情。即使加载纹理需要一些时间(可能几百毫秒),也会立即返回 Texture 类的实例。上面,我们将其存储在一个名为 ..loadTextureLoadertexture

我们可以立即使用这个空,甚至在图像完成加载之前。但是,在图像数据完全加载之前,纹理将显示为黑色。换句话说,如果我们将此纹理分配给材质的颜色映射表插槽,则该材质将在场景中显示为黑色,直到纹理完成加载。texture

加载完成后,将自动插入正确的图像,并且材料的颜色将从黑色变为图像中的任何颜色。如果互联网连接速度较慢,此过程将尤为明显。如果使用内联编辑器更新场景,则可能会看到这种情况发生,尽管图像数据应在几分之一秒内加载。您可能希望避免在场景中显示黑色网格,在这种情况下,您可以等到所有纹理加载完毕后再渲染场景。我们将在本书的后面部分探讨您的选择。TextureLoader

将纹理分配给材质的色彩映射表插槽

以前,我们使用 .color 属性设置材质的颜色。在这里,我们将 material.map 属性分配给 material.map 属性,该属性描述了颜色在对象表面上的变化情况。 应该命名,但是,由于它经常使用,因此为了方便起见,因此将其缩短。texture.map.colorMap

通常,我们设置 .color 或 .map,但不能同时设置两者。如果我们同时设置了两者,纹理中的颜色将以属性。例如,如果我们保持紫色,这种黑白纹理将获得紫色调。这里的一个常见用例是将颜色设置为灰色阴影以使纹理变暗。由于白色是默认颜色,因此设置为白色不会对纹理产生影响。因此,无法用于减轻质地。你只能让它变暗。.color.color.color

与 color 参数一样,我们可以将纹理传递到材质的构造函数中:

在构造函数中将纹理分配给材质

const material = new MeshStandardMaterial({
map: texture,
});

或者,我们可以在创建材质后设置:.map

创建材质后分配纹理

const material = new MeshStandardMaterial();material.map = texture;

我们将在这里使用第一种方法。再次更新:createMaterial

cube.js:将纹理分配给材质的颜色映射表插槽

function createMaterial() {// create a texture loader.const textureLoader = new TextureLoader();// load a textureconst texture = textureLoader.load('/assets/textures/uv-test-bw.png',);// create a "standard" material using// the texture we just loaded as a color mapconst material = new MeshStandardMaterial({map: texture,});return material;
}

现在,您的场景将更新,您应该看到纹理映射到立方体的六个面中的每一个面上。

纹理有六个副本,立方体的每个面一个。特别注意拐角处发生的事情。

在上面的场景中,您可以使用鼠标或触摸旋转立方体。实际上,移动的是摄像机,而不是立方体,因为我们在这个场景中添加了一个摄像机控制插件。这个插件允许您平移、旋转和缩放/推车相机以从任何角度查看场景,这非常适合我们设置场景并想要仔细观察所有内容。在下一章中,我们将把这个插件添加到我们的应用程序中。

转载:Three.js 纹理贴图的实现 (mvrlink.com)

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

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

相关文章

IP定位应对恶意IP攻击:保护网络安全的新策略

随着网络攻击的日益猖獗&#xff0c;恶意IP攻击成为网络安全领域的一大挑战。传统的安全防护手段在应对此类攻击时显得力不从心。近年来&#xff0c;通过IP定位这一新技术&#xff0c;为应对恶意IP攻击提供了新的解决思路。 IP定位技术通过分析网络流量中的IP地址&#xff0c;能…

如何创建VPC并配置安全组以保护您的阿里云服务器

将您的基础架构放在云上意味着您可以接触到全球的许多人。但是&#xff0c;这也意味着不怀好意的人可以访问您的服务。保护您的云网络非常重要。阿里云提供虚拟专用网络 &#xff08;VPC&#xff09;&#xff0c;这是一个安全隔离的私有云&#xff0c;将您的弹性计算服务 &…

用Python来制作一个微信聊天机器人

1. 效果展示 通过本地搭建一个flask服务器来接收信息&#xff0c;这里我简单使用展示&#xff0c;就没有对接收的信息进行处理了。 信息接收展示 发送信息展示 这里就直接使用python发送一个post请求即可&#xff0c;可以发送文字或者图片 代码展示 接收信息 #!/usr/bin/e…

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch00-2(4) 质量刚体的在坐标系下运动

本文仅供学习使用&#xff0c;总结很多本现有讲述运动学或动力学书籍后的总结&#xff0c;从矢量的角度进行分析&#xff0c;方法比较传统&#xff0c;但更易理解&#xff0c;并且现有的看似抽象方法&#xff0c;两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有…

C++的一些书籍整理(个人学习)

UNIX环境高级编程&#xff08;第三版&#xff09; UNXI网络编程卷1 网络编程的笔记 收藏 我会了 一堆书 这个仓 数据库连接池原理介绍常用连接池介绍

《More Effective C++》学习

条款1&#xff1a;仔细区别 pointers 和 references 引用应该被初始化&#xff0c;指针可以不被初始化。不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。因为在使用引用之前不需要测试它的合法性。指针与引用的另一个重要的不同是指针可以被重新赋值…

mac环境桌面版docker错误修改daemon.json配置后,启动失败,一直卡在Docker Engine starting界面的解决方法

如下图&#xff1a;当桌面版docker的配置被错误的修改后&#xff0c;配置修改重启应用时&#xff0c;会一直卡在启动界面 此时需要找到mac下该桌面版docker的配置文件位置&#xff0c;手动修改恢复&#xff0c;然后重启应用。 daemon.json文件一般默认在隐藏文件夹下&#xff0…

SSL证书安装在哪?

安装SSL证书的具体步骤取决于你使用的服务器软件和操作系统。一般来说&#xff0c;SSL证书通常用于加密网站上的数据传输&#xff0c;因此安装过程主要涉及到Web服务器的配置。以下是一般步骤&#xff0c;但请注意这可能因你的具体环境而异。 永久免费SSL证书_永久免费https证…

一天一个设计模式---单例模式

概念 单例模式是一种创建型设计模式&#xff0c;其主要目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点。这意味着在应用程序中的任何地方&#xff0c;只能有一个实例存在&#xff0c;而不会创建多个相同类型的实例。 具体内容 单例模式通常包括以下几个要素…

Pytorch种torch.cat与torch.stack的区别

torch.cat 和 torch.stack 是 PyTorch 中用于拼接张量的两个不同的函数&#xff0c;它们的主要区别在于拼接的方式和创建的维度。 torch.cat&#xff1a; 拼接方式&#xff1a; torch.cat 是按照给定的维度&#xff08;dim 参数&#xff09;将多个张量沿着该维度拼接。在拼接的…

Unity 利用UGUI之Slider制作进度条

在Unity中使用Slider和Text组件可以制作简单的进度条。 首先在场景中右键->UI->Slider&#xff0c;新建一个Slider组件&#xff1a; 同样方法新建一个Text组件&#xff0c;最终如图&#xff1a; 创建一个进度模拟脚本&#xff0c;Slider_Progressbar.cs using System.C…

矿泉水除硝酸盐的方法分析

摘要&#xff1a;饮用水中的硝酸盐污染已成为全球性问题&#xff0c;对人类健康构成威胁。本文将介绍离子交换树脂技术在饮用水除硝酸盐方面的应用与优势&#xff0c;帮助您了解如何有效去除饮用水中的硝酸盐&#xff0c;保障水质安全。 正文&#xff1a; 一、饮用水中硝酸盐…

使用kubesphere的devops部署SpringCloud项目

devops部署SpringCloud项目 环境说明部署流程创建DevOps工程填写流水线信息创建流水线jenkinsfileDockerfiledeploy.yaml 环境说明 已经安装kubesphere的devops组件安装教程可参考官方文档:https://v3-1.docs.kubesphere.io/zh/docs/pluggable-components/devops/ 部署流程 创…

redis 从0到1完整学习 (十六):内存回收之 key 过期处理策略

文章目录 1. 引言2. redis 源码下载3. redisDb 结构体4. Redis 过期 key 的处理策略4.1 惰性删除 (Lazy Expiration)4.2 定期删除 (Active Expire / Periodic Expiration)* 5. 参考 1. 引言 前情提要&#xff1a; 《redis 从0到1完整学习 &#xff08;一&#xff09;&#xff…

Lumerical Monitors------frequency domain power monitor 频率域功率监视器

frequency domain power monitor 频率域功率监视器 引言正文引言 这里给大家介绍一下 frequency domain power monitor。 正文 首先,我们可以通过以下方式添加 frequency domain power monitor 到我们的工程文件中: 在 general tab 中,有一个共同的监视器设置 simulati…

苍穹外卖Day01——总结1

总结1 1. 软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境 2. 苍穹外卖项目介绍2.1 项目介绍2.2 技术选项 3. Swagger4. 补充内容&#xff08;待解决...&#xff09; 1. 软件开发整体介绍 1.1 软件开发流程 1.2 角色分工 从角色分工里面就可以查看自己以后从事哪一…

跨国制造业组网方案解析,如何实现总部-分支稳定互联?

既要控制成本&#xff0c;又要稳定高效&#xff0c;可能吗&#xff1f; 在制造企业积极向“智造”发展、数字化转型的当下&#xff0c;物联网、人工智能、机器人等新型设备加入到生产、管理环节&#xff0c;为企业内部数据传输提出了更高的要求。而当企业规模扩大&#xff0c;数…

记录一次接近24万条数据导入Mysql的过程

由于开发项目的需求&#xff0c;之前有部分数据要写入阿里云的表格存储&#xff0c;过了一年多时间&#xff0c;表A的数据量接近24万条&#xff0c;现在需要将表A的数据转到Mysql中。 利用官方工具导出数据后&#xff0c;发现文件里面有238999条数据&#xff0c;文件大小是460…

Unity中URP下深度图的线性转化

文章目录 前言一、_ZBufferParams参数有两组值二、LinearEyeDepth1、使用2、Unity源码推导&#xff1a;3、使用矩阵推导&#xff1a; 三、Linear01Depth1、使用2、Unity源码推导3、数学推导&#xff1a; 前言 在之前的文章中&#xff0c;我们实现了对深度图的使用。因为&#…

C语言中常用的字符串函数(strlen、sizeof、sscanf、sprintf、strcpy)

C语言中常用的字符串函数 文章目录 C语言中常用的字符串函数1 strlen函数2 sizeof函数2.1 sizeof介绍2.2 sizeof用法 3 sscanf函数3.1 sscanf介绍3.2 sscanf用法3.3 sscanf高级用法 4 sprintf函数4.1 背景4.2 sprintf用法 5 strcpy函数5.1 strcpy介绍5.1 strcpy用法 1 strlen函…