18

如何重复选择纹理图集?

例如,我的精灵(选择)在纹理坐标内:

GLfloat textureCoords[]=
{
    .1f,  .1f,
    .3f,  .1f,
    .1f,  .3f,
    .3f,  .3f
};

然后我想将该精灵重复N 次到由以下定义的三角形条带(或四边形):

GLfloat vertices[]=
{
   -100.f, -100.f,
    100.f, -100.f,
   -100.f,  100.f,
    100.f,  100.f
};

我知道这GL_REPEAT与 textureCoords 超出范围有关[0,1]。但是,这不起作用:(尝试重复 N = 10)

GLfloat textureCoords[]=
{
    10.1f,  10.1f,
    10.3f,  10.1f,
    10.1f,  10.3f,
    10.3f,  10.3f
};

我们看到我们的完整纹理图集重复...

我将如何以正确的方式做到这一点?

4

7 回答 7

19

不能按照问题中描述的方式完成。OpenGL 的纹理坐标模式仅适用于整个纹理。

通常,要重复纹理,您会绘制一个比纹理所暗示的“更大”的多边形。例如,如果你有一个方形纹理,你想在更大的区域上重复多次(比如六次),你会绘制一个宽度是高度的六倍的矩形。然后将纹理坐标设置为 (0,0)-(6,1),并将纹理模式设置为“重复”。在多边形上插值时,超过 1 的纹理坐标将由于启用重复而在纹理中“环绕”,导致纹理在矩形上映射六次。

没有一种纹理环绕模式支持问题中描述的那种操作,即它们都映射到完整的 [0,1] 范围,而不是某个任意子集。当您仅使用纹理的一部分进行纹理处理时,无法以使 OpenGL 仅在子矩形内重复它的方式指定较大的纹理坐标。

您基本上有两个选择:要么从现有纹理中创建一个仅包含您需要的精灵的新纹理,要么编写一个 GLSL 顶点程序来适当地映射纹理坐标。

于 2009-03-19T15:28:54.120 回答
6

我不确定你能做到这一点。我认为OpenGL的纹理坐标模式只适用于整个纹理。使用图集时,您使用的是“子纹理”,因此您的纹理坐标永远不会接近 0 和 1,即发生缠绕和夹紧的正常限制。

可能有扩展来处理这个问题,我没有检查过。

编辑:通常,要重复纹理,您会绘制一个比纹理暗示的“更大”的多边形。例如,如果你有一个方形纹理,你想在更大的区域上重复多次(比如六次),你会绘制一个宽度是高度的六倍的矩形。然后将纹理坐标设置为 (0,0)-(6,1),并将纹理模式设置为“重复”。在多边形上插值时,超过 1 的纹理坐标将由于启用重复而在纹理中“环绕”,导致纹理在矩形上映射六次。

如果没有图像,这有点粗略。

无论如何,当您只使用纹理的一部分进行纹理处理时,无法以使 OpenGL 仅在子矩形内重复它的方式指定更大的纹理坐标。

于 2009-03-19T13:40:15.107 回答
5

没有一种纹理环绕模式支持您正在寻找的那种操作,即它们都映射到完整的 [0,1] 范围,而不是某个任意子集。您基本上有两个选择:要么从现有纹理中创建一个只有您需要的精灵的新纹理,要么编写一个 GLSL 像素程序来适当地映射纹理坐标。

于 2009-03-19T14:03:03.603 回答
1

虽然这可能是一个老话题;这就是我最终这样做的方式:

一种解决方法是创建多个网格,将它们粘合在一起,包含纹理 UV 的子集。

例如:我有一个激光纹理包含在一个更大的纹理图集中,位于 U[0.05 - 0.1] 和 V[0.05-0.1]。

然后我会构建 N 个网格,每个网格都有 U[0.05-0.1] 和 V[0.05-0.1] 坐标。(N = length / texture.height;height 是我想要重复的纹理的尺寸。或者更简单:我想要重复纹理的次数。)

这种解决方案比必须在纹理后重新加载纹理更具成本效益。特别是如果你批处理所有渲染调用(你应该这样做)。

(OpenGL ES 1.0、1.1、2.0 - 移动硬件 2011)

于 2011-12-09T11:48:42.237 回答
1

可以在着色器中使用 tex 坐标的模数来完成。该模组将重复您的子范围坐标。

于 2020-03-10T15:55:01.287 回答
0

我在处理同一个问题时遇到了你的问题——尽管是在 HLSL 和 DirectX 中。我还需要 mip 映射并解决相关的纹理出血。

我是这样解决的:

min16float4 sample_atlas(Texture2D<min16float4> atlasTexture, SamplerState samplerState, float2 uv, AtlasComponent atlasComponent)
{
  //Get LOD
  //Never wrap these as that will cause the LOD value to jump on wrap
  //xy is left-top, zw is width-height of the atlas texture component
  float2 lodCoords = atlasComponent.Extent.xy + uv * atlasComponent.Extent.zw;  
  uint lod = ceil(atlasTexture.CalculateLevelOfDetail(samplerState, lodCoords));

  //Get texture size
  float2 textureSize;
  uint levels;
  atlasTexture.GetDimensions(lod, textureSize.x, textureSize.y, levels);
  
  //Calculate component size and calculate edge thickness - this is to avoid bleeding
  //Note my atlas components are well behaved, that is they are all power of 2 and mostly similar size, they are tightly packed, no gaps
  float2 componentSize = textureSize * atlasComponent.Extent.zw;
  float2 edgeThickness = 0.5 / componentSize;

  //Calculate texture coordinates
  //We only support wrap for now
  float2 wrapCoords = clamp(wrap(uv), edgeThickness, 1 - edgeThickness);
  float2 texCoords = atlasComponent.Extent.xy + wrapCoords * atlasComponent.Extent.zw;
  return atlasTexture.SampleLevel(samplerState, texCoords, lod);
}

请注意,限制是 mip 级别以这种方式混合,但在我们的用例中完全没问题。

于 2021-02-15T20:06:28.067 回答
-3

做不到...

于 2009-03-19T13:58:54.393 回答