on server you can do:
void main()
{
FragColor = texture(LowTexture, TexCoord) - texture(HighTexture, TexCoord) + vec4(0.5, 0.5, 0.5, 1.0);
}
and on client side:
void main()
{
FragColor = texture(LowTexture, TexCoord) - texture(DiffTexture, TexCoord) - vec4(0.5, 0.5, 0.5, 1.0);
}
for example if highTex have 16x16 pixels per one lowTex pixel and lowTex pixel is avg of highTex pixels then diffTexture pixels will be in bounds from 0 to 1 in ~98.75% of cases with this method
here is small js code which tests it for 50_000 * 16*16 = 38_400_000 rgb pixels of highTex
const testIterCount = 50_000*3
const result = {error: 0, ok: 0}
for (let i = 0; i < testIterCount; i++) {
const high = new Float32Array(16*16).map(a=>Math.random())
const low = high.reduce((a,b)=>a+b)/high.length
const testResult = high.reduce((counter,highVal)=>{
const serverVal = low - highVal + 0.5;
if (serverVal >= 0 && serverVal <= 1) {
counter.ok++;
} else {
counter.error++;
}
return counter
},{error: 0, ok: 0})
result.error += testResult.error
result.ok += testResult.ok
}
console.log(`ok ${ (result.ok/(result.ok+result.error)*100).toFixed(2) }%; error ${ (result.error/(result.ok+result.error)*100).toFixed(2) }%; `)
but also if you want to reduce bytes count you send to client you can just use jpeg or webp and just send low quality image and high to user or you are using compression method witch compress raw DiffTexture better than jpeg or webp do?