Skip to content

Commit 9371aca

Browse files
author
B Wu
committed
fix: add mixbox support to webgl
1 parent e7ac57f commit 9371aca

File tree

2 files changed

+117
-54
lines changed

2 files changed

+117
-54
lines changed

src/components/projects/palette-posterization/WebGlCanvas.tsx

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react';
22
import { RgbColor } from '../../common/colorUtils';
33
import { initArrayBuffer, initProgram, initTexture, setAttributeToArrayBuffer, setTexture } from '../../common/webglUtils';
44
import { ColorMetricType, getFragmentShader, RenderedColorReducerType } from './utils';
5+
import mixbox from 'mixbox';
56

67
const VERTEX_SHADER = `
78
attribute vec2 a_position;
@@ -21,56 +22,6 @@ void main() {
2122
}
2223
`
2324

24-
const FRAGMENT_SHADER = `
25-
precision mediump float;
26-
27-
uniform int u_paletteSize;
28-
uniform vec4 u_palette[64];
29-
uniform sampler2D u_image;
30-
varying vec2 v_texCoord;
31-
32-
float metric(in vec4 color1, in vec4 color2)
33-
{
34-
vec4 diff = color1 - color2;
35-
return diff.r * diff.r + diff.g * diff.g + diff.b * diff.b;
36-
}
37-
38-
vec4 reducer(in vec4 textureColor, in vec4 paletteColor)
39-
{
40-
// palette color reducer
41-
return vec4(paletteColor);
42-
}
43-
44-
void main() {
45-
if (u_paletteSize == 0)
46-
{
47-
gl_FragColor = texture2D(u_image, v_texCoord);
48-
return;
49-
}
50-
51-
vec4 currentColor = texture2D(u_image, v_texCoord);
52-
float minDistance = 1.0 / 0.0; // inf
53-
float currentDistance = 0.0;
54-
vec4 paletteColor = vec4(currentColor);
55-
56-
for(int i = 0; i < 64; i++)
57-
{
58-
if (i >= u_paletteSize)
59-
break;
60-
61-
currentDistance = metric(currentColor, u_palette[i]);
62-
63-
if (currentDistance < minDistance)
64-
{
65-
minDistance = currentDistance;
66-
paletteColor = vec4(u_palette[i]);
67-
}
68-
}
69-
70-
gl_FragColor = reducer(currentColor, paletteColor);
71-
}
72-
`
73-
7425
interface WebGlCanvasProps {
7526
image: HTMLImageElement | undefined;
7627
palette: RgbColor[];
@@ -87,7 +38,6 @@ const WebGlCanvas: React.FC<WebGlCanvasProps> = ({
8738
const canvasRef = useRef<HTMLCanvasElement>(null);
8839

8940
useEffect(() => {
90-
console.log('woah')
9141
const canvas = canvasRef.current;
9242
const gl = canvas?.getContext('webgl2') ?? undefined;
9343

@@ -164,12 +114,18 @@ const WebGlCanvas: React.FC<WebGlCanvasProps> = ({
164114
const texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
165115
setAttributeToArrayBuffer(gl, texCoordBuffer, texCoordLocation);
166116

117+
if (colorReducer === RenderedColorReducerType.MIXBOX) {
118+
gl.activeTexture(gl.TEXTURE1);
119+
gl.bindTexture(gl.TEXTURE_2D, mixbox.lutTexture(gl));
120+
gl.uniform1i(gl.getUniformLocation(program, 'mixbox_lut'), 0);
121+
}
122+
167123
gl.drawArrays(gl.TRIANGLES, 0, 6);
168124
}, [ image, palette, colorMetric, colorReducer ])
169125

170126
if (image === undefined) {
171127
return (
172-
<div className='w-full h-96 bg-enabled' />
128+
<></>
173129
)
174130
}
175131

src/components/projects/palette-posterization/utils.ts

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export interface ColorPaletteChangeResponseData {
174174

175175
export const RGB_TO_HSL_SHADER_SOURCE = `
176176
vec3 rgb2hsl(vec3 color) {
177-
vec3 hsl; // init to 0 to avoid warnings ? (and reverse if + remove first part)
177+
vec3 hsl = vec3(0.0, 0.0, 0.0);
178178
179179
float fmin = min(min(color.r, color.g), color.b); //Min. value of RGB
180180
float fmax = max(max(color.r, color.g), color.b); //Max. value of RGB
@@ -388,7 +388,114 @@ vec4 reducer(in vec4 textureColor, in vec4 paletteColor)
388388
return vec4(hsl2rgb(vec3(paletteHsl.x, textureHsl.yz)), 1.0);
389389
}
390390
`], [RenderedColorReducerType.MIXBOX, `
391-
${mixbox.glsl()}
391+
uniform sampler2D mixbox_lut;
392+
393+
vec3 mixbox_eval_polynomial(vec3 c)
394+
{
395+
float c0 = c[0];
396+
float c1 = c[1];
397+
float c2 = c[2];
398+
float c3 = 1.0 - (c0 + c1 + c2);
399+
400+
float c00 = c0 * c0;
401+
float c11 = c1 * c1;
402+
float c22 = c2 * c2;
403+
float c01 = c0 * c1;
404+
float c02 = c0 * c2;
405+
float c12 = c1 * c2;
406+
float c33 = c3 * c3;
407+
408+
return (c0*c00) * vec3(+0.07717053, +0.02826978, +0.24832992) +
409+
(c1*c11) * vec3(+0.95912302, +0.80256528, +0.03561839) +
410+
(c2*c22) * vec3(+0.74683774, +0.04868586, +0.00000000) +
411+
(c3*c33) * vec3(+0.99518138, +0.99978149, +0.99704802) +
412+
(c00*c1) * vec3(+0.04819146, +0.83363781, +0.32515377) +
413+
(c01*c1) * vec3(-0.68146950, +1.46107803, +1.06980936) +
414+
(c00*c2) * vec3(+0.27058419, -0.15324870, +1.98735057) +
415+
(c02*c2) * vec3(+0.80478189, +0.67093710, +0.18424500) +
416+
(c00*c3) * vec3(-0.35031003, +1.37855826, +3.68865000) +
417+
(c0*c33) * vec3(+1.05128046, +1.97815239, +2.82989073) +
418+
(c11*c2) * vec3(+3.21607125, +0.81270228, +1.03384539) +
419+
(c1*c22) * vec3(+2.78893374, +0.41565549, -0.04487295) +
420+
(c11*c3) * vec3(+3.02162577, +2.55374103, +0.32766114) +
421+
(c1*c33) * vec3(+2.95124691, +2.81201112, +1.17578442) +
422+
(c22*c3) * vec3(+2.82677043, +0.79933038, +1.81715262) +
423+
(c2*c33) * vec3(+2.99691099, +1.22593053, +1.80653661) +
424+
(c01*c2) * vec3(+1.87394106, +2.05027182, -0.29835996) +
425+
(c01*c3) * vec3(+2.56609566, +7.03428198, +0.62575374) +
426+
(c02*c3) * vec3(+4.08329484, -1.40408358, +2.14995522) +
427+
(c12*c3) * vec3(+6.00078678, +2.55552042, +1.90739502);
428+
}
429+
430+
float mixbox_srgb_to_linear(float x)
431+
{
432+
return (x >= 0.04045) ? pow((x + 0.055) / 1.055, 2.4) : x/12.92;
433+
}
434+
435+
float mixbox_linear_to_srgb(float x)
436+
{
437+
return (x >= 0.0031308) ? 1.055*pow(x, 1.0/2.4) - 0.055 : 12.92*x;
438+
}
439+
440+
vec3 mixbox_srgb_to_linear(vec3 rgb)
441+
{
442+
return vec3(mixbox_srgb_to_linear(rgb.r),
443+
mixbox_srgb_to_linear(rgb.g),
444+
mixbox_srgb_to_linear(rgb.b));
445+
}
446+
447+
vec3 mixbox_linear_to_srgb(vec3 rgb)
448+
{
449+
return vec3(mixbox_linear_to_srgb(rgb.r),
450+
mixbox_linear_to_srgb(rgb.g),
451+
mixbox_linear_to_srgb(rgb.b));
452+
}
453+
454+
mat3 mixbox_rgb_to_latent(vec3 rgb)
455+
{
456+
rgb = clamp(rgb, 0.0, 1.0);
457+
458+
float x = rgb.r * 63.0;
459+
float y = rgb.g * 63.0;
460+
float z = rgb.b * 63.0;
461+
462+
float iz = floor(z);
463+
464+
float x0 = mod(iz, 8.0) * 64.0;
465+
float y0 = floor(iz / 8.0) * 64.0;
466+
467+
float x1 = mod(iz + 1.0, 8.0) * 64.0;
468+
float y1 = floor((iz + 1.0) / 8.0) * 64.0;
469+
470+
vec2 uv0 = vec2(x0 + x + 0.5, y0 + y + 0.5) / 512.0;
471+
vec2 uv1 = vec2(x1 + x + 0.5, y1 + y + 0.5) / 512.0;
472+
473+
if (texture2D(mixbox_lut, vec2(0.5, 0.5) / 512.0).b < 0.1)
474+
{
475+
uv0.y = 1.0 - uv0.y;
476+
uv1.y = 1.0 - uv1.y;
477+
}
478+
479+
vec3 c = mix(texture2D(mixbox_lut, uv0).rgb, texture2D(mixbox_lut, uv1).rgb, z - iz);
480+
481+
return mat3(c, rgb - mixbox_eval_polynomial(c), vec3(0.0));
482+
}
483+
484+
vec3 mixbox_latent_to_rgb(mat3 latent)
485+
{
486+
vec3 rgb = clamp(mixbox_eval_polynomial(latent[0]) + latent[1], 0.0, 1.0);
487+
return rgb;
488+
}
489+
490+
vec3 mixbox_lerp(vec3 color1, vec3 color2, float t)
491+
{
492+
return mixbox_latent_to_rgb((1.0-t)*mixbox_rgb_to_latent(color1) + t*mixbox_rgb_to_latent(color2));
493+
}
494+
495+
vec4 mixbox_lerp(vec4 color1, vec4 color2, float t)
496+
{
497+
return vec4(mixbox_lerp(color1.rgb, color2.rgb, t), mix(color1.a, color2.a, t));
498+
}
392499
393500
vec4 reducer(in vec4 textureColor, in vec4 paletteColor)
394501
{

0 commit comments

Comments
 (0)