【问题标题】:How to use GL_REPEAT to repeat only a selection of a texture atlas? (OpenGL)如何使用 GL_REPEAT 仅重复选择纹理图集? (OpenGL)
【发布时间】:2010-10-14 07:25:54
【问题描述】:

如何重复选择纹理图集?

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

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

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

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

【问题讨论】:

    标签: opengl graphics textures texture-mapping


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 感谢“unwind”、“Jimmy J”和“TrayMan”的贡献。我对你的答案进行了投票,并从你的答案中汇编了这个答案,它现在很好地描述了正在发生的事情。
    • >"或者编写一个 GLSL 顶点程序来适当地映射纹理坐标。"必须有fragment程序代替。
    • 这取决于,中士。使用曲面细分技术更多的是顶点而不是片段。您通常可以通过不在纹理着色器中执行纹理坐标计算来进行优化 - 特别是基于图块的延迟渲染。
    【解决方案2】:

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

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

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

    没有图片解释有点粗略。

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

    【讨论】:

    • 嗯,例如 GL_CLAMP 会影响您所描述的子纹理,这让我想到纹理坐标模式确实适用于纹理图集的某些部分。还是我在这里错了? (当然,看到我不能按照自己喜欢的方式重复,说明我确实错了:))
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      一种解决方法是创建多个网格,将它们粘合在一起,包含纹理 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)

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            做不到……

            【讨论】:

            • 那是你的固定管道在说话。
            猜你喜欢
            • 2012-07-03
            • 2019-12-06
            • 2012-12-09
            • 2012-07-07
            • 2021-11-04
            • 2014-12-30
            • 2020-04-03
            • 2011-10-20
            • 1970-01-01
            相关资源
            最近更新 更多