我对opengl有一点问题,我有一张3D地图,所以我想应用几个纹理。
我创建了一个带纹理的着色器,但使用rgba时的问题是我被阻止只有4个组件文本最大
uniform sampler2D detail_tex1;
uniform sampler2D detail_tex2;
uniform sampler2D detail_tex3;
uniform sampler2D detail_tex4;
uniform sampler2D detail_tex5;
uniform sampler2D attribute_tex;
vec3 diffuse = texture(detail_tex1, terrain_uv * 16.0).rgb * texture(attribute_tex, terrain_uv).r;
diffuse += texture(detail_tex2, terrain_uv * 16.0).rgb * texture(attribute_tex, terrain_uv).g;
diffuse += texture(detail_tex3, terrain_uv * 16.0).rgb * texture(attribute_tex, terrain_uv).b;
diffuse += texture(detail_tex4, terrain_uv * 16.0).rgb * texture(attribute_tex, terrain_uv).a;
纹理只有4个组件,所以我只能为4个纹理做这个。我的问题是如何克服这种限制?
我分享完整的代码,我在python中使用panda3d引擎 https://drive.google.com/file/d/1VjpEnEktwGfw6rZyE6nGDkdj-8gZF29Z/view
答案 0 :(得分:3)
纹理只有4个组件,句号。没有解决这个问题。唯一的问题是如何最好地处理它。
例如,显而易见的解决方案是使用多个纹理来控制各个图层的混合。 attribute_tex1
将拥有前4个组件,attribute_tex2
将拥有第4个组件,依此类推。您只需使用相同的纹理坐标访问它们。
如果您想避免使用多个纹理的开销,可以尝试将数据打包到单个纹理中。这需要对这些值究竟是什么有一定程度的了解。例如,你真的需要这5个纹理的每个可能的组合吗?或者你真的只是在两个“相邻”纹理之间混合?也就是说,特定像素是否在1和2之间混合,另一个在2和3之间混合,但在1和3之间没有混合?
如果是这种情况,那么您的混合数据只需要是第一个纹理的索引和该纹理的混合因子。第二个索引只是第一个索引+1,第二个混合因子只是1.0 - 第一个混合因子。
此时,你并不需要一堆单独的纹理。你需要的是2D array texture。我在这里选择一个数组纹理而不是3D纹理,因为你可能仍然希望mipmapping正常工作。在3D纹理中,较低的mipmap无法正确混合。
您的attribute_tex
将使用GL_RG8UI
格式,这意味着它会存储无符号整数数据。 r
组件是第一个索引,g
组件是第一个混合因子,其中0表示使用第二个的完整值,255表示第一个的完整值。
您的detail_tex#
纹理将成为单个sampler2DArray
纹理,其中每个原始图像都会成为纹理中的图层。第0层对应detail_tex1
,依此类推。
所以你的代码变成了这个:
uniform sampler2DArray detail_textures;
uniform usampler2D attribute_tex; //Must be `u` to designate that it's an unsigned integer texture.
...
vec2 blend_factors = texture(attribute_tex, terrain_uv).rg;
vec4 tex_first = texture(detail_textures, vec3(terrain_uv, blend_factors.r);
vec4 tex_second = texture(detail_textures, vec3(terrain_uv, blend_factors.r + 1);
diffuse = mix(tex_first, tex_second, blend_factors.g / 255.0f);
答案 1 :(得分:0)
不是将每个属性放在同一纹理的单独通道中,而是使用单通道内部格式(例如GL_TEXTURE_2D_ARRAY
或GL_R8
)创建GL_R16F
,将每个属性放入一个单独的数组图层,并将每个细节纹理放入另一个数组纹理的图层中。然后,您可以使用与此类似的着色器:
uniform sampler2DArray detail_array;
uniform sampler2DArray attribute_array;
uniform uint texture_count;
...
vec3 diffuse(0.0);
for (uint i = 0; i < texture_count; ++i) {
diffuse += texture(detail_array, vec3(terrain_uv * 16.0, i)).rgb *
texture(attribute_array, vec3(terrain_uv, i)).r;
}
如果需要从不同的纹理中读取不同的网格物体,可以传递一个整数数组来识别应该读取的纹理。
请注意,对每个像素采样这么多纹理对于您要执行的操作可能效率低下。