From 917ca03e20097daa45f8d6451107696a348f858d Mon Sep 17 00:00:00 2001 From: "Alexander G. Morano" Date: Sat, 3 Aug 2024 23:57:42 -0700 Subject: [PATCH] 32bit precision for all glsl textures/buffers better rgb/lab conversions --- node_list.json | 2 +- pyproject.toml | 2 +- res/glsl/color-convert_lab2rgb.frag | 42 ++++++++++++++++------------- res/glsl/color-convert_rgb2lab.frag | 18 +++++-------- sup/shader.py | 7 +++-- 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/node_list.json b/node_list.json index 40a9b7a..da87346 100644 --- a/node_list.json +++ b/node_list.json @@ -20,7 +20,7 @@ "GLSL HSV-2-LAB (JOV) \ud83e\uddd9\ud83c\udffd": "Convert HSV input to LAB", "GLSL HSV-2-RGB (JOV) \ud83e\uddd9\ud83c\udffd": "Convert HSV input to RGB", "GLSL LAB-2-HSV (JOV) \ud83e\uddd9\ud83c\udffd": "Convert LAB color space to HSV", - "GLSL LAB-2-RGB (JOV) \ud83e\uddd9\ud83c\udffd": "Convert LAB color space to RGB", + "GLSL LAB-2-RGB (JOV) \ud83e\uddd9\ud83c\udffd": "Convert LAB input to RGB", "GLSL NORMAL (JOV) \ud83e\uddd9\ud83c\udffd": "Convert input into a Normal map", "GLSL RGB-2-HSV (JOV) \ud83e\uddd9\ud83c\udffd": "Convert RGB input to HSV", "GLSL RGB-2-LAB (JOV) \ud83e\uddd9\ud83c\udffd": "Convert RGB input to LAB", diff --git a/pyproject.toml b/pyproject.toml index 8555dcf..e45d5fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "jovimetrix" description = "Integrates Webcam, MIDI, Spout and GLSL shader support. Animation via tick. Parameter manipulation with wave generator. Math operations with Unary and Binary support. Value conversion for all major types (int, string, list, dict, Image, Mask). Shape mask generation, image stacking and channel ops, batch splitting, merging and randomizing, load images and video from anywhere, dynamic bus routing with a single node, export support for GIPHY, save output anywhere! flatten, crop, transform; check colorblindness, make stereogram or stereoscopic images, or liner interpolate values and more." -version = "1.2.9" +version = "1.3.0" license = { file = "LICENSE" } dependencies = [ "aenum>=3.1.15, <4", diff --git a/res/glsl/color-convert_lab2rgb.frag b/res/glsl/color-convert_lab2rgb.frag index d7fc0ea..a7ea981 100644 --- a/res/glsl/color-convert_lab2rgb.frag +++ b/res/glsl/color-convert_lab2rgb.frag @@ -1,5 +1,5 @@ // name: LAB-2-RGB -// desc: Convert LAB color space to RGB +// desc: Convert LAB input to RGB // category: convert uniform sampler2D image; @@ -7,34 +7,38 @@ uniform sampler2D image; void mainImage(out vec4 fragColor, vec2 fragCoord) { vec2 uv = fragCoord.xy / iResolution.xy; vec4 color = texture(image, uv); - - // Denormalize LAB vec3 lab = color.rgb; - float L = lab.x * 100.0; - float a = lab.y * 255.0 - 128.0; - float b = lab.z * 255.0 - 128.0; // LAB to XYZ - float y = (L + 16.0) / 116.0; - float x = a / 500.0 + y; - float z = y - b / 200.0; + vec3 f; + f.y = (lab.x + 16.0) / 116.0; + f.x = lab.y / 500.0 + f.y; + f.z = f.y - lab.z / 200.0; vec3 xyz; - xyz.x = 0.95047 * ((x * x * x > 0.008856) ? x * x * x : (x - 16.0 / 116.0) / 7.787); - xyz.y = 1.00000 * ((y * y * y > 0.008856) ? y * y * y : (y - 16.0 / 116.0) / 7.787); - xyz.z = 1.08883 * ((z * z * z > 0.008856) ? z * z * z : (z - 16.0 / 116.0) / 7.787); + xyz.x = (f.x > 0.206897) ? pow(f.x, 3.0) : (f.x - 16.0 / 116.0) / 7.787; + xyz.y = (f.y > 0.206897) ? pow(f.y, 3.0) : (f.y - 16.0 / 116.0) / 7.787; + xyz.z = (f.z > 0.206897) ? pow(f.z, 3.0) : (f.z - 16.0 / 116.0) / 7.787; + + // D65 reference white + xyz *= vec3(95.047, 100.0, 108.883); // XYZ to RGB - vec3 rgb; - rgb.r = xyz.x * 3.2406 + xyz.y * -1.5372 + xyz.z * -0.4986; - rgb.g = xyz.x * -0.9689 + xyz.y * 1.8758 + xyz.z * 0.0415; - rgb.b = xyz.x * 0.0557 + xyz.y * -0.2040 + xyz.z * 1.0570; + vec3 rgb = xyz / 100.0 * mat3( + 3.2404542, -1.5371385, -0.4985314, + -0.9692660, 1.8760108, 0.0415560, + 0.0556434, -0.2040259, 1.0572252 + ); // Apply gamma correction - rgb = (rgb > 0.0031308) ? 1.055 * pow(rgb, vec3(1.0 / 2.4)) - 0.055 : 12.92 * rgb; + rgb = vec3( + (rgb.r > 0.0031308) ? 1.055 * pow(rgb.r, 1.0 / 2.4) - 0.055 : 12.92 * rgb.r, + (rgb.g > 0.0031308) ? 1.055 * pow(rgb.g, 1.0 / 2.4) - 0.055 : 12.92 * rgb.g, + (rgb.b > 0.0031308) ? 1.055 * pow(rgb.b, 1.0 / 2.4) - 0.055 : 12.92 * rgb.b + ); - // Clamp to [0, 1] range - rgb = clamp(rgb, 0.0, 1.0); + // Scale back to 0-255 range + rgb *= 255.0; fragColor = vec4(rgb, color.a); } \ No newline at end of file diff --git a/res/glsl/color-convert_rgb2lab.frag b/res/glsl/color-convert_rgb2lab.frag index 80fbe33..abe4174 100644 --- a/res/glsl/color-convert_rgb2lab.frag +++ b/res/glsl/color-convert_rgb2lab.frag @@ -7,13 +7,14 @@ uniform sampler2D image; void mainImage(out vec4 fragColor, vec2 fragCoord) { vec2 uv = fragCoord.xy / iResolution.xy; vec4 color = texture(image, uv); - vec3 rgb = color.rgb; // RGB to XYZ + vec3 rgb = color.rgb / 255; vec3 xyz; xyz.r = (rgb.r > 0.04045) ? pow((rgb.r + 0.055) / 1.055, 2.4) : rgb.r / 12.92; xyz.g = (rgb.g > 0.04045) ? pow((rgb.g + 0.055) / 1.055, 2.4) : rgb.g / 12.92; xyz.b = (rgb.b > 0.04045) ? pow((rgb.b + 0.055) / 1.055, 2.4) : rgb.b / 12.92; + xyz *= 100; xyz = xyz * mat3( 0.4124564, 0.3575761, 0.1804375, @@ -25,21 +26,14 @@ void mainImage(out vec4 fragColor, vec2 fragCoord) { xyz /= vec3(95.047, 100.0, 108.883); // D65 reference white vec3 f; - f.x = (xyz.x > 0.008856) ? pow(xyz.x, 1.0/3.0) : (7.787 * xyz.x) + (16.0 / 116.0); - f.y = (xyz.y > 0.008856) ? pow(xyz.y, 1.0/3.0) : (7.787 * xyz.y) + (16.0 / 116.0); - f.z = (xyz.z > 0.008856) ? pow(xyz.z, 1.0/3.0) : (7.787 * xyz.z) + (16.0 / 116.0); + f.x = (xyz.x > 0.008856) ? pow(xyz.x, 0.33333333) : (7.787 * xyz.x) + 0.13793103; // 16.0 / 116.0 = 0.13793103 + f.y = (xyz.y > 0.008856) ? pow(xyz.y, 0.33333333) : (7.787 * xyz.y) + 0.13793103; + f.z = (xyz.z > 0.008856) ? pow(xyz.z, 0.33333333) : (7.787 * xyz.z) + 0.13793103; vec3 lab; lab.x = (116.0 * f.y) - 16.0; // L lab.y = 500.0 * (f.x - f.y); // a lab.z = 200.0 * (f.y - f.z); // b - // Normalize LAB values to 0-1 range for output - lab = vec3( - lab.x / 100.0, - (lab.y + 128.0) / 255.0, - (lab.z + 128.0) / 255.0 - ); - fragColor = vec4(lab, color.a); -} \ No newline at end of file +} diff --git a/sup/shader.py b/sup/shader.py index 177426a..826d42a 100644 --- a/sup/shader.py +++ b/sup/shader.py @@ -94,6 +94,8 @@ void mainImage( out vec4 fragColor, vec2 fragCoord ) { PROG_VERTEX = """ #version 330 core +precision highp float; + void main() { vec2 verts[3] = vec2[](vec2(-1, -1), vec2(3, -1), vec2(-1, 3)); @@ -242,7 +244,8 @@ void main() gl.glBindTexture(gl.GL_TEXTURE_2D, self.__fbo_texture) glfw.set_window_size(self.__window, self.__size[0], self.__size[1]) - gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, self.__size[0], self.__size[1], 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None) + gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F, self.__size[0], self.__size[1], 0, gl.GL_RGBA, gl.GL_FLOAT, None) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, self.__fbo_texture, 0) @@ -368,7 +371,7 @@ void main() val = val[::-1,:] val = val.astype(np.float32) / 255.0 val = cv2.resize(val, self.__size, interpolation=cv2.INTER_LINEAR) - gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, self.__size[0], self.__size[1], 0, gl.GL_RGBA, gl.GL_FLOAT, val) + gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F, self.__size[0], self.__size[1], 0, gl.GL_RGBA, gl.GL_FLOAT, val) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE)