具有4个以上组件

时间:2018-06-13 17:57:25

标签: python-3.x opengl glsl

我对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

2 个答案:

答案 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_ARRAYGL_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;
}

如果需要从不同的纹理中读取不同的网格物体,可以传递一个整数数组来识别应该读取的纹理。

请注意,对每个像素采样这么多纹理对于您要执行的操作可能效率低下。