如何使用 GL_REPEAT 仅重复纹理图集的选择? (OpenGL)

发布于 2024-07-15 06:21:13 字数 653 浏览 9 评论 0原文

如何重复选择纹理图集?

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

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
};

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

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

How can I repeat a selection of a texture atlas?

For example, my sprite (selection) is within the texture coordinates:

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

Then I want to repeat that sprite N times to a triangle strip (or quad) defined by:

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

I know it has something to do with GL_REPEAT and textureCoords going passed the range [0,1]. This however, doesn't work: (trying to repeat N = 10)

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

We're seeing our full texture atlas repeated...

How would I do this the right way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

给我一枪 2024-07-22 06:21:13

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

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

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

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

It can't be done the way it's described in the question. OpenGL's texture coordinate modes only apply for the entire texture.

Normally, to repeat a texture, you'd draw a polygon that is "larger" than your texture implies. For instance, if you had a square texture that you wanted to repeat a number of times (say six) over a bigger area, you'd draw a rectangle that's six times as wide as it is tall. Then you'd set the texture coordinates to (0,0)-(6,1), and the texture mode to "repeat". When interpolating across the polygon, the texture coordinate that goes beyond 1 will, due to repeat being enabled, "wrap around" in the texture, causing the texture to be mapped six times across the rectangle.

None of the texture wrap modes support the kind of operation as described in the question, i.e. they all map to the full [0,1] range, not some arbitrary subset. when you're texturing using just a part of the texture, there's no way to specify that larger texture coordinate in a way that makes OpenGL repeat it inside only the sub-rectangle.

You basically have two choices: Either create a new texture that only has the sprite you need from the existing texture or write a GLSL vertex program to map the texture coordinates appropriately.

長街聽風 2024-07-22 06:21:13

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

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

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

没有图像来解释有点粗糙。

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

I'm not sure you can do that. I think OpenGL's texture coordinate modes only apply for the entire texture. When using an atlas, you're using "sub-textures", so that your texture coordinates never come close to 0 and 1, the normal limits where wrapping and clamping occurs.

There might be extensions to deal with this, I haven't checked.

EDIT: Normally, to repeat a texture, you'd draw a polygon that is "larger" than your texture implies. For instance, if you had a square texture that you wanted to repeat a number of times (say six) over a bigger area, you'd draw a rectangle that's six times as wide as it is tall. Then you'd set the texture coordinates to (0,0)-(6,1), and the texture mode to "repeat". When interpolating across the polygon, the texture coordinate that goes beyond 1 will, due to repeat being enabled, "wrap around" in the texture, causing the texture to be mapped six times across the rectangle.

This is a bit crude to explain without images.

Anyway, when you're texturing using just a part of the texture, there's no way to specify that larger texture coordinate in a way that makes OpenGL repeat it inside only the sub-rectangle.

轻拂→两袖风尘 2024-07-22 06:21:13

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

None of the texture wrap modes support the kind of operation you are looking for, i.e. they all map to the full [0,1] range, not some arbitrary subset. You basically have two choices: Either create a new texture that only has the sprite you need from the existing texture or write a GLSL pixel program to map the texture coordinates appropriately.

随梦而飞# 2024-07-22 06:21:13

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

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

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

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

此解决方案比必须在之后重新加载纹理更具成本效益质地。
特别是如果您对所有渲染调用进行批处理(正如您应该的那样)。

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

While this may be an old topic; here's how I ended up doing it:

A workaround would be to create multiple meshes, glued together containing the subset of the Texture UV's.

E.g.:
I have a laser texture contained within a larger texture atlas, at U[0.05 - 0.1] & V[0.05-0.1].

I would then construct N meshes, each having U[0.05-0.1] & V[0.05-0.1] coordinates.
(N = length / texture.height; height being the dimension of the texture I would like to repeat. Or easier: the amount of times I want to repeat the texture.)

This solution would be more cost effective than having to reload texture after texture.
Especially if you batch all render calls (as you should).

(OpenGL ES 1.0,1.1,2.0 - Mobile Hardware 2011)

可爱暴击 2024-07-22 06:21:13

可以通过着色器中的纹理坐标取模来完成。 该模组将重复您的子范围坐标。

Can be done with modulo of your tex-coords in shader. The mod will repeat your sub range coords.

墨落画卷 2024-07-22 06:21:13

我在处理同一问题时遇到了你的问题 - 尽管是在 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 级别以这种方式混合,但在我们的用例中,这是完全没问题的。

I was running into your question while working on the same issue - although in HLSL and DirectX. I also needed mip mapping and solve the related texture bleeding too.

I solved it this way:

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);
}

Note the limitation is that the mip levels are blended this way, but in our use-case that is completely fine.

只为一人 2024-07-22 06:21:13

做不到...

Can't be done...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文