three-slug 1.0.0
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/GOAL.md +32 -0
- package/README.md +78 -0
- package/demo/fonts/DejaVu Fonts License.txt +97 -0
- package/demo/fonts/DejaVuSansMono-Bold.sluggish +0 -0
- package/demo/fonts/DejaVuSansMono-Bold.ttf +0 -0
- package/demo/fonts/DejaVuSansMono-BoldOblique.ttf +0 -0
- package/demo/fonts/DejaVuSansMono-Oblique.ttf +0 -0
- package/demo/fonts/DejaVuSansMono.ttf +0 -0
- package/demo/fonts/Roboto-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/demo/fonts/Roboto-VariableFont_wdth,wght.ttf +0 -0
- package/demo/fonts/SpaceMono-Bold.ttf +0 -0
- package/demo/fonts/SpaceMono-BoldItalic.ttf +0 -0
- package/demo/fonts/SpaceMono-Italic.ttf +0 -0
- package/demo/fonts/SpaceMono-Regular.sluggish +0 -0
- package/demo/fonts/SpaceMono-Regular.ttf +0 -0
- package/demo/fonts/fonts.json +12 -0
- package/demo/index.html +103 -0
- package/demo/main.js +357 -0
- package/package.json +29 -0
- package/screenshot.png +0 -0
- package/src/SlugGenerator.js +399 -0
- package/src/SlugGeometry.js +211 -0
- package/src/SlugLoader.js +123 -0
- package/src/SlugMaterial.js +254 -0
- package/src/index.js +4 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
const SLUGGISH_HEADER_DATA = "SLUGGISH";
|
|
4
|
+
const TEXTURE_WIDTH = 4096;
|
|
5
|
+
|
|
6
|
+
export class SlugLoader {
|
|
7
|
+
constructor(manager) {
|
|
8
|
+
this.manager = manager !== undefined ? manager : THREE.DefaultLoadingManager;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
load(url, onLoad, onProgress, onError) {
|
|
12
|
+
const loader = new THREE.FileLoader(this.manager);
|
|
13
|
+
loader.setResponseType('arraybuffer');
|
|
14
|
+
loader.load(url, (buffer) => {
|
|
15
|
+
try {
|
|
16
|
+
onLoad(this.parse(buffer));
|
|
17
|
+
} catch (e) {
|
|
18
|
+
if (onError) {
|
|
19
|
+
onError(e);
|
|
20
|
+
} else {
|
|
21
|
+
console.error(e);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}, onProgress, onError);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
parse(buffer) {
|
|
28
|
+
const dataView = new DataView(buffer);
|
|
29
|
+
let offset = 0;
|
|
30
|
+
|
|
31
|
+
// Verify Header Validate
|
|
32
|
+
const headerBytes = new Uint8Array(buffer, offset, 8);
|
|
33
|
+
const headerStr = String.fromCharCode.apply(null, headerBytes);
|
|
34
|
+
if (headerStr !== SLUGGISH_HEADER_DATA) {
|
|
35
|
+
throw new Error(`Invalid header found (${headerStr} instead of ${SLUGGISH_HEADER_DATA})`);
|
|
36
|
+
}
|
|
37
|
+
offset += 8;
|
|
38
|
+
|
|
39
|
+
const codePointCount = dataView.getUint16(offset, true);
|
|
40
|
+
offset += 2;
|
|
41
|
+
|
|
42
|
+
const codePoints = new Map();
|
|
43
|
+
for (let i = 0; i < codePointCount; i++) {
|
|
44
|
+
const cp = {
|
|
45
|
+
codePoint: dataView.getUint32(offset, true),
|
|
46
|
+
width: dataView.getUint32(offset + 4, true),
|
|
47
|
+
height: dataView.getUint32(offset + 8, true),
|
|
48
|
+
advanceWidth: dataView.getUint32(offset + 12, true),
|
|
49
|
+
bearingX: dataView.getInt32(offset + 16, true),
|
|
50
|
+
bearingY: dataView.getInt32(offset + 20, true),
|
|
51
|
+
bandCount: dataView.getUint32(offset + 24, true),
|
|
52
|
+
bandDimX: dataView.getUint32(offset + 28, true),
|
|
53
|
+
bandDimY: dataView.getUint32(offset + 32, true),
|
|
54
|
+
bandsTexCoordX: dataView.getUint16(offset + 36, true),
|
|
55
|
+
bandsTexCoordY: dataView.getUint16(offset + 38, true),
|
|
56
|
+
};
|
|
57
|
+
codePoints.set(cp.codePoint, cp);
|
|
58
|
+
offset += 40; // Extended struct in Javascript
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const curvesTexWidth = dataView.getUint16(offset, true); offset += 2;
|
|
62
|
+
const curvesTexHeight = dataView.getUint16(offset, true); offset += 2;
|
|
63
|
+
const curvesTexBytes = dataView.getUint32(offset, true); offset += 4;
|
|
64
|
+
|
|
65
|
+
if (curvesTexWidth === 0 || curvesTexHeight === 0 || curvesTexBytes === 0 || curvesTexWidth !== TEXTURE_WIDTH) {
|
|
66
|
+
throw new Error("Invalid curves texture dimensions");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const curvesTexels = curvesTexWidth * curvesTexHeight;
|
|
70
|
+
const curvesData = new Float32Array(curvesTexels * 4); // RGBA32F
|
|
71
|
+
const curvesBuffer = buffer.slice(offset, offset + curvesTexBytes);
|
|
72
|
+
const incomingCurvesData = new Float32Array(curvesBuffer);
|
|
73
|
+
curvesData.set(incomingCurvesData);
|
|
74
|
+
// Fill remaining with -1/-1/-1/-1 padding as expected by shader sometimes? Wait, C++ memsets to 0xCD.
|
|
75
|
+
offset += curvesTexBytes;
|
|
76
|
+
|
|
77
|
+
const bandsTexWidth = dataView.getUint16(offset, true); offset += 2;
|
|
78
|
+
const bandsTexHeight = dataView.getUint16(offset, true); offset += 2;
|
|
79
|
+
const bandsTexBytes = dataView.getUint32(offset, true); offset += 4;
|
|
80
|
+
|
|
81
|
+
if (bandsTexWidth === 0 || bandsTexHeight === 0 || bandsTexBytes === 0 || bandsTexWidth !== TEXTURE_WIDTH) {
|
|
82
|
+
throw new Error("Invalid bands texture dimensions");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const bandsTexels = bandsTexWidth * bandsTexHeight;
|
|
86
|
+
const bandsData = new Uint32Array(bandsTexels * 2); // RG32UI
|
|
87
|
+
const bandsBuffer = buffer.slice(offset, offset + bandsTexBytes);
|
|
88
|
+
const incomingBandsData = new Uint32Array(bandsBuffer);
|
|
89
|
+
bandsData.set(incomingBandsData);
|
|
90
|
+
offset += bandsTexBytes;
|
|
91
|
+
|
|
92
|
+
let ascender = 0, descender = 0, lineGap = 0, unitsPerEm = 0;
|
|
93
|
+
if (offset + 16 <= buffer.byteLength) {
|
|
94
|
+
ascender = dataView.getInt32(offset, true); offset += 4;
|
|
95
|
+
descender = dataView.getInt32(offset, true); offset += 4;
|
|
96
|
+
lineGap = dataView.getInt32(offset, true); offset += 4;
|
|
97
|
+
unitsPerEm = dataView.getInt32(offset, true); offset += 4;
|
|
98
|
+
}
|
|
99
|
+
console.log("SlugLoader Metrics read:", { ascender, descender, lineGap, unitsPerEm, offset, bufferLen: buffer.byteLength });
|
|
100
|
+
|
|
101
|
+
const curvesTex = new THREE.DataTexture(curvesData, curvesTexWidth, curvesTexHeight, THREE.RGBAFormat, THREE.FloatType);
|
|
102
|
+
curvesTex.internalFormat = 'RGBA32F';
|
|
103
|
+
curvesTex.minFilter = THREE.NearestFilter;
|
|
104
|
+
curvesTex.magFilter = THREE.NearestFilter;
|
|
105
|
+
curvesTex.needsUpdate = true;
|
|
106
|
+
|
|
107
|
+
const bandsTex = new THREE.DataTexture(bandsData, bandsTexWidth, bandsTexHeight, THREE.RGIntegerFormat, THREE.UnsignedIntType);
|
|
108
|
+
bandsTex.internalFormat = 'RG32UI';
|
|
109
|
+
bandsTex.minFilter = THREE.NearestFilter;
|
|
110
|
+
bandsTex.magFilter = THREE.NearestFilter;
|
|
111
|
+
bandsTex.needsUpdate = true;
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
codePoints: codePoints,
|
|
115
|
+
curvesTex: curvesTex,
|
|
116
|
+
bandsTex: bandsTex,
|
|
117
|
+
ascender: ascender,
|
|
118
|
+
descender: descender,
|
|
119
|
+
lineGap: lineGap,
|
|
120
|
+
unitsPerEm: unitsPerEm
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
const slug_pars_fragment = `
|
|
4
|
+
precision highp int;
|
|
5
|
+
precision highp usampler2D;
|
|
6
|
+
|
|
7
|
+
in vec2 vTexCoords;
|
|
8
|
+
flat in vec4 vGlyphBandScale;
|
|
9
|
+
flat in uvec4 vBandMaxTexCoords;
|
|
10
|
+
|
|
11
|
+
uniform sampler2D curvesTex;
|
|
12
|
+
uniform usampler2D bandsTex;
|
|
13
|
+
|
|
14
|
+
const float epsilon = 0.0001;
|
|
15
|
+
|
|
16
|
+
#define glyphScale vGlyphBandScale.xy
|
|
17
|
+
#define bandScale vGlyphBandScale.zw
|
|
18
|
+
#define bandMax vBandMaxTexCoords.xy
|
|
19
|
+
#define bandsTexCoords vBandMaxTexCoords.zw
|
|
20
|
+
|
|
21
|
+
float TraceRayCurveH(vec2 p1, vec2 p2, vec2 p3, float pixelsPerEm)
|
|
22
|
+
{
|
|
23
|
+
if(max(max(p1.x, p2.x), p3.x) * pixelsPerEm < -0.5)
|
|
24
|
+
{
|
|
25
|
+
return 0.0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
uint code = (0x2E74U >> (((p1.y > 0.0) ? 2U : 0U) + ((p2.y > 0.0) ? 4U : 0U) + ((p3.y > 0.0) ? 8U : 0U))) & 3U;
|
|
29
|
+
if(code == 0U)
|
|
30
|
+
{
|
|
31
|
+
return 0.0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
vec2 a = p1 - p2 * 2.0 + p3;
|
|
35
|
+
vec2 b = p1 - p2;
|
|
36
|
+
float c = p1.y;
|
|
37
|
+
float ayr = 1.0 / a.y;
|
|
38
|
+
float d = sqrt(max(b.y * b.y - a.y * c, 0.0));
|
|
39
|
+
float t1 = (b.y - d) * ayr;
|
|
40
|
+
float t2 = (b.y + d) * ayr;
|
|
41
|
+
|
|
42
|
+
if(abs(a.y) < epsilon)
|
|
43
|
+
{
|
|
44
|
+
t1 = t2 = c / (2.0 * b.y);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
float coverage = 0.0;
|
|
48
|
+
|
|
49
|
+
if((code & 1U) != 0U)
|
|
50
|
+
{
|
|
51
|
+
float x1 = (a.x * t1 - b.x * 2.0) * t1 + p1.x;
|
|
52
|
+
float cov_c = clamp(x1 * pixelsPerEm + 0.5, 0.0, 1.0);
|
|
53
|
+
coverage += cov_c;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if(code > 1U)
|
|
57
|
+
{
|
|
58
|
+
float x2 = (a.x * t2 - b.x * 2.0) * t2 + p1.x;
|
|
59
|
+
float cov_c = clamp(x2 * pixelsPerEm + 0.5, 0.0, 1.0);
|
|
60
|
+
coverage -= cov_c;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return coverage;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
float TraceRayBandH(uvec2 bandData, float pixelsPerEm)
|
|
67
|
+
{
|
|
68
|
+
float coverage = 0.0;
|
|
69
|
+
for(uint curve = 0U; curve < bandData.x; ++curve)
|
|
70
|
+
{
|
|
71
|
+
uint curveOffset = bandData.y + curve;
|
|
72
|
+
ivec2 curveLoc = ivec2(texelFetch(bandsTex, ivec2(curveOffset & 0xFFFU, curveOffset >> 12U), 0).xy);
|
|
73
|
+
vec4 p12 = texelFetch(curvesTex, curveLoc, 0) / vec4(glyphScale, glyphScale) - vec4(vTexCoords, vTexCoords);
|
|
74
|
+
vec2 p3 = texelFetch(curvesTex, ivec2(curveLoc.x + 1, curveLoc.y), 0).xy / glyphScale - vTexCoords;
|
|
75
|
+
coverage += TraceRayCurveH(p12.xy, p12.zw, p3.xy, pixelsPerEm);
|
|
76
|
+
}
|
|
77
|
+
return coverage;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
float TraceRayBandV(uvec2 bandData, float pixelsPerEm)
|
|
81
|
+
{
|
|
82
|
+
float coverage = 0.0;
|
|
83
|
+
for(uint curve = 0U; curve < bandData.x; ++curve)
|
|
84
|
+
{
|
|
85
|
+
uint curveOffset = bandData.y + curve;
|
|
86
|
+
ivec2 curveLoc = ivec2(texelFetch(bandsTex, ivec2(curveOffset & 0xFFFU, curveOffset >> 12U), 0).xy);
|
|
87
|
+
vec4 p12 = texelFetch(curvesTex, curveLoc, 0) / vec4(glyphScale, glyphScale) - vec4(vTexCoords, vTexCoords);
|
|
88
|
+
vec2 p3 = texelFetch(curvesTex, ivec2(curveLoc.x + 1, curveLoc.y), 0).xy / glyphScale - vTexCoords;
|
|
89
|
+
coverage += TraceRayCurveH(p12.yx, p12.wz, p3.yx, pixelsPerEm);
|
|
90
|
+
}
|
|
91
|
+
return coverage;
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
const slug_fragment_core = `
|
|
96
|
+
vec2 fdx = dFdx(vTexCoords);
|
|
97
|
+
vec2 fdy = dFdy(vTexCoords);
|
|
98
|
+
// Modern WebGL GPUs legally return 0.0 for fragment derivatives inside colorless Depth-Only passes!
|
|
99
|
+
// A strict mechanical floor guarantees we never divide-by-zero -> Infinity.
|
|
100
|
+
vec2 fw = max(max(abs(fdx), abs(fdy)), vec2(0.000001));
|
|
101
|
+
vec2 pixelsPerEm = vec2(1.0 / fw.x, 1.0 / fw.y);
|
|
102
|
+
|
|
103
|
+
// Shadow cameras evaluate text at a sub-pixel size and the algorithm aggressively culls it into alpha 0.0.
|
|
104
|
+
// Clamping to a high resolution floor forces solid strokes when drawn locally into a shadow mapping buffer!
|
|
105
|
+
pixelsPerEm = clamp(pixelsPerEm, vec2(1.0), vec2(200.0));
|
|
106
|
+
|
|
107
|
+
uvec2 bandIndex = uvec2(clamp(uvec2(vTexCoords * bandScale), uvec2(0U, 0U), bandMax));
|
|
108
|
+
|
|
109
|
+
uint hBandOffset = bandsTexCoords.y * 4096U + bandsTexCoords.x + bandIndex.y;
|
|
110
|
+
uvec2 hBandData = texelFetch(bandsTex, ivec2(hBandOffset & 0xFFFU, hBandOffset >> 12U), 0).xy;
|
|
111
|
+
|
|
112
|
+
uint vBandOffset = bandsTexCoords.y * 4096U + bandsTexCoords.x + bandMax.y + 1U + bandIndex.x;
|
|
113
|
+
uvec2 vBandData = texelFetch(bandsTex, ivec2(vBandOffset & 0xFFFU, vBandOffset >> 12U), 0).xy;
|
|
114
|
+
|
|
115
|
+
float coverageX = TraceRayBandH(hBandData, pixelsPerEm.x);
|
|
116
|
+
float coverageY = TraceRayBandV(vBandData, pixelsPerEm.y);
|
|
117
|
+
|
|
118
|
+
coverageX = min(abs(coverageX), 1.0);
|
|
119
|
+
coverageY = min(abs(coverageY), 1.0);
|
|
120
|
+
float slugAlpha = (coverageX + coverageY) * 0.5;
|
|
121
|
+
`;
|
|
122
|
+
|
|
123
|
+
const slug_fragment_standard = slug_fragment_core + `
|
|
124
|
+
diffuseColor.a *= slugAlpha;
|
|
125
|
+
if ( diffuseColor.a < 0.0001 ) discard;
|
|
126
|
+
`;
|
|
127
|
+
|
|
128
|
+
const slug_pars_vertex = `
|
|
129
|
+
in vec4 aScaleBias;
|
|
130
|
+
in vec4 aGlyphBandScale;
|
|
131
|
+
in vec4 aBandMaxTexCoords;
|
|
132
|
+
|
|
133
|
+
out vec2 vTexCoords;
|
|
134
|
+
flat out vec4 vGlyphBandScale;
|
|
135
|
+
flat out uvec4 vBandMaxTexCoords;
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
const slug_vertex = `
|
|
139
|
+
vec3 transformed = vec3( position.xy * aScaleBias.xy + aScaleBias.zw, 0.0 );
|
|
140
|
+
vTexCoords = position.xy * 0.5 + 0.5;
|
|
141
|
+
vGlyphBandScale = aGlyphBandScale;
|
|
142
|
+
vBandMaxTexCoords = uvec4(aBandMaxTexCoords);
|
|
143
|
+
`;
|
|
144
|
+
|
|
145
|
+
export function injectSlug(target, ...args) {
|
|
146
|
+
if (target && target.isMesh) {
|
|
147
|
+
const mesh = target;
|
|
148
|
+
const material = args[0];
|
|
149
|
+
const slugData = args[1];
|
|
150
|
+
|
|
151
|
+
mesh.material = material;
|
|
152
|
+
injectSlug(material, slugData);
|
|
153
|
+
|
|
154
|
+
if (material.isRawShaderMaterial) return;
|
|
155
|
+
|
|
156
|
+
if (!slugData._depthMaterial) {
|
|
157
|
+
slugData._depthMaterial = new THREE.MeshDepthMaterial({ side: THREE.DoubleSide });
|
|
158
|
+
injectSlug(slugData._depthMaterial, slugData);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!slugData._distanceMaterial) {
|
|
162
|
+
slugData._distanceMaterial = new THREE.MeshDistanceMaterial({ side: THREE.DoubleSide });
|
|
163
|
+
injectSlug(slugData._distanceMaterial, slugData);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
mesh.customDepthMaterial = slugData._depthMaterial;
|
|
167
|
+
mesh.customDistanceMaterial = slugData._distanceMaterial;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Material fallback mode
|
|
172
|
+
const material = target;
|
|
173
|
+
const slugData = args[0];
|
|
174
|
+
|
|
175
|
+
if (material.userData && material.userData.slugInjected) return; // Prevent redundant native macro splicing
|
|
176
|
+
|
|
177
|
+
material.transparent = true;
|
|
178
|
+
material.alphaTest = 0.01;
|
|
179
|
+
|
|
180
|
+
material.onBeforeCompile = (shader) => {
|
|
181
|
+
shader.uniforms.curvesTex = { value: slugData.curvesTex };
|
|
182
|
+
shader.uniforms.bandsTex = { value: slugData.bandsTex };
|
|
183
|
+
|
|
184
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
185
|
+
'#include <clipping_planes_pars_vertex>',
|
|
186
|
+
'#include <clipping_planes_pars_vertex>\n' + slug_pars_vertex
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
190
|
+
'#include <begin_vertex>',
|
|
191
|
+
slug_vertex
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
195
|
+
'#include <clipping_planes_pars_fragment>',
|
|
196
|
+
'#include <clipping_planes_pars_fragment>\n' + slug_pars_fragment
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
200
|
+
'#include <alphatest_fragment>',
|
|
201
|
+
slug_fragment_standard + '\n#include <alphatest_fragment>'
|
|
202
|
+
);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Also attach to userData so we can clone easily or reference
|
|
206
|
+
material.userData.slugData = slugData;
|
|
207
|
+
material.userData.slugInjected = true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const SLUG_RAW_PIXEL_SHADER = `
|
|
211
|
+
precision highp float;
|
|
212
|
+
${slug_pars_fragment}
|
|
213
|
+
|
|
214
|
+
out vec4 fragColor;
|
|
215
|
+
|
|
216
|
+
void main() {
|
|
217
|
+
${slug_fragment_core}
|
|
218
|
+
fragColor = vec4(1.0, 0.8, 0.0, slugAlpha); // Solid yellow fallback text
|
|
219
|
+
}
|
|
220
|
+
`;
|
|
221
|
+
|
|
222
|
+
const SLUG_RAW_VERTEX_SHADER = `
|
|
223
|
+
uniform mat4 modelViewMatrix;
|
|
224
|
+
uniform mat4 projectionMatrix;
|
|
225
|
+
in vec2 position;
|
|
226
|
+
${slug_pars_vertex}
|
|
227
|
+
void main() {
|
|
228
|
+
${slug_vertex}
|
|
229
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed, 1.0);
|
|
230
|
+
}
|
|
231
|
+
`;
|
|
232
|
+
|
|
233
|
+
export class SlugMaterial extends THREE.RawShaderMaterial {
|
|
234
|
+
constructor(parameters = {}) {
|
|
235
|
+
super({
|
|
236
|
+
vertexShader: SLUG_RAW_VERTEX_SHADER,
|
|
237
|
+
fragmentShader: SLUG_RAW_PIXEL_SHADER,
|
|
238
|
+
uniforms: {
|
|
239
|
+
curvesTex: { value: null },
|
|
240
|
+
bandsTex: { value: null }
|
|
241
|
+
},
|
|
242
|
+
transparent: true,
|
|
243
|
+
blending: THREE.NormalBlending,
|
|
244
|
+
//depthTest: false,
|
|
245
|
+
//depthWrite: false,
|
|
246
|
+
side: THREE.DoubleSide,
|
|
247
|
+
glslVersion: THREE.GLSL3 // We need WebGL2 / GLSL3 for texelFetch, usampler2D, flat in uvec4
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
if (parameters.curvesTex) this.uniforms.curvesTex.value = parameters.curvesTex;
|
|
251
|
+
if (parameters.bandsTex) this.uniforms.bandsTex.value = parameters.bandsTex;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
package/src/index.js
ADDED