ron*_*nag 8 c c++ shader image-processing glsl
我有一个应用程序,用户应该能够使用滑块修改图像的色调,饱和度和亮度.使用GLSL片段着色器在GPU上完成所有图像处理.
我的问题是由于广泛的分支,RGB - > HSL - > RGB转换在gpu上相当昂贵.
我的问题是我是否可以将用户"颜色调整"转换为其他颜色空间,这可以更有效地计算GPU上调整后的图像.
Spa*_*ial 12
假设GPU中的分支和代码中的分支是一回事是错误的.
对于简单的条件,根本就没有任何分支.GPU具有条件移动指令,可直接转换为三元表达式和简单的if-else语句.
事情有问题的地方是你有嵌套条件或多个有条件依赖的操作.然后你必须考虑GLSL编译器是否足够智能将它全部转换为cmoves.只要有可能,编译器将发出执行所有分支的代码,并通过条件移动重新组合结果,但它不能总是这样做.
你必须知道什么时候帮助它.永远不要猜测何时可以测量 - 使用AMD的GPU着色器分析器或Nvidia的GCG来查看组件输出.GPU的指令集非常有限且简单,所以不要害怕"汇编"这个词.
这是一对RGB/HSL转换函数,我已经改变了它们,因此它们可以很好地与AMD的GLSL编译器以及汇编输出一起使用.感谢Paul Bourke提供的原始C转换代码.
// HSL range 0:1
vec4 convertRGBtoHSL( vec4 col )
{
float red = col.r;
float green = col.g;
float blue = col.b;
float minc = min3( col.r, col.g, col.b );
float maxc = max3( col.r, col.g, col.b );
float delta = maxc - minc;
float lum = (minc + maxc) * 0.5;
float sat = 0.0;
float hue = 0.0;
if (lum > 0.0 && lum < 1.0) {
float mul = (lum < 0.5) ? (lum) : (1.0-lum);
sat = delta / (mul * 2.0);
}
vec3 masks = vec3(
(maxc == red && maxc != green) ? 1.0 : 0.0,
(maxc == green && maxc != blue) ? 1.0 : 0.0,
(maxc == blue && maxc != red) ? 1.0 : 0.0
);
vec3 adds = vec3(
((green - blue ) / delta),
2.0 + ((blue - red ) / delta),
4.0 + ((red - green) / delta)
);
float deltaGtz = (delta > 0.0) ? 1.0 : 0.0;
hue += dot( adds, masks );
hue *= deltaGtz;
hue /= 6.0;
if (hue < 0.0)
hue += 1.0;
return vec4( hue, sat, lum, col.a );
}
Run Code Online (Sandbox Code Playgroud)
此功能的汇编输出:
1 x: MIN ____, R0.y, R0.z
y: ADD R127.y, -R0.x, R0.z
z: MAX ____, R0.y, R0.z
w: ADD R127.w, R0.x, -R0.y
t: ADD R127.x, R0.y, -R0.z
2 y: MAX R126.y, R0.x, PV1.z
w: MIN R126.w, R0.x, PV1.x
t: MOV R1.w, R0.w
3 x: ADD R125.x, -PV2.w, PV2.y
y: SETE_DX10 ____, R0.x, PV2.y
z: SETNE_DX10 ____, R0.y, PV2.y
w: SETE_DX10 ____, R0.y, PV2.y
t: SETNE_DX10 ____, R0.z, PV2.y
4 x: CNDE_INT R123.x, PV3.y, 0.0f, PV3.z
y: CNDE_INT R125.y, PV3.w, 0.0f, PS3
z: SETNE_DX10 ____, R0.x, R126.y
w: SETE_DX10 ____, R0.z, R126.y
t: RCP_e R125.w, PV3.x
5 x: MUL_e ____, PS4, R127.y
y: CNDE_INT R123.y, PV4.w, 0.0f, PV4.z
z: ADD/2 R127.z, R126.w, R126.y VEC_021
w: MUL_e ____, PS4, R127.w
t: CNDE_INT R126.x, PV4.x, 0.0f, 1065353216
6 x: MUL_e ____, R127.x, R125.w
y: CNDE_INT R123.y, R125.y, 0.0f, 1065353216
z: CNDE_INT R123.z, PV5.y, 0.0f, 1065353216
w: ADD ____, PV5.x, (0x40000000, 2.0f).y
t: ADD ____, PV5.w, (0x40800000, 4.0f).z
7 x: DOT4 ____, R126.x, PV6.x
y: DOT4 ____, PV6.y, PV6.w
z: DOT4 ____, PV6.z, PS6
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f
t: SETGT_DX10 R125.w, 0.5, R127.z
8 x: ADD R126.x, PV7.x, 0.0f
y: SETGT_DX10 ____, R127.z, 0.0f
z: ADD ____, -R127.z, 1.0f
w: SETGT_DX10 ____, R125.x, 0.0f
t: SETGT_DX10 ____, 1.0f, R127.z
9 x: CNDE_INT R127.x, PV8.y, 0.0f, PS8
y: CNDE_INT R123.y, R125.w, PV8.z, R127.z
z: CNDE_INT R123.z, PV8.w, 0.0f, 1065353216
t: MOV R1.z, R127.z
10 x: MOV*2 ____, PV9.y
w: MUL ____, PV9.z, R126.x
11 z: MUL_e R127.z, PV10.w, (0x3E2AAAAB, 0.1666666716f).x
t: RCP_e ____, PV10.x
12 x: ADD ____, PV11.z, 1.0f
y: SETGT_DX10 ____, 0.0f, PV11.z
z: MUL_e ____, R125.x, PS11
13 x: CNDE_INT R1.x, PV12.y, R127.z, PV12.x
y: CNDE_INT R1.y, R127.x, 0.0f, PV12.z
Run Code Online (Sandbox Code Playgroud)
请注意,没有分支指令.它是有条件的一直移动,几乎和我写的一样.
条件移动所需的硬件只是一个二进制比较器(每位5个门)和一串跟踪.非常快.
另一个有趣的事情是,没有分歧.相反,编译器使用近似倒数和乘法指令.它也适用于sqrt操作以及很多时候.您可以使用(例如)SSE rcpps和rsqrtps指令在CPU上提取相同的技巧.
现在反向操作:
// HSL [0:1] to RGB [0:1]
vec4 convertHSLtoRGB( vec4 col )
{
const float onethird = 1.0 / 3.0;
const float twothird = 2.0 / 3.0;
const float rcpsixth = 6.0;
float hue = col.x;
float sat = col.y;
float lum = col.z;
vec3 xt = vec3(
rcpsixth * (hue - twothird),
0.0,
rcpsixth * (1.0 - hue)
);
if (hue < twothird) {
xt.r = 0.0;
xt.g = rcpsixth * (twothird - hue);
xt.b = rcpsixth * (hue - onethird);
}
if (hue < onethird) {
xt.r = rcpsixth * (onethird - hue);
xt.g = rcpsixth * hue;
xt.b = 0.0;
}
xt = min( xt, 1.0 );
float sat2 = 2.0 * sat;
float satinv = 1.0 - sat;
float luminv = 1.0 - lum;
float lum2m1 = (2.0 * lum) - 1.0;
vec3 ct = (sat2 * xt) + satinv;
vec3 rgb;
if (lum >= 0.5)
rgb = (luminv * ct) + lum2m1;
else rgb = lum * ct;
return vec4( rgb, col.a );
}
Run Code Online (Sandbox Code Playgroud)
(2013年7月5日编辑:我在翻译这个函数时出错.组装也已更新).
装配输出:
1 x: ADD ____, -R2.x, 1.0f
y: ADD ____, R2.x, (0xBF2AAAAB, -0.6666666865f).x
z: ADD R0.z, -R2.x, (0x3F2AAAAB, 0.6666666865f).y
w: ADD R0.w, R2.x, (0xBEAAAAAB, -0.3333333433f).z
2 x: SETGT_DX10 R0.x, (0x3F2AAAAB, 0.6666666865f).x, R2.x
y: MUL R0.y, PV2.x, (0x40C00000, 6.0f).y
z: MOV R1.z, 0.0f
w: MUL R1.w, PV2.y, (0x40C00000, 6.0f).y
3 x: MUL ____, R0.w, (0x40C00000, 6.0f).x
y: MUL ____, R0.z, (0x40C00000, 6.0f).x
z: ADD R0.z, -R2.x, (0x3EAAAAAB, 0.3333333433f).y
w: MOV ____, 0.0f
4 x: CNDE_INT R0.x, R0.x, R0.y, PV4.x
y: CNDE_INT R0.y, R0.x, R1.z, PV4.y
z: CNDE_INT R1.z, R0.x, R1.w, PV4.w
w: SETGT_DX10 R1.w, (0x3EAAAAAB, 0.3333333433f).x, R2.x
5 x: MUL ____, R2.x, (0x40C00000, 6.0f).x
y: MUL ____, R0.z, (0x40C00000, 6.0f).x
z: ADD R0.z, -R2.y, 1.0f
w: MOV ____, 0.0f
6 x: CNDE_INT R127.x, R1.w, R0.x, PV6.w
y: CNDE_INT R127.y, R1.w, R0.y, PV6.x
z: CNDE_INT R127.z, R1.w, R1.z, PV6.y
w: ADD R1.w, -R2.z, 1.0f
7 x: MULADD R0.x, R2.z, (0x40000000, 2.0f).x, -1.0f
y: MIN*2 ____, PV7.x, 1.0f
z: MIN*2 ____, PV7.y, 1.0f
w: MIN*2 ____, PV7.z, 1.0f
8 x: MULADD R1.x, PV8.z, R2.y, R0.z
y: MULADD R127.y, PV8.w, R2.y, R0.z
z: SETGE_DX10 R1.z, R2.z, 0.5
w: MULADD R0.w, PV8.y, R2.y, R0.z
9 x: MULADD R0.x, R1.w, PV9.x, R0.x
y: MULADD R0.y, R1.w, PV9.y, R0.x
z: MUL R0.z, R2.z, PV9.y
w: MULADD R1.w, R1.w, PV9.w, R0.x
10 x: MUL ____, R2.z, R0.w
y: MUL ____, R2.z, R1.x
w: MOV R2.w, R2.w
11 x: CNDE_INT R2.x, R1.z, R0.z, R0.y
y: CNDE_INT R2.y, R1.z, PV11.y, R0.x
z: CNDE_INT R2.z, R1.z, PV11.x, R1.w
Run Code Online (Sandbox Code Playgroud)
再没有分支机构.百胜!
对于亮度和饱和度,您可以使用YUV (实际上是YCbCr).它很容易从RGB转换回来.不需要分支.通过增加或减少Cr和Cb来控制饱和度.亮度是Y.
通过旋转Cb和Cr组件(它实际上是一个3D矢量)可以得到类似于HSL色调修改的东西,但当然这取决于你的应用程序是否足够.

编辑:颜色分量(Cb,Cr)是如上所述的颜色平面中的点.如果你采取任何随机点并围绕中心旋转,结果是色调变化.但由于机制与HSL略有不同,结果并不完全相同.
图片来自维基百科的公共领域.
小智 5
我有同样的问题,但我找到了一个非常简单的解决方案,它适合我的需求,也许对你也有用。颜色的饱和度基本上是它的扩散,我相信这是 RGB 值与其平均值之间的欧几里德距离。无论如何,如果您只是简单地取 RGB 值的最大值和最小值的平均值,并相对于该枢轴缩放颜色,则效果是饱和度的非常可观的增加(或减少)。
在 glsl 着色器中你会写:
float pivot=(min(min(color.x, color.y), color.z)+max(max(color.x, color.y), color.z))/2.0;
color.xyz -= vec3( pivot );
color.xyz *= saturationScale;
color.xyz += vec3( pivot );
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3897 次 |
| 最近记录: |