如何重复选择纹理图集?
例如,我的精灵(选择)位于纹理坐标内:
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
};
我们正在看到我们的全纹理图集重复......
我如何以正确的方式做到这一点?
答案 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)
无法完成......