在着色器中平铺纹理

4
我将传递到顶点着色器(glsl)的内容分为两个纹理:来自屏幕和较小的法线贴图。法线贴图被缩放以适应屏幕尺寸。因此,如果第一个纹理是1152×864像素,法线贴图是256×256,它将从其大小缩放到更大。
我该如何使其平铺?例如,将其设置为256×256并在整个纹理上进行平铺。
更新:
例如,我的主要(大)纹理映射如下:
[0.17, 0.61, 0.33, 0.83]

替代方案:

[0, 0, 1, 1]

这样,我的普通纹理也被映射到了第一个坐标。所以我只看到了一个小的映射矩形。如何在着色器中将其映射为全尺寸?

不清楚OpenGL,但在DirectX中,这是采样器的一个用例。OGL也会有类似的东西。 - Karel Petranek
1个回答

6
它不会从它的大小变得更大。这是关于纹理的一个常见误解。纹理只是一种花哨的查找表。纹理相对于彼此并没有“缩放”;这只是使用什么纹理坐标的问题。很可能,您正在使用与屏幕纹理相同的纹理坐标作为普通贴图。由于我们可能正在谈论归一化的纹理坐标,这意味着您将相同的[0,1]范围映射到两者之间。要获得您所说的效果,您需要计算用于普通纹理的纹理坐标,以实现所需的效果。因此,如果您有一个相对于屏幕纹理的纹理坐标,您必须将其转换为普通纹理中想要的空间。有几种方法可以做到这一点。手动方法是在CPU上计算纹理之间的大小比率,然后将其传递给着色器。使用您提供的数字,大小比率将为:
(1152.0/256.0, 864.0/256.0) = (4.5, 3.375).

请确保使用浮点数进行计算。完成后,只需在着色器中将此比率传递给uniform,并在采样之前将纹理坐标乘以该比率:

uniform vec2 textureRatio;

void main() {
//Get the texture coordinate.
vec4 screenTexColor = texture(screenTex, texCoord);
vec2 normTexCoord = textureRatio * texCoord;
vec4 normalValue = texture(normalTex, normTexCoord);
//Do something with these.
}

在GLSL中的自动方式是直接在着色器中完成。这需要GLSL 1.30或更高版本。基本上,你可以使用语言的可用特性来计算比率:

void main() {
//Get the texture coordinate.
vec2 textureRatio = textureSize(screenTex) / textureSize(normalTex);
vec4 screenTexColor = texture(screenTex, texCoord);
vec2 normTexCoord = textureRatio * texCoord;
vec4 normalValue = texture(normalTex, normTexCoord);
//Do something with these.
}

在这两种情况下,我假设您的GL_TEXTURE_WRAP_S/T设置为GL_REPEAT,并具有适当的纹理或采样器参数。
请注意,在CPU上计算比率并将其作为统一变量传递,很可能比在着色器中计算要快。特别是对于将大量运行的片段着色器。

很好的回答,但是使用1.30版本的功能,对于每个片段计算常数比率可能不是一个好主意,甚至更糟糕的是鼓励新手为每个片段重新计算常数值。我认为你需要一个非常优化的GLSL编译器来优化它。 - Christian Rau
@Christian Rau:同意。但他确实说他正在“传递到顶点着色器(glsl)2个纹理”。现在是的,这与他实际要做的事情似乎毫无意义,但那就是他所说的。因此,如果他从顶点着色器中访问它们,那么问题可能不会太严重。但我会添加有关性能影响的说明。 - Nicol Bolas
很棒的答案,谢谢!说实话,我并不是你想象中的那么新手。只是我的英语太纯正了,无法告诉你我真正的想法 :) - Max Frai
bolas 又有一个小问题:如果我的主纹理不是映射到 [0; 1] (0, 0, 1, 1) 矩形,而是映射到其他一些东西(不超过 1×1)。例如,如果我需要主纹理的一半部分,我将其映射到 [0; 0.5]。如何执行您在帖子中告诉我的相同操作? - Max Frai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接