✺ch5——纹理贴图

2023-12-19 14:44
文章标签 贴图 纹理 ch5

本文主要是介绍✺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 引入了采样器对象(有时称为“采样器状态”,不要与采样器变量混淆),可用于保存一组独立于实际纹理对象的纹理设置。将采样器对象附加到纹理单元,可以方便、 有效地更改纹理设置。

这篇关于✺ch5——纹理贴图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/512590

相关文章

opengl纹理操作

我们在前一课中,学习了简单的像素操作,这意味着我们可以使用各种各样的BMP文件来丰富程序的显示效果,于是我们的OpenGL图形程序也不再像以前总是只显示几个多边形那样单调了。——但是这还不够。虽然我们可以将像素数据按照矩形进行缩小和放大,但是还不足以满足我们的要求。例如要将一幅世界地图绘制到一个球体表面,只使用glPixelZoom这样的函数来进行缩放显然是不够的。OpenGL纹理映射功能支持将

试用UE4的纹理数组(UTexture2DArray)

UTexture2DArray 我发现在我目前使用的版本(4.25)中,官方已经实现了纹理数组(可能在4.24或更早版本就已经实现了)。 纹理数组,其含义不言而喻。一个重要作用是可以使用更多的纹理而不受制于sampler数目限制。 这一篇里我想对官方的纹理数组进行一下简单的试用。 试用 0. 启用纹理数组 虽然我看到了代码中有UTexture2DArray这个类,不过一开始并没有在编辑器

研究纹理采样器在像素级别的采样位置

问题 【纹理采样器】是一个基础的概念。假设有一个正方形面片,顶点的UV范围是0.0~1.0,那么在这个正方形面片上采样一张纹理时,会呈现出完整的纹理。 但我现在关注的问题是,在像素级别上,采样的位置是怎样的。具体来讲:对于UV值是(0.0,0.0)的点,它对应的采样位置是纹理最左上角像素的中心?还是纹理最左上角像素的左上角?即,下面左右哪个是正确的情况? 在宏观上,尤其是像素较多的时候,二者

图形API学习工程(11):使用纹理

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics 目标 实现纹理采样。 参考教程/代码范例: OpenGL: 纹理 - LearnOpenGL CN Vulkan: Images - Vulkan Tutorial D3D11: DirectX11官方SDK范例【Tutorial 7: Texture Mapping and Constant

图形API学习工程(25):实现法线贴图

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics 目标 在《图形API学习工程(10):基础光照》中,我实现了最基础的光照,同时也表现了法线的作用。 在《图形API学习工程(11):使用纹理》中,工程已经能够加载纹理贴图。 这样,法线贴图 所需的准备已经完成,可以在工程里实现这个技术了。 (关于法线贴图的意义,可见上一篇博客《从“法线贴图的意义

从“法线贴图的意义”到“切线空间公式的推导与验证”

目录 目标1. 法线贴图1.1 “法线”的意义1.2 “法线贴图”的意义 2. 切线空间2.1 法线贴图中数据的含义2.2 “切线空间”的定义 3. 切线空间计算公式3.1 构造几何关系等式3.2 切线空间计算公式 4. 代码5. 验证——与其他美术软件计算的结果进行比较总结 目标 本篇的重点是 讨论法线贴图的意义讨论切线空间的意义推导切线空间的计算公式根据公式编写代码将其计算

翻译 Albert Julian Mayer 关于虚拟纹理的论文(3. 概述)

第3章:概述 本章介绍了整篇论文中使用的术语,并简要介绍了“虚拟纹理”及其挑战。 3.1 术语 目前,在纹理缓存领域存在术语不匹配的情况。一些论文将术语 “虚拟纹理” 应用于所有 “使用部分驻留在内存中的纹理的系统”,特别是类似 Clipmapping 的系统 [TSH09]、 [EC06]、 [Wei04]、 [SLT+07]。而其他论文和资源将这个术语应用于一种更新的、截然不同的大纹理支

翻译 Albert Julian Mayer 关于虚拟纹理的论文(1. 介绍)

译者前言 在搜寻关于虚拟纹理相关资料的时候,我发现了这篇论文: 这似乎是 维也纳科技大学计算机科学系 的学生 Albert Julian Mayer 的研究生学位论文。 这篇论文也出现在了 2014 GDC Adaptive Virtual Texture Rendering in Far Cry 4 的参考文献之中。 我希望通过翻译这篇论文来学习虚拟纹理的基础概念等知识。 摘要 在实时

【教学类-52-08】20240905动物数独(6宫格)一页2张任务卡,一页一个动物贴图卡,有答案

背景需求: 前文提到6宫格数独的图片6*6=36图,如果将6张任务卡放在一个A4上,看上去6种动物很小,所以我换了一个word模板,变成了2张任务卡放在一个A4上。 【教学类-52-07】20240903动物数独(6宫格)一页2张任务卡,无答案-CSDN博客文章浏览阅读846次,点赞25次,收藏6次。【教学类-52-07】20240903动物数独(6宫格)一页2张任务卡,无答案https:

Three.js new THREE.TextureLoader()纹理贴图使用png图片显示为黑色

问题代码如下: const texture = new THREE.TextureLoader().load('./image.png');droneGeometry = new THREE.PlaneGeometry(1, 1);droneMaterial = new THREE.MeshBasicMaterial({ map: texture});droneMesh = new THRE