webgl2-sdf 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -12
- package/browser/index.min.js +1 -1
- package/node/debug-shaders.js +2 -2
- package/node/debug-shaders.js.map +1 -1
- package/node/generate-sdf.d.ts +85 -9
- package/node/generate-sdf.js +97 -15
- package/node/generate-sdf.js.map +1 -1
- package/node/index.d.ts +1 -0
- package/node/index.js +1 -0
- package/node/index.js.map +1 -1
- package/node/main-program.d.ts +2 -1
- package/node/main-program.js +6 -2
- package/node/main-program.js.map +1 -1
- package/node/shaders/fragment.d.ts +4 -2
- package/node/shaders/fragment.js +80 -55
- package/node/shaders/fragment.js.map +1 -1
- package/node/types/gl-context.d.ts +0 -5
- package/node/webgl-utils/get-web-gl-context.js +2 -0
- package/node/webgl-utils/get-web-gl-context.js.map +1 -1
- package/package.json +1 -1
- package/src/debug-shaders.ts +2 -2
- package/src/generate-sdf.ts +122 -26
- package/src/index.ts +1 -0
- package/src/main-program.ts +18 -7
- package/src/shaders/fragment.ts +87 -56
- package/src/types/gl-context.ts +0 -5
- package/src/webgl-utils/get-web-gl-context.ts +3 -0
package/src/shaders/fragment.ts
CHANGED
|
@@ -4,11 +4,38 @@ import { ROW_COUNT } from "../row-count.js";
|
|
|
4
4
|
const cache: { [padCount_times_colCount: number]: string } = {};
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
const GLSL_PATTERN1 = `
|
|
8
|
+
float exponent = uCustom.x;
|
|
9
|
+
float alpha = res >= 1.0 ? 0.0 : 0.5;
|
|
10
|
+
res = pow(1.0 - res, exponent);
|
|
11
|
+
float red = inside ? 0.2 : 0.8;
|
|
12
|
+
float green = abs(sin(25.0 * res));
|
|
13
|
+
// float green = step(0.5, fract(10.0 * res));
|
|
14
|
+
float blue = 0.5;
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
const GLSL_DEFAULT = `
|
|
19
|
+
float exponent = uCustom.x;
|
|
20
|
+
float adj = 0.5*pow(1.0 - res, exponent);
|
|
21
|
+
res = inside ? 1.0 - adj : adj;
|
|
22
|
+
float red = res;
|
|
23
|
+
float green = res;
|
|
24
|
+
float blue = res;
|
|
25
|
+
float alpha = res;
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
|
|
7
29
|
function getFragment(
|
|
8
30
|
colCount: number,
|
|
9
|
-
padCount: number
|
|
10
|
-
|
|
11
|
-
|
|
31
|
+
padCount: number,
|
|
32
|
+
calcFragColorStr: string,
|
|
33
|
+
hash: number): string {
|
|
34
|
+
|
|
35
|
+
// `colCount` and `padCount` can take at most 8 bits and `has` 32 bits and
|
|
36
|
+
// we have at least 53 bits to play with so we're fine
|
|
37
|
+
const key = (2**32)*(256*colCount + padCount) + hash;
|
|
38
|
+
const fragment = cache[key];
|
|
12
39
|
if (fragment !== undefined) { return fragment; }
|
|
13
40
|
|
|
14
41
|
const main_Fragment =
|
|
@@ -20,7 +47,11 @@ uniform float uMaxDistance;
|
|
|
20
47
|
uniform highp sampler2D uSegs;
|
|
21
48
|
uniform highp isampler2D uCloseCellIdxs;
|
|
22
49
|
uniform highp isampler2D uCrossCellIdxs;
|
|
23
|
-
|
|
50
|
+
// bit 0 -> calc distance inside
|
|
51
|
+
// bit 1 -> calc distance outside
|
|
52
|
+
// bit 2 -> calc whether fragment is inside or outside (else outside is assumed with winds == 0.0)
|
|
53
|
+
uniform int uTestInOut;
|
|
54
|
+
uniform vec4 uCustom;
|
|
24
55
|
|
|
25
56
|
uniform SegIdxRangePerCellBlock {
|
|
26
57
|
ivec4 uSegIdxRangePerCell[${(ROW_COUNT + 2*padCount)*(colCount + 2*padCount) / 2}];
|
|
@@ -35,6 +66,10 @@ flat in ivec2 closeCellIdxRange;
|
|
|
35
66
|
flat in ivec2 crossCellIdxRange;
|
|
36
67
|
out vec4 FragColor;
|
|
37
68
|
|
|
69
|
+
// testing!!
|
|
70
|
+
// float rand(vec2 co) {
|
|
71
|
+
// return mod(uCustom.w * fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453), 1.0);
|
|
72
|
+
// }
|
|
38
73
|
|
|
39
74
|
float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
|
|
40
75
|
vec2 lineDir = lineB - lineA;
|
|
@@ -48,72 +83,75 @@ float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
|
|
|
48
83
|
|
|
49
84
|
void main() {
|
|
50
85
|
///////////////////////////////////////////////////////////////////////////
|
|
86
|
+
// Calculate \`winds\`:
|
|
87
|
+
//
|
|
51
88
|
// Project a ray to the left to check if it crosses the segment in order
|
|
52
89
|
// to find the fragment's winding number to determine whether fragment
|
|
53
90
|
// is inside or outside the shape.
|
|
91
|
+
///////////////////////////////////////////////////////////////////////////
|
|
54
92
|
|
|
55
|
-
int crossIdxS = crossCellIdxRange.x;
|
|
56
|
-
int crossLen = crossCellIdxRange.y;
|
|
57
93
|
float winds = 0.0;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
int
|
|
94
|
+
if ((uTestInOut & 4) != 0) {
|
|
95
|
+
int crossIdxS = crossCellIdxRange.x;
|
|
96
|
+
int crossLen = crossCellIdxRange.y;
|
|
97
|
+
// Iterate over all relevant cell indexes
|
|
98
|
+
for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {
|
|
99
|
+
int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;
|
|
61
100
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
101
|
+
ivec2 uSegIdxRange = crossIdx % 2 == 0
|
|
102
|
+
? uSegIdxRangePerCell[crossIdx / 2].xy
|
|
103
|
+
: uSegIdxRangePerCell[crossIdx / 2].zw;
|
|
65
104
|
|
|
66
|
-
|
|
67
|
-
|
|
105
|
+
int segIdx = uSegIdxRange.x;
|
|
106
|
+
int segLen = uSegIdxRange.y;
|
|
68
107
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
108
|
+
for (int j = segIdx; j < segIdx + segLen; j++) {
|
|
109
|
+
// Fetch segment from texture
|
|
110
|
+
vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
|
|
72
111
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
112
|
+
// line segment's min-y is excluded
|
|
113
|
+
bool crossing =
|
|
114
|
+
(seg.y > vXY.y != seg.w > vXY.y) &&
|
|
115
|
+
(vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
|
|
77
116
|
|
|
78
|
-
|
|
117
|
+
bool crossingUp = seg.y < seg.w;
|
|
79
118
|
|
|
80
|
-
|
|
119
|
+
winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;
|
|
120
|
+
}
|
|
81
121
|
}
|
|
82
|
-
}
|
|
83
122
|
|
|
84
|
-
|
|
85
|
-
|
|
123
|
+
{
|
|
124
|
+
int cellIdx = (instanceId % ${ROW_COUNT});
|
|
86
125
|
|
|
87
|
-
|
|
126
|
+
bool isEven = cellIdx % 2 == 0;
|
|
88
127
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
128
|
+
ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];
|
|
129
|
+
int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
|
|
130
|
+
int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
|
|
131
|
+
|
|
93
132
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
133
|
+
for (int j = segIdx; j < segIdx + segLen; j++) {
|
|
134
|
+
// Fetch segment from texture
|
|
135
|
+
vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
|
|
97
136
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
137
|
+
// line segment's min-y is excluded
|
|
138
|
+
bool crossing =
|
|
139
|
+
(seg.y > vXY.y != seg.w > vXY.y) &&
|
|
140
|
+
(vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
|
|
102
141
|
|
|
103
|
-
|
|
142
|
+
bool crossingUp = seg.y < seg.w;
|
|
104
143
|
|
|
105
|
-
|
|
144
|
+
winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;
|
|
145
|
+
}
|
|
106
146
|
}
|
|
107
147
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
148
|
bool inside = winds != 0.0;
|
|
111
149
|
///////////////////////////////////////////////////////////////////////////
|
|
112
|
-
|
|
150
|
+
// Calculate \`res\`: the distance to the nearest curve
|
|
113
151
|
///////////////////////////////////////////////////////////////////////////
|
|
114
152
|
float res = 1.0; // sdf result
|
|
115
153
|
|
|
116
|
-
if ((inside && (
|
|
154
|
+
if ((inside && ((uTestInOut & 1) != 0)) || (!inside && ((uTestInOut & 2) != 0))) {
|
|
117
155
|
int cellIdxS = closeCellIdxRange.x;
|
|
118
156
|
int cellLen = closeCellIdxRange.y;
|
|
119
157
|
// Iterate over all relevant cell indexes
|
|
@@ -131,9 +169,8 @@ void main() {
|
|
|
131
169
|
// Fetch segment from texture
|
|
132
170
|
vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
|
|
133
171
|
|
|
134
|
-
// Find unsigned distance to the segment; only the nearest will be kept
|
|
172
|
+
// Find normalized unsigned distance to the segment; only the nearest will be kept
|
|
135
173
|
float d = absDistToSegment(vXY, seg.xy, seg.zw);
|
|
136
|
-
// Apply exponential transform
|
|
137
174
|
float val = clamp(d / uMaxDistance, 0.0, 1.0);
|
|
138
175
|
|
|
139
176
|
res = min(res, val);
|
|
@@ -145,22 +182,16 @@ void main() {
|
|
|
145
182
|
// DEBUG!
|
|
146
183
|
// float alpha = ((instanceId + instanceId/${ROW_COUNT}) % 2 == 0 ? 0.3 : 0.5);
|
|
147
184
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
res = pow(1.0 - val, exponent) * 0.5;
|
|
151
|
-
|
|
152
|
-
float alpha = res == 1.0 ? 0.0 : 0.5;
|
|
153
|
-
float red = inside ? 0.2 : 0.8;
|
|
154
|
-
float green = abs(sin(25.0 * res));
|
|
155
|
-
float blue = 0.5;
|
|
185
|
+
|
|
186
|
+
${calcFragColorStr}
|
|
156
187
|
|
|
157
188
|
FragColor = vec4(red, green, blue, alpha);
|
|
158
189
|
}
|
|
159
190
|
`
|
|
160
191
|
|
|
161
|
-
cache[
|
|
192
|
+
cache[key] = main_Fragment;
|
|
162
193
|
return main_Fragment;
|
|
163
194
|
}
|
|
164
195
|
|
|
165
196
|
|
|
166
|
-
export { getFragment }
|
|
197
|
+
export { getFragment, GLSL_PATTERN1, GLSL_DEFAULT }
|
package/src/types/gl-context.ts
CHANGED
|
@@ -8,13 +8,8 @@ import type { Texture } from "./texture";
|
|
|
8
8
|
*
|
|
9
9
|
* * `textures`
|
|
10
10
|
* * `programs`
|
|
11
|
-
* * `framebufferStack`
|
|
12
11
|
*
|
|
13
12
|
* so they don't have to be recreated on each draw call.
|
|
14
|
-
*
|
|
15
|
-
* * an optional `width` and `height` that can be used for any purpose and that are not
|
|
16
|
-
* set or read by any function within the library
|
|
17
|
-
*
|
|
18
13
|
*/
|
|
19
14
|
interface GlContext {
|
|
20
15
|
readonly gl: WebGL2RenderingContext;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Texture } from "../types/texture.js";
|
|
2
2
|
import type { Program } from "../types/program.js";
|
|
3
3
|
import type { GlContext } from "../types/gl-context.js";
|
|
4
|
+
import { debugShaders } from "../debug-shaders.js";
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
const cache = new WeakMap<WebGL2RenderingContext, GlContext>();
|
|
@@ -21,6 +22,8 @@ function getWebGlContext(
|
|
|
21
22
|
if (glContext) { return glContext; }
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
debugShaders(gl);
|
|
26
|
+
|
|
24
27
|
const programs: { [index:string]: Program } = {};
|
|
25
28
|
const textures: { [index:string]: Texture } = {};
|
|
26
29
|
|