且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用3D查找表并将其像素值映射到图像?

更新时间:2022-12-12 10:10:46

查找表不是64*64*64,而是8*8光栅中的64*64。texture2D读取的颜色通道在[0,1]范围内,纹理坐标也在[0,1]范围内。

vec2 tiles    = vec2(8.0);
vec2 tileSize = vec2(64.0);

vec3 imageColor = texture(src_i, samplerCoord(src_i)).rgb;
将区块的索引编码为蓝色通道。共有64个平铺,第一个平铺的索引为0,最后一个平铺的索引为63。这意味着范围[0,1]中的蓝色通道必须映射到范围[0,63]:
float index = imageColor.b * (tiles.x * tiles.y - 1.0);

根据此线性平铺索引,必须计算范围为[0,8]的二维平铺索引:

vec2 tileIndex;
tileIndex.y = floor(index / tiles.x);
tileIndex.x = floor(index - tileIndex.y * tiles.x);

纹理缩小功能(GL_TEXTURE_MIN_FILTER)和纹理放大功能(GL_TEXTURE_MAG_FILTER)应设置为GL_LINEAR。这会导致每个磁贴上的颜色可以进行线性插值。
每个平铺都有64x64个纹理元素。左下纹理的相对坐标为(0.5/64.0,0.5/64.0),右上纹理的相对坐标为(63.5/64.0,63.5/64.0)。
范围[0,1]中的红色和绿色通道必须映射到范围[0.5/64.0,63.5/64.0]:

vec2 tileUV = mix(0.5/tileSize, (tileSize-0.5)/tileSize, imageColor.rg);

最后可以计算[0,1]c范围内颜色查找表的纹理坐标:

vec2 tableUV = tileIndex / tiles + tileUV / tiles;

在片段着色器中解码颜色的最终代码可能如下所示:

vec2 tiles    = vec2(8.0, 8.0);
vec2 tileSize = vec2(64.0);

vec4 imageColor = texture(src_i, samplerCoord(src_i));

float index = imageColor.b * (tiles.x * tiles.y - 1.0);

vec2 tileIndex;
tileIndex.y = floor(index / tiles.x);
tileIndex.x = floor(index - tileIndex.y * tiles.x);

vec2 tileUV = mix(0.5/tileSize, (tileSize-0.5)/tileSize, imageColor.rg);

vec2 tableUV = tileIndex / tiles + tileUV / tiles;

vec3 lookUpColor = texture(src_l, tableUV).rgb;
通过在表的2个平铺之间进行插值,可以进一步改进该算法。计算蓝色通道下方的瓷砖索引和蓝色通道上方的瓷砖索引:
float index     = imageColor.b * (tiles.x * tiles.y - 1.0);
float index_min = min(62.0, floor(index));
float index_max = index_min + 1.0;

最后使用mix函数在两个瓷砖的颜色之间进行插值:

vec3 lookUpColor_1 = texture(src_l, tableUV_1).rgb;
vec3 lookUpColor_2 = texture(src_l, tableUV_1).rgb;
vec3 lookUpColor   = mix(lookUpColor_1, lookUpColor_2, index-index_min); 

最终代码:

vec2 tiles    = vec2(8.0, 8.0);
vec2 tileSize = vec2(64.0);

vec4 imageColor = texture(src_i, samplerCoord(src_i));

float index     = imageColor.b * (tiles.x * tiles.y - 1.0);
float index_min = min(62.0, floor(index));
float index_max = index_min + 1.0;

vec2 tileIndex_min;
tileIndex_min.y = floor(index_min / tiles.x);
tileIndex_min.x = floor(index_min - tileIndex_min.y * tiles.x);
vec2 tileIndex_max;
tileIndex_max.y = floor(index_max / tiles.x);
tileIndex_max.x = floor(index_max - tileIndex_max.y * tiles.x);

vec2 tileUV = mix(0.5/tileSize, (tileSize-0.5)/tileSize, imageColor.rg);

vec2 tableUV_1 = tileIndex_min / tiles + tileUV / tiles;
vec2 tableUV_2 = tileIndex_max / tiles + tileUV / tiles;

vec3 lookUpColor_1 = texture(src_l, tableUV_1).rgb;
vec3 lookUpColor_2 = texture(src_l, tableUV_2).rgb;
vec3 lookUpColor   = mix(lookUpColor_1, lookUpColor_2, index-index_min); 

查看比较原始图像(左上)和通过颜色查找修改后的图像(右下)的图像: