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

时间:2009-03-19 12:59:05

标签: opengl graphics textures texture-mapping

如何重复选择纹理图集?

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

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

我们正在看到我们的全纹理图集重复......

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

7 个答案:

答案 0 :(得分:18)

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

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

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

你基本上有两个选择:创建一个只有现有纹理所需的精灵的新纹理,或者写一个GLSL顶点程序来适当地映射纹理坐标。

答案 1 :(得分:6)

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

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

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

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

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

答案 2 :(得分:5)

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

答案 3 :(得分:1)

虽然这可能是一个古老的话题;这是我最终如何做到的:

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

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

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

此解决方案比在纹理后重新加载纹理更具成本效益。 特别是如果您批量处理所有渲染调用(如您所愿)。

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

答案 4 :(得分:0)

可以在着色器中对tex坐标进行模运算。该mod将重复您的子范围坐标。

答案 5 :(得分:0)

我在处理同一问题时遇到了您的问题 - 尽管在 HLSL 和 DirectX 中。我还需要 mip mapping 并解决相关的纹理渗色问题。

我是这样解决的:

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 级别以这种方式混合,但在我们的用例中完全没问题。

答案 6 :(得分:-3)

无法完成......