我正在开发一个使用OpenGL的项目,其中服务器需要渲染两个图像:高质量图像和低质量图像。目标是计算两者之间的差异图像并将该差异发送给客户端。然后客户端渲染低质量图像并将其与接收到的差异图像组合以重建高质量图像。
在服务器端,我通过直接减去片段着色器中的两个图像并将结果作为纹理输出来计算它们之间的差异。
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D HighTexture;
uniform sampler2D LowTexture;
void main()
{
FragColor = texture(HighTexture, TexCoord) - texture(LowTexture, TexCoord);
}
然后客户端:
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D LowTexture;
uniform sampler2D DiffTexture;
void main()
{
FragColor = texture(LowTexture, TexCoord) + texture(DiffTexture, TexCoord);
}
但是,当减法结果为负数时(例如:高图像有阴影),我遇到一个问题:OpenGL自动将负值截断为零,这导致客户端渲染不正确。
两张图片都是RGB类型,纹理格式是GL_UNSIGNED_BYTE。
如果改用GL_RGBA32F等浮点纹理格式,差异图像的尺寸会变得更大,这与降低传输比特率的目标背道而驰。由于发送差异图像的主要目的是减少传输的数据量,因此使用浮点纹理会显着增加数据大小并抵消压缩的优势。
我需要什么帮助:
如何处理负值,同时仍保持纹理大小足够小以实现高效传输?
如何防止OpenGL在计算两幅图像之间的差异时自动截断负值?
有没有办法在减法结果中保留负值,或者我应该将纹理格式更改为支持浮点值的格式?
[0, 1] 范围内的两个实数之间的差异将在 [-1, 1] 范围内,即两倍大。因此,如果您想留在实数领域,您需要更改差异纹理以使用
GL_RGBA8_SNORM
内部格式。然而,这将是一个有损转换,因为您将在相同的八位中编码两倍大的范围。
如果您确实需要无损转换,那么您需要使用模运算。切换所有纹理(高、低和差异)以使用
GL_RGBA8UI
- 这样算术将环绕而不是截断。
在服务器上你可以这样做:
void main()
{
FragColor = texture(LowTexture, TexCoord) - texture(HighTexture, TexCoord) + vec4(0.5, 0.5, 0.5, 1.0);
}
在客户端:
void main()
{
FragColor = texture(LowTexture, TexCoord) - texture(DiffTexture, TexCoord) - vec4(0.5, 0.5, 0.5, 1.0);
}
例如,如果 highTex 每个 lowTex 像素有 16x16 像素,并且 lowTex 像素是 highTex 像素的平均值,则在使用此方法的情况下,diffTexture 像素将在 0 到 1 的范围内
这是小的 js 代码,用于测试 highTex~98.75%
rgb 像素
50_000 * 16*16 = 38_400_000
但是如果您想减少发送给客户端的字节数,您可以只使用 jpeg 或 webp 并只发送低质量图像和高质量图像给用户,或者您正在使用比 jpeg 或 webp 更好的压缩原始 DiffTexture 的压缩方法?