add shaders

This commit is contained in:
jrkb 2023-04-11 17:44:46 +02:00
parent 51058def87
commit e1557285de
8 changed files with 449 additions and 0 deletions

View file

@ -0,0 +1,12 @@
#version 330 core
in vec2 position;
out vec3 color;
void main() {
float t = (position.y + 1.0) / 2.0;
vec3 bottom = vec3(75.0, 55.0, 201.0) / 255.0;
vec3 top = vec3(0.0, 12.0, 0.0) / 255.0;
color = mix(bottom, top, t);
}

View file

@ -0,0 +1,15 @@
#version 330 core
const vec2 vertices[4] = vec2[4](
vec2(-1.0, -1.0),
vec2( 1.0, -1.0),
vec2(-1.0, 1.0),
vec2( 1.0, 1.0)
);
out vec2 position;
void main() {
position = vertices[gl_VertexID];
gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0);
}

View file

@ -0,0 +1,182 @@
#version 300 es
precision highp float;
precision highp isampler2D;
precision highp sampler2D;
// Based on: http://wdobbie.com/post/gpu-text-rendering-with-vector-textures/
struct Glyph {
int start, count;
};
struct Curve {
vec2 p0, p1, p2;
};
uniform isampler2D glyphs;
uniform sampler2D curves;
uniform sampler2D iChannel0;
uniform vec4 color;
// Controls for debugging and exploring:
// Size of the window (in pixels) used for 1-dimensional anti-aliasing along each rays.
// 0 - no anti-aliasing
// 1 - normal anti-aliasing
// >=2 - exaggerated effect
uniform float antiAliasingWindowSize;
// Enable a second ray along the y-axis to achieve 2-dimensional anti-aliasing.
uniform bool enableSuperSamplingAntiAliasing;
// Draw control points for debugging (green - on curve, magenta - off curve).
uniform bool enableControlPointsVisualization;
in vec2 uv;
flat in int bufferIndex;
out vec4 result;
Glyph loadGlyph(int index) {
Glyph result;
ivec2 data = texelFetch(glyphs, ivec2(index, 0), 0).xy;
result.start = data.x;
result.count = data.y;
return result;
}
Curve loadCurve(int index) {
Curve result;
result.p0 = texelFetch(curves, ivec2(3*index+0, 0), 0).xy;
result.p1 = texelFetch(curves, ivec2(3*index+1, 0), 0).xy;
result.p2 = texelFetch(curves, ivec2(3*index+2, 0), 0).xy;
return result;
}
float computeCoverage(float inverseDiameter, vec2 p0, vec2 p1, vec2 p2) {
if (p0.y > 0.0 && p1.y > 0.0 && p2.y > 0.0) return 0.0;
if (p0.y < 0.0 && p1.y < 0.0 && p2.y < 0.0) return 0.0;
// Note: Simplified from abc formula by extracting a factor of (-2) from b.
vec2 a = p0 - 2.0*p1 + p2;
vec2 b = p0 - p1;
vec2 c = p0;
float t0, t1;
if (abs(a.y) >= 1e-5) {
// Quadratic segment, solve abc formula to find roots.
float radicand = b.y*b.y - a.y*c.y;
if (radicand <= 0.0) return 0.0;
float s = sqrt(radicand);
t0 = (b.y - s) / a.y;
t1 = (b.y + s) / a.y;
} else {
// Linear segment, avoid division by a.y, which is near zero.
// There is only one root, so we have to decide which variable to
// assign it to based on the direction of the segment, to ensure that
// the ray always exits the shape at t0 and enters at t1. For a
// quadratic segment this works 'automatically', see readme.
float t = p0.y / (p0.y - p2.y);
if (p0.y < p2.y) {
t0 = -1.0;
t1 = t;
} else {
t0 = t;
t1 = -1.0;
}
}
float alpha = 0.0;
if (t0 >= 0.0 && t0 < 1.0) {
float x = (a.x*t0 - 2.0*b.x)*t0 + c.x;
alpha += clamp(x * inverseDiameter + 0.5, 0.0, 1.0);
}
if (t1 >= 0.0 && t1 < 1.0) {
float x = (a.x*t1 - 2.0*b.x)*t1 + c.x;
alpha -= clamp(x * inverseDiameter + 0.5, 0.0, 1.0);
}
return alpha;
}
vec2 rotate(vec2 v) {
return vec2(v.y, -v.x);
}
void main() {
//vec4 debug = texture(curves, vec2(uv.x, 0.5));
//ivec4 debug = texelFetch(glyphs, ivec2(uv.x * float(textureSize(glyphs, 0).x), 0), 0);
//result = vec4(debug.rgb, 1.0);
//Glyph gly = loadGlyph(bufferIndex);
//result = vec4((float(gly.start) / 1883.0), (float(gly.count) / 42.0), 0.0, 1.0);
// verify bufferIndex [x]
//result = vec4((float(bufferIndex) / 100.0), 0.0, 0.0, 1.0);
//return;
float alpha = 0.0;
// Inverse of the diameter of a pixel in uv units for anti-aliasing.
vec2 inverseDiameter = 1.0 / (antiAliasingWindowSize * fwidth(uv));
Glyph glyph = loadGlyph(bufferIndex);
for (int i = 0; i < glyph.count; i++) {
Curve curve = loadCurve(glyph.start + i);
vec2 p0 = curve.p0 - uv;
vec2 p1 = curve.p1 - uv;
vec2 p2 = curve.p2 - uv;
alpha += computeCoverage(inverseDiameter.x, p0, p1, p2);
if (enableSuperSamplingAntiAliasing) {
alpha += computeCoverage(inverseDiameter.y, rotate(p0), rotate(p1), rotate(p2));
}
}
// DEBUG
//if (uv.x > 0.5) {
//ivec2 ts = textureSize(curves,0);
//float w = float(ts.x);
//float h = float(ts.y);
////float green = (float(glyph.count) / 27.0);
//float green = float(w) / (3.0 * 27.0);
//result = vec4(0.0,h * 0.5,0.0,1.0);
//} else {
//result = vec4(0.0,0.5,0.0,1.0);
//}
//return;
if (enableSuperSamplingAntiAliasing) {
alpha *= 0.5;
}
alpha = clamp(alpha, 0.0, 1.0);
result = color * alpha;
if (enableControlPointsVisualization) {
// Visualize control points.
vec2 fw = fwidth(uv);
float r = 4.0 * 0.5 * (fw.x + fw.y);
for (int i = 0; i < glyph.count; i++) {
Curve curve = loadCurve(glyph.start + i);
vec2 p0 = curve.p0 - uv;
vec2 p1 = curve.p1 - uv;
vec2 p2 = curve.p2 - uv;
if (dot(p0, p0) < r*r || dot(p2, p2) < r*r) {
result = vec4(0.0, 1.0, 0.0, 1.0);
return;
}
if (dot(p1, p1) < r*r) {
result = vec4(1.0, 0.0, 1.0, 1.0);
return;
}
}
}
}

View file

@ -0,0 +1,21 @@
#version 300 es
precision highp float;
precision highp isampler2D;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform float z;
layout (location = 0) in vec2 vertexPosition;
layout (location = 1) in vec2 vertexUV;
layout (location = 2) in int vertexIndex;
out vec2 uv;
flat out int bufferIndex;
void main() {
gl_Position = projection * view * model * vec4(vertexPosition, z, 1.0);
uv = vertexUV;
bufferIndex = vertexIndex;
}

View file

@ -0,0 +1,12 @@
#version 330 core
in vec2 position;
out vec3 color;
void main() {
float t = (position.y + 1.0) / 2.0;
vec3 bottom = vec3(75.0, 55.0, 201.0) / 255.0;
vec3 top = vec3(0.0, 12.0, 0.0) / 255.0;
color = mix(bottom, top, t);
}

View file

@ -0,0 +1,15 @@
#version 330 core
const vec2 vertices[4] = vec2[4](
vec2(-1.0, -1.0),
vec2( 1.0, -1.0),
vec2(-1.0, 1.0),
vec2( 1.0, 1.0)
);
out vec2 position;
void main() {
position = vertices[gl_VertexID];
gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0);
}

View file

@ -0,0 +1,171 @@
#version 300 es
precision highp float;
precision highp isampler2D;
precision highp sampler2D;
// Based on: http://wdobbie.com/post/gpu-text-rendering-with-vector-textures/
struct Glyph {
int start, count;
};
struct Curve {
vec2 p0, p1, p2;
};
uniform isampler2D glyphs;
uniform sampler2D curves;
uniform vec4 color;
// Controls for debugging and exploring:
// Size of the window (in pixels) used for 1-dimensional anti-aliasing along each rays.
// 0 - no anti-aliasing
// 1 - normal anti-aliasing
// >=2 - exaggerated effect
uniform float antiAliasingWindowSize;
// Enable a second ray along the y-axis to achieve 2-dimensional anti-aliasing.
uniform bool enableSuperSamplingAntiAliasing;
// Draw control points for debugging (green - on curve, magenta - off curve).
uniform bool enableControlPointsVisualization;
in vec2 uv;
flat in int bufferIndex;
out vec4 result;
Glyph loadGlyph(int index) {
Glyph result;
ivec2 data = texelFetch(glyphs, ivec2(index, 0), 0).xy;
result.start = data.x;
result.count = data.y;
return result;
}
Curve loadCurve(int index) {
Curve result;
result.p0 = texelFetch(curves, ivec2(3*index+0, 0), 0).xy;
result.p1 = texelFetch(curves, ivec2(3*index+1, 0), 0).xy;
result.p2 = texelFetch(curves, ivec2(3*index+2, 0), 0).xy;
return result;
}
float computeCoverage(float inverseDiameter, vec2 p0, vec2 p1, vec2 p2) {
if (p0.y > 0.0 && p1.y > 0.0 && p2.y > 0.0) return 0.0;
if (p0.y < 0.0 && p1.y < 0.0 && p2.y < 0.0) return 0.0;
// Note: Simplified from abc formula by extracting a factor of (-2) from b.
vec2 a = p0 - 2.0*p1 + p2;
vec2 b = p0 - p1;
vec2 c = p0;
float t0, t1;
if (abs(a.y) >= 1e-5) {
// Quadratic segment, solve abc formula to find roots.
float radicand = b.y*b.y - a.y*c.y;
if (radicand <= 0.0) return 0.0;
float s = sqrt(radicand);
t0 = (b.y - s) / a.y;
t1 = (b.y + s) / a.y;
} else {
// Linear segment, avoid division by a.y, which is near zero.
// There is only one root, so we have to decide which variable to
// assign it to based on the direction of the segment, to ensure that
// the ray always exits the shape at t0 and enters at t1. For a
// quadratic segment this works 'automatically', see readme.
float t = p0.y / (p0.y - p2.y);
if (p0.y < p2.y) {
t0 = -1.0;
t1 = t;
} else {
t0 = t;
t1 = -1.0;
}
}
float alpha = 0.0;
if (t0 >= 0.0 && t0 < 1.0) {
float x = (a.x*t0 - 2.0*b.x)*t0 + c.x;
alpha += clamp(x * inverseDiameter + 0.5, 0.0, 1.0);
}
if (t1 >= 0.0 && t1 < 1.0) {
float x = (a.x*t1 - 2.0*b.x)*t1 + c.x;
alpha -= clamp(x * inverseDiameter + 0.5, 0.0, 1.0);
}
return alpha;
}
vec2 rotate(vec2 v) {
return vec2(v.y, -v.x);
}
void main() {
//vec4 debug = texture(curves, vec2(uv.x, 0.5));
//ivec4 debug = texture(glyphs, vec2(uv.x, 0.5));
////ivec4 debug = texelFetch(glyphs, ivec2(uv.x * float(textureSize(glyphs, 0).x), 0), 0);
//result = vec4(debug.rgb, 1.0);
Glyph gly = loadGlyph(bufferIndex);
result = vec4((float(gly.start) / 1883.0), (float(gly.count) / 42.0), 0.0, 1.0);
// verify bufferIndex [x]
//result = vec4((float(bufferIndex) / 100.0), 0.0, 0.0, 1.0);
return;
float alpha = 0.0;
// Inverse of the diameter of a pixel in uv units for anti-aliasing.
vec2 inverseDiameter = 1.0 / (antiAliasingWindowSize * fwidth(uv));
Glyph glyph = loadGlyph(bufferIndex);
for (int i = 0; i < glyph.count; i++) {
Curve curve = loadCurve(glyph.start + i);
vec2 p0 = curve.p0 - uv;
vec2 p1 = curve.p1 - uv;
vec2 p2 = curve.p2 - uv;
alpha += computeCoverage(inverseDiameter.x, p0, p1, p2);
if (enableSuperSamplingAntiAliasing) {
alpha += computeCoverage(inverseDiameter.y, rotate(p0), rotate(p1), rotate(p2));
}
}
if (enableSuperSamplingAntiAliasing) {
alpha *= 0.5;
}
alpha = clamp(alpha, 0.0, 1.0);
result = color * alpha;
if (enableControlPointsVisualization) {
// Visualize control points.
vec2 fw = fwidth(uv);
float r = 4.0 * 0.5 * (fw.x + fw.y);
for (int i = 0; i < glyph.count; i++) {
Curve curve = loadCurve(glyph.start + i);
vec2 p0 = curve.p0 - uv;
vec2 p1 = curve.p1 - uv;
vec2 p2 = curve.p2 - uv;
if (dot(p0, p0) < r*r || dot(p2, p2) < r*r) {
result = vec4(0.0, 1.0, 0.0, 1.0);
return;
}
if (dot(p1, p1) < r*r) {
result = vec4(1.0, 0.0, 1.0, 1.0);
return;
}
}
}
}

View file

@ -0,0 +1,21 @@
#version 300 es
precision highp float;
precision highp isampler2D;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform float z;
layout (location = 0) in vec2 vertexPosition;
layout (location = 1) in vec2 vertexUV;
layout (location = 2) in int vertexIndex;
out vec2 uv;
flat out int bufferIndex;
void main() {
gl_Position = projection * view * model * vec4(vertexPosition, z, 1.0);
uv = vertexUV;
bufferIndex = vertexIndex;
}