GLSL:如何根据Photoshops曲线值计算片段输出RGB值?
GLSL: How to calculate fragments output RGB value based on Photoshops curve value?
我正在 Android 中使用 OPENGL
进行图像编辑,我已经使用 photoshop 曲线对图像应用滤镜,现在我想在 Android 中使用 glsl
。是否有任何公式可以使用 photoshops 曲线输出值计算单个片段颜色?
编辑
photoshop 曲线背后的数学问题已经在这个问题中得到解答
How to recreate the math behind photoshop curves 但我不太清楚如何在 glsl fragment shader
中重现相同的内容。
我的 photoshop 曲线的屏幕截图
您正在寻找函数 fragColour = curves(inColour, constants...)
。如果只有红色、绿色和蓝色的一条曲线,则可以分别对每条曲线应用相同的曲线。 This answer 有一个 link(如下)来编写沿函数绘制点的代码。关键行是:
double y = ...
您 return 来自 curves
。循环中的变量 x
就是你的 inColour
。您现在需要的只是来自 points
和二阶导数 sd
数组的常量。这些你必须作为 uniforms 传递。该函数首先必须找出每种颜色 x
之间的哪个点(找到 cur
、next
、sd[i]
和 sd[i+1]
),然后计算并 return y
.
编辑:
如果您只想应用您在 photoshop 中创建的一些曲线,那么问题就简单多了。最简单的方法是创建一个具有相似形状的简单函数。我用these as a starting point. A gamma correction曲线也挺常见的。
这太过分了,但如果您确实需要更精确的结果,您可以创建一个具有线性渐变的图像(例如,从黑到白的 255 像素),在 photoshop 中对其应用滤镜,结果就变成了查找 table。将所有 255 个值传递给着色器非常昂贵,因此如果它是平滑曲线,您可以尝试一些曲线拟合工具 (for example)。
获得函数后,只需将其应用到 GLSL 中的颜色即可。例如,应用伽玛曲线 like this:
fragColour = vec4(pow(inColour.rgb, 1.0 / gamma.rgb), inColour.a);
EDIT2:
您的曲线看起来与此非常相似:
fragColour = vec4(pow(inColour.rgb, 1.0 / vec3(0.6)), inColour.a);
或者更简单:
fragColour = vec4(inColour.rgb * inColour.rgb, inColour.a);
以防万一 the link 死了,我会把代码复制到这里(不是我测试过的):
Point[] points = /* liste de points, triés par "x" croissants */
double[] sd = secondDerivative(points);
for(int i=0;i<points.length-1;i++) {
Point cur = points[i];
Point next = points[i+1];
for(int x=cur.x;x<next.x;x++) {
double t = (double)(x-cur.x)/(next.x-cur.x);
double a = 1-t;
double b = t;
double h = next.x-cur.x;
double y= a*cur.y + b*next.y + (h*h/6)*( (a*a*a-a)*sd[i]+ (b*b*b-b)*sd[i+1] );
draw(x,y); /* ou tout autre utilisation */
}
}
和二阶导数:
public static double[] secondDerivative(Point... P) {
int n = P.length;
double yp1=0.0;
double ypn=0.0;
// build the tridiagonal system
// (assume 0 boundary conditions: y2[0]=y2[-1]=0)
double[][] matrix = new double[n][3];
double[] result = new double[n];
matrix[0][1]=1;
for(int i=1;i<n-1;i++) {
matrix[i][0]=(double)(P[i].x-P[i-1].x)/6;
matrix[i][1]=(double)(P[i+1].x-P[i-1].x)/3;
matrix[i][2]=(double)(P[i+1].x-P[i].x)/6;
result[i]=(double)(P[i+1].y-P[i].y)/(P[i+1].x-P[i].x) - (double)(P[i].y-P[i-1].y)/(P[i].x-P[i-1].x);
}
matrix[n-1][1]=1;
// solving pass1 (up->down)
for(int i=1;i<n;i++) {
double k = matrix[i][0]/matrix[i-1][1];
matrix[i][1] -= k*matrix[i-1][2];
matrix[i][0] = 0;
result[i] -= k*result[i-1];
}
// solving pass2 (down->up)
for(int i=n-2;i>=0;i--) {
double k = matrix[i][2]/matrix[i+1][1];
matrix[i][1] -= k*matrix[i+1][0];
matrix[i][2] = 0;
result[i] -= k*result[i+1];
}
// return second derivative value for each point P
double[] y2 = new double[n];
for(int i=0;i<n;i++) y2[i]=result[i]/matrix[i][1];
return y2;
}
我正在 Android 中使用 OPENGL
进行图像编辑,我已经使用 photoshop 曲线对图像应用滤镜,现在我想在 Android 中使用 glsl
。是否有任何公式可以使用 photoshops 曲线输出值计算单个片段颜色?
编辑
photoshop 曲线背后的数学问题已经在这个问题中得到解答
How to recreate the math behind photoshop curves 但我不太清楚如何在 glsl fragment shader
中重现相同的内容。
我的 photoshop 曲线的屏幕截图
您正在寻找函数 fragColour = curves(inColour, constants...)
。如果只有红色、绿色和蓝色的一条曲线,则可以分别对每条曲线应用相同的曲线。 This answer 有一个 link(如下)来编写沿函数绘制点的代码。关键行是:
double y = ...
您 return 来自 curves
。循环中的变量 x
就是你的 inColour
。您现在需要的只是来自 points
和二阶导数 sd
数组的常量。这些你必须作为 uniforms 传递。该函数首先必须找出每种颜色 x
之间的哪个点(找到 cur
、next
、sd[i]
和 sd[i+1]
),然后计算并 return y
.
编辑:
如果您只想应用您在 photoshop 中创建的一些曲线,那么问题就简单多了。最简单的方法是创建一个具有相似形状的简单函数。我用these as a starting point. A gamma correction曲线也挺常见的。
这太过分了,但如果您确实需要更精确的结果,您可以创建一个具有线性渐变的图像(例如,从黑到白的 255 像素),在 photoshop 中对其应用滤镜,结果就变成了查找 table。将所有 255 个值传递给着色器非常昂贵,因此如果它是平滑曲线,您可以尝试一些曲线拟合工具 (for example)。
获得函数后,只需将其应用到 GLSL 中的颜色即可。例如,应用伽玛曲线 like this:
fragColour = vec4(pow(inColour.rgb, 1.0 / gamma.rgb), inColour.a);
EDIT2:
您的曲线看起来与此非常相似:
fragColour = vec4(pow(inColour.rgb, 1.0 / vec3(0.6)), inColour.a);
或者更简单:
fragColour = vec4(inColour.rgb * inColour.rgb, inColour.a);
以防万一 the link 死了,我会把代码复制到这里(不是我测试过的):
Point[] points = /* liste de points, triés par "x" croissants */
double[] sd = secondDerivative(points);
for(int i=0;i<points.length-1;i++) {
Point cur = points[i];
Point next = points[i+1];
for(int x=cur.x;x<next.x;x++) {
double t = (double)(x-cur.x)/(next.x-cur.x);
double a = 1-t;
double b = t;
double h = next.x-cur.x;
double y= a*cur.y + b*next.y + (h*h/6)*( (a*a*a-a)*sd[i]+ (b*b*b-b)*sd[i+1] );
draw(x,y); /* ou tout autre utilisation */
}
}
和二阶导数:
public static double[] secondDerivative(Point... P) {
int n = P.length;
double yp1=0.0;
double ypn=0.0;
// build the tridiagonal system
// (assume 0 boundary conditions: y2[0]=y2[-1]=0)
double[][] matrix = new double[n][3];
double[] result = new double[n];
matrix[0][1]=1;
for(int i=1;i<n-1;i++) {
matrix[i][0]=(double)(P[i].x-P[i-1].x)/6;
matrix[i][1]=(double)(P[i+1].x-P[i-1].x)/3;
matrix[i][2]=(double)(P[i+1].x-P[i].x)/6;
result[i]=(double)(P[i+1].y-P[i].y)/(P[i+1].x-P[i].x) - (double)(P[i].y-P[i-1].y)/(P[i].x-P[i-1].x);
}
matrix[n-1][1]=1;
// solving pass1 (up->down)
for(int i=1;i<n;i++) {
double k = matrix[i][0]/matrix[i-1][1];
matrix[i][1] -= k*matrix[i-1][2];
matrix[i][0] = 0;
result[i] -= k*result[i-1];
}
// solving pass2 (down->up)
for(int i=n-2;i>=0;i--) {
double k = matrix[i][2]/matrix[i+1][1];
matrix[i][1] -= k*matrix[i+1][0];
matrix[i][2] = 0;
result[i] -= k*result[i+1];
}
// return second derivative value for each point P
double[] y2 = new double[n];
for(int i=0;i<n;i++) y2[i]=result[i]/matrix[i][1];
return y2;
}