多纹理:任意数量的纹理和UV集

在Photoshop或Effetcs工作后,我们的用户可以合成任意数量的图层,并驱动片段颜色和不透明度的结果。

一层是:

  • 纹理或任意大小(静态图像文件或video帧)或着色器计算的程序色彩
  • 紫外线设置
  • 一个不透明的值
  • 合并操作:混合(对于颜色)或者多(对于alpha)

在下面的例子中,网格有2个UV集和5个层(从上到下):

  1. 沿着紫外线组1重复一个小的64×64方形纹理(操作:mult来驱动alpha)
  2. 哑光512×512纹理(紫外线1,多)
  3. 一个半透明的1024×256彩虹纹理(紫外线2,混合)
  4. 一个完全不透明的512×512棋盘(紫外线1,混合)
  5. 在这里从未显示的着色器计算的基本颜色具有完全不透明的上层

纹理和合成

目前,我将UVs集作为varying vec2和层信息arrays int[TEXTURES_ARRAY_SIZE]给合并操作标识符的统一arrays int[TEXTURES_ARRAY_SIZE] ,纹理arrays sampler2D[TEXTURES_ARRAY_SIZE]等。

 #if USE_MAPPING_0 varying vec2 vUv0; #endif #if USE_MAPPING_1 varying vec2 vUv1; #endif #if USE_MAPPING_2 varying vec2 vUv2; #endif // ... etc until USE_MAPPING_8 #if TEXTURES_ARRAY_SIZE > 0 uniform sampler2D layersTexture[TEXTURES_ARRAY_SIZE]; uniform int layersMapping[TEXTURES_ARRAY_SIZE]; uniform float layersOpacity[TEXTURES_ARRAY_SIZE]; uniform bool layersIsPremult[TEXTURES_ARRAY_SIZE]; uniform int layersMergeOp[TEXTURES_ARRAY_SIZE]; uniform bool layersTransparent[TEXTURES_ARRAY_SIZE]; uniform bool layersIsMatte[TEXTURES_ARRAY_SIZE]; uniform vec2 layersRepeat[TEXTURES_ARRAY_SIZE]; #endif // unrolled UV getter vec2 getUv(int uvSetNumber) { #if USE_MAPPING_0 if (uvSetNumber == 0) { return vUv0; } #endif #if USE_MAPPING_1 if (uvSetNumber == 1) { return vUv1; } #endif // etc... } 

然后循环for (int i = 0 ; i < TEXTURES_ARRAY_SIZE ; ++i)来合并图层。 在某些时候,我用vec4 texelColor = texture2D(layersTexture[i], getUv(layersMapping[i]) * layersRepeat[i]);检索纹理颜色vec4 texelColor = texture2D(layersTexture[i], getUv(layersMapping[i]) * layersRepeat[i]);

很显然,当UV集的数量或层数发生变化时,我需要重新编译一个新的着色器。

这种方法在Open GL ES 2.0 / WebGL 1中texture2D ,但不能在更多版本中使用, texture2D无法通过运行时值对索引进行索引。 为了保持我的代码未来的certificate,我需要find另一种方法。

第一个想到的是有一个固定数量的sampler2D并有另一个开关函数来访问它们:

 #if USE_TEXTURE_0 uniform sampler2D sampler0; #endif #if USE_TEXTURE_1 uniform sampler2D sampler1; #endif // ... vec4 getTextureSample(int textureIndex, vec2 uv) { #if USE_TEXTURE_0 if (textureIndex == 0) { return texture2D(sampler0, uv); } #endif #if USE_TEXTURE_1 if (textureIndex == 1) { return texture2D(sampler1, uv); } #endif // etc... } 

但是我发现这种方法有三个缺点:

  • 这是很多分支
  • 每次定义新的纹理/图层/ uvset时,仍然需要重新编译新的着色器
  • 我可以根据varyingsampler2D硬件限制

我想我可以忍受这三个限制,但我想知道你们是否知道更好的方法来处理合成任意数量的任意大小的纹理的问题?

谢谢 !