poppygl 0.0.11 → 0.0.13
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 +34 -19
- package/dist/index.js +205 -24
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,23 +10,6 @@ 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;
|
|
@@ -39,6 +22,17 @@ interface DrawCall {
|
|
|
39
22
|
model: mat4;
|
|
40
23
|
material: Material;
|
|
41
24
|
colors?: Float32Array | null;
|
|
25
|
+
mode?: number;
|
|
26
|
+
}
|
|
27
|
+
interface GridOptions {
|
|
28
|
+
size?: number | readonly [number, number, number];
|
|
29
|
+
divisions?: number;
|
|
30
|
+
color?: readonly [number, number, number];
|
|
31
|
+
offset?: Partial<{
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
z: number;
|
|
35
|
+
}>;
|
|
42
36
|
}
|
|
43
37
|
interface GLTFResources {
|
|
44
38
|
buffers: Uint8Array[];
|
|
@@ -49,6 +43,24 @@ interface GLTFScene {
|
|
|
49
43
|
gltf: any;
|
|
50
44
|
}
|
|
51
45
|
|
|
46
|
+
declare const DEFAULT_LIGHT_DIR: readonly [-0.4, -0.9, -0.2];
|
|
47
|
+
interface RenderOptions {
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
fov: number;
|
|
51
|
+
cull: boolean;
|
|
52
|
+
gamma: boolean;
|
|
53
|
+
ambient: number;
|
|
54
|
+
lightDir: readonly [number, number, number];
|
|
55
|
+
camPos?: readonly [number, number, number] | null;
|
|
56
|
+
lookAt?: readonly [number, number, number] | null;
|
|
57
|
+
backgroundColor?: readonly [number, number, number] | null;
|
|
58
|
+
grid?: boolean | GridOptions;
|
|
59
|
+
}
|
|
60
|
+
type RenderOptionsInput = Partial<RenderOptions>;
|
|
61
|
+
declare const DEFAULT_RENDER_OPTIONS: RenderOptions;
|
|
62
|
+
declare function getDefaultRenderOptions(): RenderOptions;
|
|
63
|
+
|
|
52
64
|
interface Camera {
|
|
53
65
|
view: mat4;
|
|
54
66
|
proj: mat4;
|
|
@@ -64,6 +76,8 @@ declare function renderDrawCalls(drawCalls: DrawCall[], optionsInput?: RenderOpt
|
|
|
64
76
|
|
|
65
77
|
declare function resolveRenderOptions(options?: RenderOptionsInput): RenderOptions;
|
|
66
78
|
|
|
79
|
+
declare function createGrid(options?: GridOptions): DrawCall;
|
|
80
|
+
|
|
67
81
|
type GLTF = any;
|
|
68
82
|
declare function createSceneFromGLTF(gltf: GLTF, resources: GLTFResources): GLTFScene;
|
|
69
83
|
|
|
@@ -108,6 +122,7 @@ declare class SoftwareRenderer {
|
|
|
108
122
|
get buffer(): Uint8Array<ArrayBufferLike> | Uint8ClampedArray<ArrayBufferLike>;
|
|
109
123
|
clear(colorRGBA?: [number, number, number, number]): void;
|
|
110
124
|
setPixel(x: number, y: number, r: number, g: number, b: number, a: number): void;
|
|
125
|
+
drawLines(mesh: DrawCall, camera: Camera, gammaOut?: boolean): void;
|
|
111
126
|
sampleTextureNearest(img: BitmapLike | null, u: number, v: number): MutableRGBA;
|
|
112
127
|
perspInterp(attrs: number[][], invWs: number[], lambdas: number[]): number[];
|
|
113
128
|
drawMesh(mesh: DrawCall, camera: Camera, light: LightSettings, material: Material, cullBackFaces?: boolean, gammaOut?: boolean): void;
|
|
@@ -124,8 +139,8 @@ declare function renderGLTFToPNGBufferFromURL(url: string, options?: RenderGLTFT
|
|
|
124
139
|
type RenderGLTFToPNGBufferFromGLBBufferOptions = RenderOptionsInput;
|
|
125
140
|
declare function renderGLTFToPNGBufferFromGLBBuffer(glb: ArrayBuffer | Uint8Array, options?: RenderGLTFToPNGBufferFromGLBBufferOptions): Promise<Buffer>;
|
|
126
141
|
|
|
127
|
-
declare function renderGLTFToPNGBuffer(
|
|
142
|
+
declare function renderGLTFToPNGBuffer(gltfPathOrString: string, options?: RenderOptionsInput): Promise<Buffer>;
|
|
128
143
|
|
|
129
144
|
declare function renderSceneFromGLTF(scene: GLTFScene, options?: RenderOptionsInput, imageFactory?: ImageFactory): RenderResult;
|
|
130
145
|
|
|
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 };
|
|
146
|
+
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;
|
|
@@ -468,21 +608,52 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
|
|
|
468
608
|
} else {
|
|
469
609
|
renderer.clear([0, 0, 0, 0]);
|
|
470
610
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
611
|
+
const allDrawCalls = [...drawCalls];
|
|
612
|
+
if (options.grid) {
|
|
613
|
+
const userGridOptions = typeof options.grid === "boolean" ? {} : options.grid;
|
|
614
|
+
const aabb = computeWorldAABB(drawCalls);
|
|
615
|
+
const sizeX = aabb.max[0] - aabb.min[0];
|
|
616
|
+
const sizeZ = aabb.max[2] - aabb.min[2];
|
|
617
|
+
const maxSize = Math.max(sizeX, sizeZ);
|
|
618
|
+
const defaultSize = Math.ceil(maxSize * 1.2 / 2) * 2;
|
|
619
|
+
const defaultOffset = {
|
|
620
|
+
x: (aabb.min[0] + aabb.max[0]) / 2,
|
|
621
|
+
y: aabb.min[1],
|
|
622
|
+
z: (aabb.min[2] + aabb.max[2]) / 2
|
|
623
|
+
};
|
|
624
|
+
const defaultGridOptions = {
|
|
625
|
+
size: defaultSize > 0 ? defaultSize : 10,
|
|
626
|
+
offset: defaultOffset
|
|
627
|
+
};
|
|
628
|
+
const finalGridOptions = {
|
|
629
|
+
...defaultGridOptions,
|
|
630
|
+
...userGridOptions,
|
|
631
|
+
offset: {
|
|
632
|
+
...defaultGridOptions.offset,
|
|
633
|
+
...userGridOptions.offset
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
allDrawCalls.push(createGrid(finalGridOptions));
|
|
637
|
+
}
|
|
638
|
+
for (const dc of allDrawCalls) {
|
|
639
|
+
if (dc.mode === 1) {
|
|
640
|
+
renderer.drawLines(dc, camera, options.gamma);
|
|
641
|
+
} else {
|
|
642
|
+
renderer.drawMesh(
|
|
643
|
+
dc,
|
|
644
|
+
camera,
|
|
645
|
+
{ dir: options.lightDir, ambient: options.ambient },
|
|
646
|
+
dc.material,
|
|
647
|
+
options.cull,
|
|
648
|
+
options.gamma
|
|
649
|
+
);
|
|
650
|
+
}
|
|
480
651
|
}
|
|
481
652
|
return { bitmap: renderer.bitmap, camera, options };
|
|
482
653
|
}
|
|
483
654
|
|
|
484
655
|
// lib/gltf/createSceneFromGLTF.ts
|
|
485
|
-
import { mat4 as
|
|
656
|
+
import { mat4 as mat44 } from "gl-matrix";
|
|
486
657
|
var COMPONENT_INFO = {
|
|
487
658
|
5120: {
|
|
488
659
|
name: "BYTE",
|
|
@@ -680,17 +851,17 @@ function readIndices(ctx, accessorIndex) {
|
|
|
680
851
|
}
|
|
681
852
|
function nodeLocalMatrix(node) {
|
|
682
853
|
if (node.matrix) {
|
|
683
|
-
const m2 =
|
|
854
|
+
const m2 = mat44.create();
|
|
684
855
|
for (let i = 0; i < 16; i++) m2[i] = node.matrix[i];
|
|
685
856
|
return m2;
|
|
686
857
|
}
|
|
687
858
|
const translation = node.translation || [0, 0, 0];
|
|
688
859
|
const rotation = node.rotation || [0, 0, 0, 1];
|
|
689
860
|
const scale = node.scale || [1, 1, 1];
|
|
690
|
-
const m =
|
|
691
|
-
const tmp =
|
|
692
|
-
|
|
693
|
-
|
|
861
|
+
const m = mat44.create();
|
|
862
|
+
const tmp = mat44.create();
|
|
863
|
+
mat44.fromRotationTranslationScale(tmp, rotation, translation, scale);
|
|
864
|
+
mat44.copy(m, tmp);
|
|
694
865
|
return m;
|
|
695
866
|
}
|
|
696
867
|
function getMaterial(gltf, textures, images, materialIndex) {
|
|
@@ -721,8 +892,8 @@ function createSceneFromGLTF(gltf, resources) {
|
|
|
721
892
|
const node = nodes[nodeIndex];
|
|
722
893
|
if (!node) return;
|
|
723
894
|
const local = nodeLocalMatrix(node);
|
|
724
|
-
const world =
|
|
725
|
-
|
|
895
|
+
const world = mat44.create();
|
|
896
|
+
mat44.multiply(world, parentMatrix, local);
|
|
726
897
|
if (Number.isInteger(node.mesh)) {
|
|
727
898
|
const mesh = meshes[node.mesh];
|
|
728
899
|
if (mesh) {
|
|
@@ -760,7 +931,7 @@ function createSceneFromGLTF(gltf, resources) {
|
|
|
760
931
|
traverse(childIndex, world);
|
|
761
932
|
}
|
|
762
933
|
}
|
|
763
|
-
const identity =
|
|
934
|
+
const identity = mat44.create();
|
|
764
935
|
for (const rootIndex of scene.nodes || []) {
|
|
765
936
|
traverse(rootIndex, identity);
|
|
766
937
|
}
|
|
@@ -1135,8 +1306,17 @@ async function loadGLTFWithResources(gltfPath) {
|
|
|
1135
1306
|
}
|
|
1136
1307
|
|
|
1137
1308
|
// cli/renderGLTFToPNGBuffer.ts
|
|
1138
|
-
async function renderGLTFToPNGBuffer(
|
|
1139
|
-
|
|
1309
|
+
async function renderGLTFToPNGBuffer(gltfPathOrString, options = {}) {
|
|
1310
|
+
let gltf;
|
|
1311
|
+
let resources;
|
|
1312
|
+
try {
|
|
1313
|
+
gltf = JSON.parse(gltfPathOrString);
|
|
1314
|
+
resources = { buffers: [], images: [] };
|
|
1315
|
+
} catch {
|
|
1316
|
+
const result = await loadGLTFWithResources(gltfPathOrString);
|
|
1317
|
+
gltf = result.gltf;
|
|
1318
|
+
resources = result.resources;
|
|
1319
|
+
}
|
|
1140
1320
|
const scene = createSceneFromGLTF(gltf, resources);
|
|
1141
1321
|
const { bitmap } = renderSceneFromGLTF(scene, options, pureImageFactory);
|
|
1142
1322
|
return encodePNGToBuffer(bitmap);
|
|
@@ -1154,6 +1334,7 @@ export {
|
|
|
1154
1334
|
buildCamera,
|
|
1155
1335
|
computeSmoothNormals,
|
|
1156
1336
|
computeWorldAABB,
|
|
1337
|
+
createGrid,
|
|
1157
1338
|
createSceneFromGLTF,
|
|
1158
1339
|
createUint8Bitmap,
|
|
1159
1340
|
decodeImageFromBuffer,
|