请原谅我,如果这已经被问到之前,我一直在寻找这个答案一整天,所有我想出的是帮助基于瓷砖的2d游戏。x~x

我正在尝试在Direct3D9中创建可换肤GUI,使用XML文件,该文件具有每个元素的位置以及拉伸或平铺它们的选项。拉伸是一个足够简单的过程,但我一直无法找到一种方法来平铺纹理的一小部分。传统上,要平铺纹理,我只需将UV坐标设置为>1.0,但源纹理坐标只会是整个纹理的一小部分,例如0.4到0.5。

我有一种感觉,我错过了一些非常明显的东西,但是我如何去简单地平铺而不是伸展?我最好的猜测是它与拥有一组以上的纹理坐标有关,但从那里开始,我不确定去哪里。

该项目目前使用固定函数管道,所以如果可能的话,我更喜欢使用它的答案,但是如果这是唯一的方法,我不会拒绝使用着色器的答案。

有帮助吗?

解决方案

我知道你只想平铺纹理的一个子集,对吧?然后事情变得复杂。

假设我们要在u1和u2值之间平铺u-coord,u1 < u2.

然后我们需要一个函数f(u),这样

f(0.0) = u1
f(0.5) = (u1+u2)/2
f(0.9999) = u2
f(1.0) = u1
f(1.5) = (u1+u2)/2
f(1.9999) = u2
f(2.0) = u1
and so on...

一个适当的功能是 f(u) = frac(u) * (u2-u1) + u1

V-coord也是如此, f(v) = frac(v) * (v2-v1) + v1

请注意,它在没有镜像的情况下进行平铺。如果你需要镜像,那么函数应该是一个三角波函数,这是 t(x) = arcsin(sin(pi*(x-0.5)))/pi+0.5f(u) = t(u) * (u2-u1) + u1.虽然使用三角函数可能很昂贵。

不知道是否可以使用固定管道,但您可以在像素着色器(HLSL代码)中轻松完成:

// float2 tex_coord -> (u,v) from vertex shader, in [0,n] range,
//                     n - number of repetitions
// float2 tex1, tex2 -> constants, subrange of [0,1] coords that will be tiled

// no mirroring
float4 color = tex2D(sampler, frac(tex_coord) * (tex2-tex1) + tex1);

// mirroring, t(x) = arcsin(sin(pi*(x-0.5)))/pi+0.5
float4 color = tex2D(sampler, t(tex_coord) * (tex2-tex1) + tex1);

编辑:一种更好的三角波函数计算方法: t1(x) = abs(2(0.5x-floor(0.5x+0.5)))t2(x) = abs(2(frac(0.5x+0.5))-1) (与t1不完全相同,但对于非负数是正确的)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top