✺ch5——纹理贴图

目录

    • 加载纹理图像文件
    • 纹理坐标
    • 在着色器中使用纹理:采样器变量和纹理单元
    • 纹理贴图:示例程序
    • 多级渐远纹理贴图
    • 各向异性过滤
    • 环绕和平铺
    • 透视变形
    • 材质——更多OpenGL细节
    • 补充说明

纹理贴图是在栅格化的模型表面上覆盖图像的技术。 它是为渲染场景添加真实感的最基本和最重要的方法之一。

纹理贴图非常重要,因此硬件也为它提供了支持,使得它具备实现实时的照片级真实感的超高性能。纹理单元是专为纹理设计的硬件组件,现代显卡通常带有数个纹理单元。

加载纹理图像文件

为了在 OpenGL/GLSL 中有效地完成纹理贴图,需要协调好以下几个不同的数据集和机制:

  • 用于保存纹理图像的纹理对象(在本章中我们仅考虑 2D 图像);
  • 特殊的统一采样器变量,以便顶点着色器访问纹理;
  • 用于保存纹理坐标的缓冲区;
  • 用于将纹理坐标传递给管线的顶点属性;
  • 显卡上的纹理单元。

图像通常存储在图像文件中,例如.jpg、.png、.gif 或.tiff 文件。为了使纹理图像用于 OpenGL 管线中的着色器, 我们需要从图像中提取颜色并将它们放入 OpenGL 纹理对象(用于保存纹理图像的内置 OpenGL 结构)中。

许多 C++ 库可用于读取和处理图像文件,常见的选择包括 Cimg 、 BoostGIL 和 Magick++。我们选择使用专为 OpenGL 设计的 SOIL2 库。

通常,将纹理加载到 OpenGL 应用程序的步骤是:
(a)使用 SOIL2 实例化 OpenGL 纹理对象并从图像文件中读入数据;
(b)调用 glBindTexture() 以使新创建的纹理对象处于激活状态;
(c)使用 glTexParameter() 函数调整纹理设置。
最终得到的结果就是现在可用的 OpenGL 纹理对象的整型 ID。

GLuint loadTexture(const char* texImagePath) {GLuint textureID;textureID = SOIL_load_OGL_texture(texImagePath, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);if (textureID == 0)cout << "Could not find texture file:" << texImagePath << endl;return textureID;
}

纹理坐标

现在我们已经有了将纹理图像加载到 OpenGL 中的方法, 需要指定希望如何将纹理应用于对象的渲染表面。我们通过为模型中的每个顶点指定纹理坐标来完成此操作。

纹理坐标是对纹理图像(通常是 2D 图像)中的像素的引用。纹理图像中的像素被称为纹元(texel),以便将它们与在屏幕上呈现的像素区分开。纹理坐标用于将 3D 模型上的点映射到纹理中的位置。除了将它定位在 3D 空间中的坐标(x,y,z)之外,模型表面上的每个点还具有纹理坐标(s,t), 用来指定纹理图像中的哪个纹元为它提供颜色。 因此,我们将设置两个缓冲区,一个用于顶点坐标(每个条目中有 3 个分量,即 x、 y 和 z),另一个用于相应的纹理坐标(每个条目中有两个分量,即 s 和 t)。这样,每次顶点着色器的调用会接收到一个顶点的数据,包括其空间坐标和相应的纹理坐标。

2D 纹理图像被设定为矩形,左下角的位置坐标为(0,0),右上角的位置坐标为(1,1)。理想情况下,纹理坐标应该在[0, 1]区间内取值。

纹理坐标(由 s 和 t 描述)将图像的部分(纹元)映射到模型正面的栅格化像素上。顶点之间的所有中间像素都已使用图像中间插值的纹元进行绘制。这正是因为纹理坐标在顶点属性中被发送到片段着色器,从而也像顶点本身一样被插值。

下面我们渲染四棱锥,只是这次用砖的图像添加纹理。我们需要指定:
(a)引用纹理图像的整型 ID;
(b)模型顶点的纹理坐标;
(c)用于保存纹理坐标的缓冲区;
(d)顶点属性,以便顶点着色器接收并通过管线转发纹理坐标;
(e)显卡上用于保存纹理对象的纹理单元;
(f)用于访问 GLSL 中纹理单元的统一采样器变量。

在着色器中使用纹理:采样器变量和纹理单元

为了最大限度地提高性能,我们希望在硬件中执行纹理处理。这意味着片段着色器需要一种访问我们在 C++/OpenGL 应用程序中创建的纹理对象的方法。它的实现机制是通过一个叫作统一采样器变量的特殊 GLSL 工具。这是一个变量,用于指示显卡上的纹理单元,从加载的纹理对象中提取或“采样”纹元。

layout(binding = 0) uniform sampler2D samp;

我们声明的变量叫作 samp。声明的 layout(binding=0)部分指定此采样器与第 0 个纹理单元关联。

纹理单元(和相关的采样器)可以对我们希望的任何纹理对象进行采样,也可以在运行时更改。 display()函数需要指定纹理单元要为当前帧采样的纹理对象。因此,每次绘制对象时,都需要激活纹理单元并将其绑定到特定的纹理对象,例如:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, brickTexture);

可用纹理单元的数量取决于显卡提供的数量。根据 OpenGL API 文档, OpenGL 4.5 要求每个着色器阶段至少有 16 个单元,所有阶段总共至少有 80 个单元。在这个例子中,我们通过在 glActiveTexture() 调用中指定 GL_TEXTURE0,使得第 0 个纹理单元处于激活状态。

要实际执行纹理处理,我们需要修改片段着色器输出颜色的方式。以前,我们的片段着色器要么输出一个固定的颜色常量,要么从顶点属性获取颜色,而这次我们需要使用从顶点着色器(通过光栅着色器)接收的插值纹理坐标来对纹理对象进行采样。调用 texture()函数如下:

in vec2 tc;// 输入插值过的纹理坐标
...
color = texture(samp, tc);

纹理贴图:示例程序

...
GLuint brickTexture;void setupVertices(void) {float pyramidPositions[54] ={ -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f,    //front1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f,    //right1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f,  //back-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f,  //left-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, //LF1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f  //RR};float textureCoordinates[36] ={ 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f};glGenVertexArrays(1, vao);glBindVertexArray(vao[0]);glGenBuffers(numVBOs, vbo);glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);glBufferData(GL_ARRAY_BUFFER, sizeof(pyramidPositions), pyramidPositions, GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoordinates), textureCoordinates, GL_STATIC_DRAW);
}void init(GLFWwindow* window) {...brickTexture = Utils::loadTexture("brick1.jpg");
}void display(GLFWwindow* window, double currentTime) {glClear(GL_DEPTH_BUFFER_BIT);glClearColor(0.0, 0.0, 0.0, 1.0);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(renderingProgram);mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));mMat = glm::translate(glm::mat4(1.0f), glm::vec3(pyrLocX, pyrLocY, pyrLocZ));mMat = glm::rotate(mMat, -0.45f, glm::vec3(1.0f, 0.0f, 0.0f));mMat = glm::rotate(mMat,  0.61f, glm::vec3(0.0f, 1.0f, 0.0f));mMat = glm::rotate(mMat,  0.00f, glm::vec3(0.0f, 0.0f, 1.0f));mvMat = vMat * mMat;glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(1);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, brickTexture);glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);glDrawArrays(GL_TRIANGLES, 0, 18);
}

顶点着色器:

#version 430layout (location=0) in vec3 pos;
layout (location=1) in vec2 texCoord;
out vec2 tc;uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp;void main(void) {gl_Position = proj_matrix * mv_matrix * vec4(pos,1.0);tc = texCoord;
} 

片段着色器:

#version 430in vec2 tc;
out vec4 color;layout(binding = 0) uniform sampler2D samp;void main(void) {color = texture(samp, tc);
}

多级渐远纹理贴图




多级渐远纹理贴图通过一种巧妙的机制来工作, 它在纹理图像中存储相同图像的连续的一系列较低分辨率的副本,所用的纹理图像比原始图像大 1/3,其中图像的 RGB 值分别存储在纹理图像空间的 3 个 1/4 区域中来实现的。剩余的 1/4 区域中迭代地将图像分辨率设置为原来的 1/4,直到剩余区域太小而不包含任何有用的图像数据。示例图像和生成的多级渐远纹理的可视化如下图所示。

这种将几个图像填充到一个小空间中的方法(只比存储原始图像所需的空间大一点)是 mipmapping 得名的原因。 mip 代表拉丁语 multumin parvo,意思是“在很小的空间里有很多东西”。

实际给对象添加纹理时,可以通过多种方法对多级渐远纹理进行采样。在 OpenGL 中,可以通过将 GL_TEXTURE_MIN_FILTER 参数设置为所需的缩小方法来选择多级渐远纹理的采样方法,可以选取以下方法之一:

  • GL_NEAREST_MIPMAP_NEAREST:选择具有与纹元区域最相似的分辨率的多级渐远纹理。然后,它获得所需纹理坐标的最近纹元。
  • GL_LINEAR_MIPMAP_NEAREST:选择具有与纹元区域最相似的分辨率的多级渐远纹理。然后,它取最接近纹理坐标的 4 个纹元的插值。这被称为“线性过滤”。
  • GL_NEAREST_MIPMAP_LINEAR:选择具有与纹元区域最相似的分辨率的 2 个多级渐远纹理。然后,它从每个多级渐远纹理获取纹理坐标的最近纹元并对其进行插值。这被称为“双线性过滤”。
  • GL_LINEAR_MIPMAP_LINEAR: 选择具有与纹元区域最相似的分辨率的 2 个多级渐远纹理。然后,它取各自最接近纹理坐标的 4 个纹元,并计算插值。这被称为“三线性过滤”。

三线性过滤通常是比较好的选择,因为较低的混合级别通常会产生伪影。

OpenGL 提供了丰富的多级渐远纹理支持,其中一些机制可用于构建你自己的多级渐远纹理级别,另一些机制可以让 OpenGL 为你构建它们。在大多数情况下, OpenGL 自动构建的多级渐远纹理已足够。这是通过将以下代码行添加进紧跟 getTextureObject()函数的 Utils::loadTexture()函数来实现的:

glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);

上述代码用于通知 OpenGL 生成多级渐远纹理。 glBindTexture()调用激活砖纹理,然后glTexParameteri()函数调用启用前面列出的缩小方法之一,此处为 GL_LINEAR_ MIPMAP_LINEAR,即三线性过滤。

构建多级渐远纹理后,可以在 display()函数中或其他位置再次调用 glTexParameteri()来更改过滤选项(尽管很少有需要这样做的情况),甚至通过选择 GL_NEAREST 或 GL_LINEAR 来禁用多级渐远纹理。

各向异性过滤

多级渐远纹理贴图有时看起来比非多级渐远纹理贴图更模糊, 尤其是当被贴图对象以严重倾斜的视角渲染时。使用多级渐远纹理贴图在减少伪影的同时也损失了图像细节。

这种细节的丢失是因为当物体倾斜时,其图元看起来在一个轴(即沿宽或高)上的尺寸比在另一个轴上更小。当 OpenGL 为图元贴图时,它选择适合两个轴中尺寸较小的轴的多级渐远纹理(以避免“闪烁”伪影)。表面远离观察者倾斜,因此每个渲染图元将使用适合其更小尺寸(即高度)的多级渐远纹理,对其宽度来说,这个分辨率似乎太小了。

一种恢复一些丢失细节的方法是使用各向异性过滤(Anisotropic Filtering,AF)。标准的多级渐远纹理贴图以各种正方形分辨率(如 256 像素×256 像素、 128 像素×128 像素等)对纹理图像进行采样,而各向异性过滤却以多种矩形分辨率对纹理进行采样(如 256 像素×128 像素、 64 像素×128 像素等)。这使得从各种角度观看的纹理都保留尽可能多的细节成为可能。

各向异性过滤比标准多级渐远纹理贴图的计算代价更高,并且不是 OpenGL 的必需部分。但是,大多数显卡都支持各向异性过滤(称为 OpenGL 扩展),而 OpenGL 也确实提供了一种查询显卡是否支持各向异性过滤的方法,以及一种访问各向异性过滤的方法,只需在生成多级渐远纹理贴图后立即添加代码:

...
// 如果使用多级渐远纹理贴图
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
// 如果还使用各向异性过滤
if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) {GLfloat anisoSetting = 0.0f;glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisoSetting);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoSetting);
}

对 glewIsSupported()进行调用可以测试显卡是否支持各向异性过滤。如果支持,我们将其设置为支持的最
大采样程度,这个最大值通过 glGetFloatv()获取。使用glTexParameterf()可以将其应用于激活纹理对象,结果如下图所示。请注意,丢失的大部分细节已经恢复,同时我们仍然消除了闪烁的伪影。

环绕和平铺

到目前为止,我们假设纹理坐标都落在[0, 1]区间。但是, OpenGL 实际上支持任何取值范围的纹理坐标。有几个选项可以用来指定当纹理坐标超出[0, 1]区间时会发生什么,可以使用glTexParameteri()设置。这些选项如下:

  • GL_REPEAT:重复,即忽略纹理坐标的整数部分,生成重复或“平铺”图案。这是默认行为。
  • GL_MIRRORED_REPEAT:镜像重复,即忽略纹理坐标的整数部分,但是当整数部分为奇数时反转坐标,因此重复的图案在原图案和其镜像图案之间交替。
  • GL_CLAMP_TO_EDGE: 夹紧到边缘, 即将小于 0 的坐标和大于 1 的坐标分别设置为 0 和 1。
  • GL_CLAMP_TO_BORDER: 夹紧到边框, 即将[0, 1]以外的纹元设置成指定的边框颜色。

例如,考虑一个使用图 5.2 中纹理图像的四棱锥,其纹理坐标区间已达[0, 5],而不是通常
的[0, 1]。默认行为(即 GL_REPEAT)会导致纹理在表面上重复(有时称为“平铺”),如图 5.17
所示。

为了使平铺块的外观在原图案和其镜像之间交替,我们可以指定以下内容:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

可以按如下方式来将小于 0 或大于 1 的值设定为指定颜色:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
float redColor[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, redColor);

下图中分别(从左到右)显示了重复、镜像重复、夹紧到边缘和夹紧到边框的效果,其中四棱锥的纹理坐标取值范围为−2~+3:

透视变形

考虑一个由两个三角形组成的矩形,纹理贴图是棋盘图样,面向相机。当矩形围绕 x 轴旋转时,矩形的顶部会倾斜并远离相机,而矩形的下半部分则更靠近相机。因此,我们希望顶部的方块变小,底部的方块变大。但是,纹理坐标的线性插值将导致所有正方形的高度相等。沿着构成矩形的两个三角形接缝处的对角线加剧失真。产生的失真如下图所示。

幸运的是,存在用于校正透视失真的算法,并且默认情况下, OpenGL 在栅格化期间会应用透视校正算法。

可以通过在包含纹理坐标的顶点属性的声明中添加关键字“noperspective”来禁用 OpenGL 的透视校正,虽然这样做并不常见。顶点着色器和片段着色器中都需要这样添加关键字。例如,顶点着色器中的顶点属性将声明如下:

noperspective out vec2 texCoord;

片段着色器中的相应属性声明为:

noperspective in vec2 texCoord;

实际上,上图中的扭曲的棋盘图样就使用了这种语法来生成图的。

材质——更多OpenGL细节

我们使用的 SOIL2 纹理图像加载库具有相对简单和直观的优点。但是,在学习 OpenGL 时,使用 SOIL2 会产生一项我们不想要的后果,即用户会接触不到一些有用的重要OpenGL 细节。在本节中,我们将描述程序员在没有纹理加载库(如 SOIL2)的情况下加载和使用纹理时需要了解的一些细节。

可以使用 C++和 OpenGL 函数直接将纹理图像文件数据加载到 OpenGL 中。这虽然有点儿复杂,但并不少见。一般步骤如下:
(1)使用 C++ 工具读取图像文件数据;
(2)生成 OpenGL 纹理对象;
(3)将图像文件数据复制到纹理对象中。

我们不会详细描述第一步——有太多方法了。 opengl-tutorials 网站中很好地描述了一种方法,可以使用 C++函数 fopen()和 fread()将数据从.bmp 图像文件读入 unsigned char 类型的数组。

步骤(2)和步骤(3)更通用,主要涉及 OpenGL 调用。在步骤(2)中,我们使用 OpenGL 的glGenTextures()命令创建一个或多个纹理对象。例如,生成单个 OpenGL 纹理对象(使用整型引用 ID)可以按如下方式完成:

GLuint textureID;// 如果需要创建多于一个纹理对象,则使用 GLuint 类型的数组
glGenTextures(1, &textureID);

在步骤(3)中,我们将步骤(1)中的图像文件数据关联到步骤(2)中创建的纹理对象。这是使用 OpenGL 的 glTexImage2D()命令完成的。下面的示例将图像文件数据从步骤(1)中描述的 unsigned char 类型的数组(此处表示为 data)加载到步骤(2)创建的纹理对象中:

glBindTexture(GL_TEXTURE_2D, textureID)
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);

此时,本章前面介绍的用于设置多级渐远纹理贴图等的各种 glTexParameteri()调用也可以应用于纹理对象。

补充说明

研究人员开发了纹理单元的许多用途,不仅仅用于场景中的纹理模型。在后面的章节中,我们将看到如何使用纹理单元来改变物体反射光线,使其看起来凹凸不平。我们还可以使用纹理单元来存储“高度图”以生成地形,以及存储“阴影贴图”以有效地为场景添加阴影。

着色器还可以向纹理写入数据,允许着色器修改纹理图像,甚至将一个纹理的一部分复制到另一个纹理的某个部分。

多级渐远纹理贴图和各向异性过滤不是减少纹理中的叠影、伪影的唯一工具。例如,全屏抗锯齿( Full-Scene Anti-Aliasing, FSAA)和其他超采样方法也可以改善 3D 场景中纹理的外观。它们虽然不是 OpenGL 核心的一部分,但通过 OpenGL 的扩展机制在许多显卡上得到了支持。

还有一种用于配置和管理纹理和采样器的替代机制。 OpenGL 3.3 引入了采样器对象(有时称为“采样器状态”,不要与采样器变量混淆),可用于保存一组独立于实际纹理对象的纹理设置。将采样器对象附加到纹理单元,可以方便、 有效地更改纹理设置。

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

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

相关文章

functools.partial:Python中灵活函数部分应用的工具

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python编程中&#xff0c;functools.partial是一个强大的工具&#xff0c;它提供了一种部分应用函数的方式&#xff0c;能够在创建新函数时固定部分参数&#xff0c;从而在后续调用中减少需要传递的参数数量。…

Python四种配色方案,适合科研的配色

1、Plasma&#xff08;等高线图颜色&#xff09;2、Inferno&#xff08;黑热图颜色&#xff09;3、Cividis&#xff08;较好的配色方案&#xff0c;适用于色盲&#xff09;4、Viridis&#xff08;绿色主导的配色方案&#xff09; 下面这四种配色是不需要指定的&#xff0c;Pyth…

element组件库的日期选择器如何限制?

本次项目中涉及到根据日期查找出来的数据进行调整,所以修改的数据必须是查找范围内的数据.需要对调整数据的日期进行限制,效果如下: 首先我们使用了element 组件库的日期选择器,其中灌完介绍, picker-options中函数disabledDate可以设置禁用状态,代码如下: <el-date-pickerv…

关于GPU使用过程中的若干问题

1.CUDA异常 问题描述&#xff1a;运行torch.cuda.is_available() 报错&#xff1a;cuda unknown error - this may be due to an incorrectly set up environment解决方案&#xff1a;重启 2.nvidia驱动版本不匹配 问题描述&#xff1a;运行nvidis-smi 报错&#xff1a;Fa…

个人用户的数据之美:数据可视化助力解读

数据可视化是一种强大的工具&#xff0c;不仅可以为企业和专业人士提供见解&#xff0c;也对个人用户带来了许多实际的帮助。下面我就以一个数据可视化从业者的视角&#xff0c;来谈谈数据可视化对个人用户的益处&#xff1a; 首先对于个人用户来说&#xff0c;数据可视化可以让…

Nodejs 第二十五章(http)

“http” 模块是 Node.js 中用于创建和处理 HTTP 服务器和客户端的核心模块。它使得构建基于 HTTP 协议的应用程序变得更加简单和灵活。 创建 Web 服务器&#xff1a;你可以使用 “http” 模块创建一个 HTTP 服务器&#xff0c;用于提供 Web 应用程序或网站。通过监听特定的端…

python接口自动化测试--requests使用和基本方法封装

之前学习了使用jmeterant做接口测试&#xff0c;并实现了接口的批量维护管理(大概500多条用例)&#xff0c;对“接口”以及“接口测试”有了一个基础了解&#xff0c;最近找了一些用python做接口测试的资料&#xff0c;一方面为了学习下如何使用python进行接口测试(如何做出一个…

抖店需要多少资金?如何开通?具体流程如下!

我是电商珠珠 新手开抖店最关心的就是资金问题&#xff0c;在网上关于抖店的资金多少的都有&#xff0c;几百几千的都有。 各个回答都不一样。 另外一个问题就是怎么开通&#xff0c;今天我就来给大家详细的讲一下。 一、资金 入驻抖店需要办理一张个体工的营业执照&#…

Unity中URP下的顶点偏移

文章目录 前言一、实现思路二、实现URP下的顶点偏移1、在顶点着色器中使用正弦函数&#xff0c;实现左右摇摆的效果2、在正弦函数的传入参数中&#xff0c;加入一个扰度值&#xff0c;实现不规则的顶点偏移3、修改正弦函数的振幅 A&#xff0c;让我们的偏移程度合适4、修改正弦…

Linux/Windows IP | Team基础管理

引言 IP&#xff08;Internet Protocol&#xff09; 定义&#xff1a; IP&#xff08;Internet Protocol&#xff09;是网络传输数据的协议&#xff0c;负责在网络中唯一标识和定位设备&#xff0c;并提供数据传输的基础。功能&#xff1a; 允许计算机在网络上相互通信和交换…

VMware Ubuntu虚拟机忘记密码

​​原文 https://blog.csdn.net/ezconn/article/details/89328024​​​​​​​ 前言&#xff1a; 在VMware运行Ubuntu虚拟机时&#xff0c;开机之后忘记密码怎么办&#xff1f; 环境&#xff1a;Ubuntu版本&#xff1a;ubuntu-16.04.6-server-amd64&#xff1b;VMware版本…

乐理基础-弱起小节、弱起

弱起小节的定义&#xff1a; 1.音乐不是从强拍开始的&#xff0c;是从弱拍或次强拍开始的。 2.弱起小节会省去前面没有音乐的部分&#xff0c;它是不完整的小节&#xff0c;它的拍数是不够的。如图1 弱起小节的作用&#xff1a; 强拍经常要作为 和弦出现 和 变化的地方&#xf…

德人合科技 | 防止公司电脑文件数据资料外泄,自动智能透明加密保护系统

【透明加密软件】——防止公司电脑文件数据资料防止外泄&#xff0c;自动智能透明加密保护内部核心文件、文档、图纸、源代码、音视频等资料&#xff01; PC端访问地址&#xff1a; www.drhchina.com &#x1f31f; 核心功能&#xff1a; 透明加密&#xff1a;采用高级加密算…

EasyExcel合并相同内容单元格及动态标题功能的实现

一、最初版本 导出的结果&#xff1a; 对应实体类代码&#xff1a; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentLoopMerge; import com.al…

全链路压力测试:解析其主要特点

随着信息技术的飞速发展和云计算的普及&#xff0c;全链路压力测试作为一种关键的质量保障手段&#xff0c;在软件开发和系统部署中扮演着至关重要的角色。全链路压力测试以模拟真实生产环境的压力和负载&#xff0c;对整个业务流程进行全面测试&#xff0c;具有以下主要特点&a…

Nginx网站服务详解(Nginx服务的主配置文件 ——nginx.conf)

目录 一、全局配置的六个模块简介 二、Nginx配置文件的详解 1&#xff09;全局配置模块 2&#xff09;I/O 事件配置 3&#xff09;HTTP 配置 4&#xff09;web服务监听设置 5&#xff09;其他设置 location常见配置指令&#xff1a;“root、alias、proxy_pass 对比&a…

【数据分享】2019-2023年我国地级市逐年新房房价数据(免费获取/Excel/Shp格式)

房价是一个城市发展程度的重要体现&#xff0c;一个城市的房价越高通常代表这个城市越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享了2019—2023年我国地级市逐月的新房房价数据…

揭秘`v-if`和`v-show`的区别:选择正确指令的技巧(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

EasyExcel模板导出(行和列自动合并)

1.需求背景: ①需要从第三方获取数据,第三方接口有两个参数,开始时间和结束时间 ②获取回来的数据并没有入库,所以不能通过数据库将数据归类统计,excel合并大概的流程是判断上一行或者左右相邻列是否相同,然后进行合并,所以不能是零散的数据且客户要求每一个自治区和每一个航站…

系统分析师(软考)知识点整理(一)

第一章 信息 信息是不确定性的减少 xi: n个状态中的第i个状态p(xi):出现第i个状态的概率b: b一般取值为2 特征 #mermaid-svg-pvPkY9RE5GZIIIxl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-pvPkY9RE5GZIIIxl…