poppygl 0.0.12 → 0.0.14
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/dist/index.d.ts +35 -18
- package/dist/index.js +243 -27
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,26 +10,11 @@ interface BitmapLike {
|
|
|
10
10
|
type ImageFactory = (width: number, height: number) => BitmapLike;
|
|
11
11
|
declare const createUint8Bitmap: ImageFactory;
|
|
12
12
|
|
|
13
|
-
declare const DEFAULT_LIGHT_DIR: readonly [-0.4, -0.9, -0.2];
|
|
14
|
-
interface RenderOptions {
|
|
15
|
-
width: number;
|
|
16
|
-
height: number;
|
|
17
|
-
fov: number;
|
|
18
|
-
cull: boolean;
|
|
19
|
-
gamma: boolean;
|
|
20
|
-
ambient: number;
|
|
21
|
-
lightDir: readonly [number, number, number];
|
|
22
|
-
camPos?: readonly [number, number, number] | null;
|
|
23
|
-
lookAt?: readonly [number, number, number] | null;
|
|
24
|
-
backgroundColor?: readonly [number, number, number] | null;
|
|
25
|
-
}
|
|
26
|
-
type RenderOptionsInput = Partial<RenderOptions>;
|
|
27
|
-
declare const DEFAULT_RENDER_OPTIONS: RenderOptions;
|
|
28
|
-
declare function getDefaultRenderOptions(): RenderOptions;
|
|
29
|
-
|
|
30
13
|
interface Material {
|
|
31
14
|
baseColorFactor: [number, number, number, number];
|
|
32
15
|
baseColorTexture: BitmapLike | null;
|
|
16
|
+
alphaMode?: "OPAQUE" | "MASK" | "BLEND";
|
|
17
|
+
alphaCutoff?: number;
|
|
33
18
|
}
|
|
34
19
|
interface DrawCall {
|
|
35
20
|
positions: Float32Array;
|
|
@@ -39,6 +24,17 @@ interface DrawCall {
|
|
|
39
24
|
model: mat4;
|
|
40
25
|
material: Material;
|
|
41
26
|
colors?: Float32Array | null;
|
|
27
|
+
mode?: number;
|
|
28
|
+
}
|
|
29
|
+
interface GridOptions {
|
|
30
|
+
size?: number | readonly [number, number, number];
|
|
31
|
+
divisions?: number;
|
|
32
|
+
color?: readonly [number, number, number];
|
|
33
|
+
offset?: Partial<{
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
z: number;
|
|
37
|
+
}>;
|
|
42
38
|
}
|
|
43
39
|
interface GLTFResources {
|
|
44
40
|
buffers: Uint8Array[];
|
|
@@ -49,6 +45,24 @@ interface GLTFScene {
|
|
|
49
45
|
gltf: any;
|
|
50
46
|
}
|
|
51
47
|
|
|
48
|
+
declare const DEFAULT_LIGHT_DIR: readonly [-0.4, -0.9, -0.2];
|
|
49
|
+
interface RenderOptions {
|
|
50
|
+
width: number;
|
|
51
|
+
height: number;
|
|
52
|
+
fov: number;
|
|
53
|
+
cull: boolean;
|
|
54
|
+
gamma: boolean;
|
|
55
|
+
ambient: number;
|
|
56
|
+
lightDir: readonly [number, number, number];
|
|
57
|
+
camPos?: readonly [number, number, number] | null;
|
|
58
|
+
lookAt?: readonly [number, number, number] | null;
|
|
59
|
+
backgroundColor?: readonly [number, number, number] | null;
|
|
60
|
+
grid?: boolean | GridOptions;
|
|
61
|
+
}
|
|
62
|
+
type RenderOptionsInput = Partial<RenderOptions>;
|
|
63
|
+
declare const DEFAULT_RENDER_OPTIONS: RenderOptions;
|
|
64
|
+
declare function getDefaultRenderOptions(): RenderOptions;
|
|
65
|
+
|
|
52
66
|
interface Camera {
|
|
53
67
|
view: mat4;
|
|
54
68
|
proj: mat4;
|
|
@@ -64,6 +78,8 @@ declare function renderDrawCalls(drawCalls: DrawCall[], optionsInput?: RenderOpt
|
|
|
64
78
|
|
|
65
79
|
declare function resolveRenderOptions(options?: RenderOptionsInput): RenderOptions;
|
|
66
80
|
|
|
81
|
+
declare function createGrid(options?: GridOptions): DrawCall;
|
|
82
|
+
|
|
67
83
|
type GLTF = any;
|
|
68
84
|
declare function createSceneFromGLTF(gltf: GLTF, resources: GLTFResources): GLTFScene;
|
|
69
85
|
|
|
@@ -108,6 +124,7 @@ declare class SoftwareRenderer {
|
|
|
108
124
|
get buffer(): Uint8Array<ArrayBufferLike> | Uint8ClampedArray<ArrayBufferLike>;
|
|
109
125
|
clear(colorRGBA?: [number, number, number, number]): void;
|
|
110
126
|
setPixel(x: number, y: number, r: number, g: number, b: number, a: number): void;
|
|
127
|
+
drawLines(mesh: DrawCall, camera: Camera, gammaOut?: boolean): void;
|
|
111
128
|
sampleTextureNearest(img: BitmapLike | null, u: number, v: number): MutableRGBA;
|
|
112
129
|
perspInterp(attrs: number[][], invWs: number[], lambdas: number[]): number[];
|
|
113
130
|
drawMesh(mesh: DrawCall, camera: Camera, light: LightSettings, material: Material, cullBackFaces?: boolean, gammaOut?: boolean): void;
|
|
@@ -128,4 +145,4 @@ declare function renderGLTFToPNGBuffer(gltfPathOrString: string, options?: Rende
|
|
|
128
145
|
|
|
129
146
|
declare function renderSceneFromGLTF(scene: GLTFScene, options?: RenderOptionsInput, imageFactory?: ImageFactory): RenderResult;
|
|
130
147
|
|
|
131
|
-
export { type BitmapLike, type Camera, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, encodePNGToBuffer, getDefaultRenderOptions, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBuffer, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderSceneFromGLTF, resolveRenderOptions };
|
|
148
|
+
export { type BitmapLike, type Camera, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type GridOptions, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createGrid, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, encodePNGToBuffer, getDefaultRenderOptions, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBuffer, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderSceneFromGLTF, resolveRenderOptions };
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,12 @@ function computeWorldAABB(drawCalls) {
|
|
|
23
23
|
max[2] = Math.max(max[2], z);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
if (!isFinite(min[0])) {
|
|
27
|
+
return {
|
|
28
|
+
min: [-1, -1, -1],
|
|
29
|
+
max: [1, 1, 1]
|
|
30
|
+
};
|
|
31
|
+
}
|
|
26
32
|
return { min, max };
|
|
27
33
|
}
|
|
28
34
|
|
|
@@ -76,6 +82,49 @@ function buildCamera(drawCalls, width, height, fovDeg, camPos, lookAt) {
|
|
|
76
82
|
return { view, proj };
|
|
77
83
|
}
|
|
78
84
|
|
|
85
|
+
// lib/gltf/createGrid.ts
|
|
86
|
+
import { mat4 as mat42 } from "gl-matrix";
|
|
87
|
+
function createGrid(options = {}) {
|
|
88
|
+
const size = options.size ?? 10;
|
|
89
|
+
const sizeX = typeof size === "number" ? size : size[0];
|
|
90
|
+
const sizeZ = typeof size === "number" ? size : size[2];
|
|
91
|
+
const divisions = options.divisions ?? 10;
|
|
92
|
+
const color = options.color ?? [0.5, 0.5, 0.5];
|
|
93
|
+
const offset = { x: 0, y: 0, z: 0, ...options.offset };
|
|
94
|
+
const positions = [];
|
|
95
|
+
const indices = [];
|
|
96
|
+
let vertexIndex = 0;
|
|
97
|
+
const halfSizeX = sizeX / 2;
|
|
98
|
+
const halfSizeZ = sizeZ / 2;
|
|
99
|
+
const stepX = sizeX / divisions;
|
|
100
|
+
const stepZ = sizeZ / divisions;
|
|
101
|
+
for (let i = 0; i <= divisions; i++) {
|
|
102
|
+
const pX = -halfSizeX + i * stepX;
|
|
103
|
+
const pZ = -halfSizeZ + i * stepZ;
|
|
104
|
+
positions.push(pX, 0, -halfSizeZ);
|
|
105
|
+
positions.push(pX, 0, halfSizeZ);
|
|
106
|
+
indices.push(vertexIndex++, vertexIndex++);
|
|
107
|
+
positions.push(-halfSizeX, 0, pZ);
|
|
108
|
+
positions.push(halfSizeX, 0, pZ);
|
|
109
|
+
indices.push(vertexIndex++, vertexIndex++);
|
|
110
|
+
}
|
|
111
|
+
const model = mat42.create();
|
|
112
|
+
mat42.fromTranslation(model, [offset.x, offset.y, offset.z]);
|
|
113
|
+
return {
|
|
114
|
+
positions: new Float32Array(positions),
|
|
115
|
+
indices: new Uint32Array(indices),
|
|
116
|
+
normals: null,
|
|
117
|
+
uvs: null,
|
|
118
|
+
model,
|
|
119
|
+
material: {
|
|
120
|
+
baseColorFactor: [...color, 1],
|
|
121
|
+
baseColorTexture: null
|
|
122
|
+
},
|
|
123
|
+
mode: 1
|
|
124
|
+
// 1 = LINES
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
79
128
|
// lib/image/createUint8Bitmap.ts
|
|
80
129
|
var createUint8Bitmap = (width, height) => ({
|
|
81
130
|
width,
|
|
@@ -95,14 +144,15 @@ var DEFAULT_RENDER_OPTIONS = {
|
|
|
95
144
|
lightDir: DEFAULT_LIGHT_DIR,
|
|
96
145
|
camPos: null,
|
|
97
146
|
lookAt: null,
|
|
98
|
-
backgroundColor: null
|
|
147
|
+
backgroundColor: null,
|
|
148
|
+
grid: false
|
|
99
149
|
};
|
|
100
150
|
function getDefaultRenderOptions() {
|
|
101
151
|
return { ...DEFAULT_RENDER_OPTIONS };
|
|
102
152
|
}
|
|
103
153
|
|
|
104
154
|
// lib/render/SoftwareRenderer.ts
|
|
105
|
-
import { mat3, mat4 as
|
|
155
|
+
import { mat3, mat4 as mat43, vec3 as vec32, vec4 as vec42 } from "gl-matrix";
|
|
106
156
|
|
|
107
157
|
// lib/gltf/computeSmoothNormals.ts
|
|
108
158
|
function computeSmoothNormals(positions, indices) {
|
|
@@ -218,6 +268,96 @@ var SoftwareRenderer = class {
|
|
|
218
268
|
this.buffer[idx + 2] = b;
|
|
219
269
|
this.buffer[idx + 3] = a;
|
|
220
270
|
}
|
|
271
|
+
drawLines(mesh, camera, gammaOut = true) {
|
|
272
|
+
const { positions, indices, model, material } = mesh;
|
|
273
|
+
if (!indices) return;
|
|
274
|
+
const view = camera.view;
|
|
275
|
+
const proj = camera.proj;
|
|
276
|
+
const mvp = mat43.create();
|
|
277
|
+
mat43.multiply(mvp, proj, mat43.multiply(mat43.create(), view, model));
|
|
278
|
+
const vertexCount = positions.length / 3 | 0;
|
|
279
|
+
const vScreen = new Array(vertexCount);
|
|
280
|
+
const vInvW = new Float32Array(vertexCount);
|
|
281
|
+
const vNDCz = new Float32Array(vertexCount);
|
|
282
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
283
|
+
const p = vec42.fromValues(
|
|
284
|
+
positions[i * 3 + 0],
|
|
285
|
+
positions[i * 3 + 1],
|
|
286
|
+
positions[i * 3 + 2],
|
|
287
|
+
1
|
|
288
|
+
);
|
|
289
|
+
const c = vec42.create();
|
|
290
|
+
vec42.transformMat4(c, p, mvp);
|
|
291
|
+
const invW = 1 / c[3];
|
|
292
|
+
vInvW[i] = invW;
|
|
293
|
+
if (!isFinite(invW)) {
|
|
294
|
+
vScreen[i] = [NaN, NaN];
|
|
295
|
+
vNDCz[i] = NaN;
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const ndcX = c[0] * invW;
|
|
299
|
+
const ndcY = c[1] * invW;
|
|
300
|
+
const ndcZ = c[2] * invW;
|
|
301
|
+
const sx = (ndcX * 0.5 + 0.5) * (this.width - 1);
|
|
302
|
+
const sy = (1 - (ndcY * 0.5 + 0.5)) * (this.height - 1);
|
|
303
|
+
vScreen[i] = [sx, sy];
|
|
304
|
+
vNDCz[i] = ndcZ;
|
|
305
|
+
}
|
|
306
|
+
let [r, g, b, a] = material.baseColorFactor;
|
|
307
|
+
if (gammaOut) {
|
|
308
|
+
r = srgbEncodeLinear01(clamp(r, 0, 1));
|
|
309
|
+
g = srgbEncodeLinear01(clamp(g, 0, 1));
|
|
310
|
+
b = srgbEncodeLinear01(clamp(b, 0, 1));
|
|
311
|
+
} else {
|
|
312
|
+
r = clamp(r, 0, 1);
|
|
313
|
+
g = clamp(g, 0, 1);
|
|
314
|
+
b = clamp(b, 0, 1);
|
|
315
|
+
}
|
|
316
|
+
const r255 = r * 255 | 0;
|
|
317
|
+
const g255 = g * 255 | 0;
|
|
318
|
+
const b255 = b * 255 | 0;
|
|
319
|
+
const a255 = clamp(a, 0, 1) * 255 | 0;
|
|
320
|
+
for (let i = 0; i < indices.length; i += 2) {
|
|
321
|
+
const i0 = indices[i + 0];
|
|
322
|
+
const i1 = indices[i + 1];
|
|
323
|
+
const v0s = vScreen[i0];
|
|
324
|
+
const v1s = vScreen[i1];
|
|
325
|
+
const z0_ndc = vNDCz[i0];
|
|
326
|
+
const z1_ndc = vNDCz[i1];
|
|
327
|
+
if (isNaN(v0s[0]) || isNaN(v1s[0])) continue;
|
|
328
|
+
const z0_01 = z0_ndc * 0.5 + 0.5;
|
|
329
|
+
const z1_01 = z1_ndc * 0.5 + 0.5;
|
|
330
|
+
if (z0_01 < 0 && z1_01 < 0 || z0_01 > 1 && z1_01 > 1) continue;
|
|
331
|
+
const x0 = Math.round(v0s[0]);
|
|
332
|
+
const y0 = Math.round(v0s[1]);
|
|
333
|
+
const x1 = Math.round(v1s[0]);
|
|
334
|
+
const y1 = Math.round(v1s[1]);
|
|
335
|
+
const dx = x1 - x0;
|
|
336
|
+
const dy = y1 - y0;
|
|
337
|
+
const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
338
|
+
if (steps === 0) continue;
|
|
339
|
+
const xinc = dx / steps;
|
|
340
|
+
const yinc = dy / steps;
|
|
341
|
+
const zinc = (z1_01 - z0_01) / steps;
|
|
342
|
+
let x = x0;
|
|
343
|
+
let y = y0;
|
|
344
|
+
let z = z0_01;
|
|
345
|
+
for (let k = 0; k <= steps; k++) {
|
|
346
|
+
const xi = Math.round(x);
|
|
347
|
+
const yi = Math.round(y);
|
|
348
|
+
if (xi >= 0 && xi < this.width && yi >= 0 && yi < this.height && z >= 0 && z <= 1) {
|
|
349
|
+
const di = yi * this.width + xi;
|
|
350
|
+
if (z < this.depth[di]) {
|
|
351
|
+
this.depth[di] = z;
|
|
352
|
+
this.setPixel(xi, yi, r255, g255, b255, a255);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
x += xinc;
|
|
356
|
+
y += yinc;
|
|
357
|
+
z += zinc;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
221
361
|
sampleTextureNearest(img, u, v) {
|
|
222
362
|
if (!img) return [1, 1, 1, 1];
|
|
223
363
|
const x = clamp(Math.floor(u * (img.width - 1)), 0, img.width - 1);
|
|
@@ -247,8 +387,8 @@ var SoftwareRenderer = class {
|
|
|
247
387
|
const { positions, normals, uvs, indices, model, colors } = mesh;
|
|
248
388
|
const view = camera.view;
|
|
249
389
|
const proj = camera.proj;
|
|
250
|
-
const mvp =
|
|
251
|
-
|
|
390
|
+
const mvp = mat43.create();
|
|
391
|
+
mat43.multiply(mvp, proj, mat43.multiply(mat43.create(), view, model));
|
|
252
392
|
const normalMat = mat3.create();
|
|
253
393
|
mat3.normalFromMat4(normalMat, model);
|
|
254
394
|
const vertexCount = positions.length / 3 | 0;
|
|
@@ -404,6 +544,13 @@ var SoftwareRenderer = class {
|
|
|
404
544
|
let g = baseColor[1] * lit;
|
|
405
545
|
let b = baseColor[2] * lit;
|
|
406
546
|
let a = baseColor[3];
|
|
547
|
+
const alphaMode = material.alphaMode ?? "OPAQUE";
|
|
548
|
+
const alphaCutoff = material.alphaCutoff ?? 0.5;
|
|
549
|
+
if (alphaMode === "MASK" && a < alphaCutoff) continue;
|
|
550
|
+
const shouldWriteDepth = alphaMode !== "BLEND";
|
|
551
|
+
if (shouldWriteDepth) {
|
|
552
|
+
depth[di] = z01;
|
|
553
|
+
}
|
|
407
554
|
if (gammaOut) {
|
|
408
555
|
r = srgbEncodeLinear01(clamp(r, 0, 1));
|
|
409
556
|
g = srgbEncodeLinear01(clamp(g, 0, 1));
|
|
@@ -413,13 +560,29 @@ var SoftwareRenderer = class {
|
|
|
413
560
|
g = clamp(g, 0, 1);
|
|
414
561
|
b = clamp(b, 0, 1);
|
|
415
562
|
}
|
|
563
|
+
const dstIdx = (y * this.width + x) * 4;
|
|
564
|
+
const dstR = (this.buffer[dstIdx + 0] ?? 0) / 255;
|
|
565
|
+
const dstG = (this.buffer[dstIdx + 1] ?? 0) / 255;
|
|
566
|
+
const dstB = (this.buffer[dstIdx + 2] ?? 0) / 255;
|
|
567
|
+
const dstA = (this.buffer[dstIdx + 3] ?? 0) / 255;
|
|
568
|
+
let outR = r;
|
|
569
|
+
let outG = g;
|
|
570
|
+
let outB = b;
|
|
571
|
+
let outA = a;
|
|
572
|
+
if (alphaMode === "BLEND" && a < 1) {
|
|
573
|
+
const oneMinusA = 1 - a;
|
|
574
|
+
outR = r * a + dstR * oneMinusA;
|
|
575
|
+
outG = g * a + dstG * oneMinusA;
|
|
576
|
+
outB = b * a + dstB * oneMinusA;
|
|
577
|
+
outA = a + dstA * oneMinusA;
|
|
578
|
+
}
|
|
416
579
|
this.setPixel(
|
|
417
580
|
x,
|
|
418
581
|
y,
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
clamp(
|
|
582
|
+
clamp(outR, 0, 1) * 255 | 0,
|
|
583
|
+
clamp(outG, 0, 1) * 255 | 0,
|
|
584
|
+
clamp(outB, 0, 1) * 255 | 0,
|
|
585
|
+
clamp(outA, 0, 1) * 255 | 0
|
|
423
586
|
);
|
|
424
587
|
}
|
|
425
588
|
}
|
|
@@ -468,21 +631,66 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
|
|
|
468
631
|
} else {
|
|
469
632
|
renderer.clear([0, 0, 0, 0]);
|
|
470
633
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
634
|
+
const allDrawCalls = [...drawCalls];
|
|
635
|
+
if (options.grid) {
|
|
636
|
+
const userGridOptions = typeof options.grid === "boolean" ? {} : options.grid;
|
|
637
|
+
const aabb = computeWorldAABB(drawCalls);
|
|
638
|
+
const sizeX = aabb.max[0] - aabb.min[0];
|
|
639
|
+
const sizeZ = aabb.max[2] - aabb.min[2];
|
|
640
|
+
const maxSize = Math.max(sizeX, sizeZ);
|
|
641
|
+
const defaultSize = Math.ceil(maxSize * 1.2 / 2) * 2;
|
|
642
|
+
const defaultOffset = {
|
|
643
|
+
x: (aabb.min[0] + aabb.max[0]) / 2,
|
|
644
|
+
y: aabb.min[1],
|
|
645
|
+
z: (aabb.min[2] + aabb.max[2]) / 2
|
|
646
|
+
};
|
|
647
|
+
const defaultGridOptions = {
|
|
648
|
+
size: defaultSize > 0 ? defaultSize : 10,
|
|
649
|
+
offset: defaultOffset
|
|
650
|
+
};
|
|
651
|
+
const finalGridOptions = {
|
|
652
|
+
...defaultGridOptions,
|
|
653
|
+
...userGridOptions,
|
|
654
|
+
offset: {
|
|
655
|
+
...defaultGridOptions.offset,
|
|
656
|
+
...userGridOptions.offset
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
allDrawCalls.push(createGrid(finalGridOptions));
|
|
480
660
|
}
|
|
661
|
+
const opaqueDraws = allDrawCalls.filter(
|
|
662
|
+
(dc) => (dc.material.alphaMode ?? "OPAQUE") === "OPAQUE"
|
|
663
|
+
);
|
|
664
|
+
const maskDraws = allDrawCalls.filter(
|
|
665
|
+
(dc) => (dc.material.alphaMode ?? "OPAQUE") === "MASK"
|
|
666
|
+
);
|
|
667
|
+
const blendDraws = allDrawCalls.filter(
|
|
668
|
+
(dc) => (dc.material.alphaMode ?? "OPAQUE") === "BLEND"
|
|
669
|
+
);
|
|
670
|
+
const renderGroup = (dcs) => {
|
|
671
|
+
for (const dc of dcs) {
|
|
672
|
+
if (dc.mode === 1) {
|
|
673
|
+
renderer.drawLines(dc, camera, options.gamma);
|
|
674
|
+
} else {
|
|
675
|
+
renderer.drawMesh(
|
|
676
|
+
dc,
|
|
677
|
+
camera,
|
|
678
|
+
{ dir: options.lightDir, ambient: options.ambient },
|
|
679
|
+
dc.material,
|
|
680
|
+
options.cull,
|
|
681
|
+
options.gamma
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
renderGroup(opaqueDraws);
|
|
687
|
+
renderGroup(maskDraws);
|
|
688
|
+
renderGroup(blendDraws);
|
|
481
689
|
return { bitmap: renderer.bitmap, camera, options };
|
|
482
690
|
}
|
|
483
691
|
|
|
484
692
|
// lib/gltf/createSceneFromGLTF.ts
|
|
485
|
-
import { mat4 as
|
|
693
|
+
import { mat4 as mat44 } from "gl-matrix";
|
|
486
694
|
var COMPONENT_INFO = {
|
|
487
695
|
5120: {
|
|
488
696
|
name: "BYTE",
|
|
@@ -680,17 +888,17 @@ function readIndices(ctx, accessorIndex) {
|
|
|
680
888
|
}
|
|
681
889
|
function nodeLocalMatrix(node) {
|
|
682
890
|
if (node.matrix) {
|
|
683
|
-
const m2 =
|
|
891
|
+
const m2 = mat44.create();
|
|
684
892
|
for (let i = 0; i < 16; i++) m2[i] = node.matrix[i];
|
|
685
893
|
return m2;
|
|
686
894
|
}
|
|
687
895
|
const translation = node.translation || [0, 0, 0];
|
|
688
896
|
const rotation = node.rotation || [0, 0, 0, 1];
|
|
689
897
|
const scale = node.scale || [1, 1, 1];
|
|
690
|
-
const m =
|
|
691
|
-
const tmp =
|
|
692
|
-
|
|
693
|
-
|
|
898
|
+
const m = mat44.create();
|
|
899
|
+
const tmp = mat44.create();
|
|
900
|
+
mat44.fromRotationTranslationScale(tmp, rotation, translation, scale);
|
|
901
|
+
mat44.copy(m, tmp);
|
|
694
902
|
return m;
|
|
695
903
|
}
|
|
696
904
|
function getMaterial(gltf, textures, images, materialIndex) {
|
|
@@ -706,7 +914,14 @@ function getMaterial(gltf, textures, images, materialIndex) {
|
|
|
706
914
|
texImg = images[imageIndex] || null;
|
|
707
915
|
}
|
|
708
916
|
}
|
|
709
|
-
|
|
917
|
+
const alphaMode = typeof material.alphaMode === "string" ? material.alphaMode : "OPAQUE";
|
|
918
|
+
const alphaCutoff = typeof material.alphaCutoff === "number" ? material.alphaCutoff : 0.5;
|
|
919
|
+
return {
|
|
920
|
+
baseColorFactor: factor,
|
|
921
|
+
baseColorTexture: texImg,
|
|
922
|
+
alphaMode,
|
|
923
|
+
alphaCutoff
|
|
924
|
+
};
|
|
710
925
|
}
|
|
711
926
|
function createSceneFromGLTF(gltf, resources) {
|
|
712
927
|
const ctx = { gltf, buffers: resources.buffers };
|
|
@@ -721,8 +936,8 @@ function createSceneFromGLTF(gltf, resources) {
|
|
|
721
936
|
const node = nodes[nodeIndex];
|
|
722
937
|
if (!node) return;
|
|
723
938
|
const local = nodeLocalMatrix(node);
|
|
724
|
-
const world =
|
|
725
|
-
|
|
939
|
+
const world = mat44.create();
|
|
940
|
+
mat44.multiply(world, parentMatrix, local);
|
|
726
941
|
if (Number.isInteger(node.mesh)) {
|
|
727
942
|
const mesh = meshes[node.mesh];
|
|
728
943
|
if (mesh) {
|
|
@@ -760,7 +975,7 @@ function createSceneFromGLTF(gltf, resources) {
|
|
|
760
975
|
traverse(childIndex, world);
|
|
761
976
|
}
|
|
762
977
|
}
|
|
763
|
-
const identity =
|
|
978
|
+
const identity = mat44.create();
|
|
764
979
|
for (const rootIndex of scene.nodes || []) {
|
|
765
980
|
traverse(rootIndex, identity);
|
|
766
981
|
}
|
|
@@ -1163,6 +1378,7 @@ export {
|
|
|
1163
1378
|
buildCamera,
|
|
1164
1379
|
computeSmoothNormals,
|
|
1165
1380
|
computeWorldAABB,
|
|
1381
|
+
createGrid,
|
|
1166
1382
|
createSceneFromGLTF,
|
|
1167
1383
|
createUint8Bitmap,
|
|
1168
1384
|
decodeImageFromBuffer,
|