trid3d 0.1.1 → 0.3.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/README.md +15 -9
- package/package.json +2 -1
- package/trid/export/capture.js +150 -0
- package/trid/export/mtl.js +119 -0
- package/trid/export/obj.js +227 -0
- package/trid/index.d.ts +630 -16
- package/trid/index.js +29 -6
- package/trid/loaders/mtl.js +63 -0
- package/trid/loaders/obj.js +72 -4
- package/trid/loaders/texture.js +47 -6
- package/trid/math/matrix.js +200 -0
- package/trid/math/noise.js +162 -0
- package/trid/math/rotation.js +152 -0
- package/trid/render/canvasRenderer.js +132 -82
- package/trid/render/draw.js +21 -6
- package/trid/render/meshUtils.js +257 -0
- package/trid/render/proceduralTextures.js +211 -0
- package/trid/render/shapes.js +353 -23
- package/trid/render/uvMapping.js +225 -0
- package/trid/render/webglRenderer.js +240 -75
- package/trid/scene.js +43 -9
- package/trid/sceneGraph.js +131 -0
- package/trid/tools/dragObject.js +33 -9
- package/trid/tools/helpers.js +109 -10
- package/trid/tools/hoverHighlight.js +6 -3
- package/trid/tools/index.js +3 -1
- package/trid/tools/orbitCamera.js +27 -0
- package/trid/tools/transformGizmo.js +316 -0
- package/trid/tools/viewGizmo.js +178 -0
package/trid/index.d.ts
CHANGED
|
@@ -56,10 +56,11 @@ export interface Camera {
|
|
|
56
56
|
*
|
|
57
57
|
* An edge with 2 indices is a single segment; with 3 or more it's a closed loop.
|
|
58
58
|
* Faces are clockwise as seen from their front.
|
|
59
|
+
* Without `edges`, an object with no material draws the outline of each face.
|
|
59
60
|
*/
|
|
60
61
|
export interface Mesh {
|
|
61
62
|
vertices: Vec3[];
|
|
62
|
-
edges
|
|
63
|
+
edges?: number[][];
|
|
63
64
|
faces?: number[][];
|
|
64
65
|
/** Per-corner normals, used by smooth shading */
|
|
65
66
|
normals?: Vec3[];
|
|
@@ -69,6 +70,11 @@ export interface Mesh {
|
|
|
69
70
|
uvs?: UV[];
|
|
70
71
|
/** For each face, the index into `uvs` of each corner (null: none for that face) */
|
|
71
72
|
faceUVs?: (number[] | null)[];
|
|
73
|
+
/**
|
|
74
|
+
* For each face, which entry of the object's material list it uses
|
|
75
|
+
* (when `material` is a list). Built-in cubes and boxes number their sides 0 to 5.
|
|
76
|
+
*/
|
|
77
|
+
faceMaterials?: number[];
|
|
72
78
|
/** Set after changing the mesh in place so renderers rebuild their caches */
|
|
73
79
|
dirty?: boolean;
|
|
74
80
|
}
|
|
@@ -100,24 +106,56 @@ export interface Material {
|
|
|
100
106
|
smooth?: boolean | number;
|
|
101
107
|
/** Image drawn on the faces (needs texture coordinates). `fill` tints it. */
|
|
102
108
|
texture?: TextureSource;
|
|
109
|
+
/**
|
|
110
|
+
* Read the texture again every frame (default: only videos). For a canvas redrawn every
|
|
111
|
+
* frame; for one redrawn now and then, call `updateTexture(canvas)` instead.
|
|
112
|
+
*/
|
|
113
|
+
liveTexture?: boolean;
|
|
103
114
|
/** Keep texture pixels sharp instead of smoothing them (default false) */
|
|
104
115
|
pixelated?: boolean;
|
|
105
116
|
/** Effects applied in order, like `[toon(), rim()]` */
|
|
106
117
|
effects?: Effect[];
|
|
118
|
+
/** Where texture coordinates come from: the mesh's own ("uv", default) or made from its shape */
|
|
119
|
+
mapping?: Mapping;
|
|
120
|
+
/** How many times the texture repeats across (default 1) */
|
|
121
|
+
textureRepeat?: number | UV;
|
|
122
|
+
/** Moves the texture; 1 is its whole width or height */
|
|
123
|
+
textureOffset?: UV;
|
|
124
|
+
/** Turns the texture around its center, in radians */
|
|
125
|
+
textureRotation?: number;
|
|
107
126
|
}
|
|
108
127
|
|
|
109
|
-
/**
|
|
128
|
+
/** Ways to make texture coordinates from a mesh's shape. */
|
|
129
|
+
export type MappingType = "uv" | "planar" | "box" | "sphere" | "cylinder";
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A texture mapping: a type, or a type with an axis. `axis` is the projection
|
|
133
|
+
* direction for "planar" (default "z") and the wrap axis for "sphere" and "cylinder" (default "y").
|
|
134
|
+
*/
|
|
135
|
+
export type Mapping = MappingType | { type: MappingType; axis?: "x" | "y" | "z" };
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* What you pass to `scene.add`. Missing transform fields get defaults.
|
|
139
|
+
* Give it `children` to make a group (and leave out `mesh` for a group that only holds them).
|
|
140
|
+
*/
|
|
110
141
|
export interface SceneObjectInput {
|
|
111
|
-
|
|
142
|
+
/** What's drawn. Leave it out for a group that only holds `children` */
|
|
143
|
+
mesh?: Mesh;
|
|
112
144
|
pos?: Vec3;
|
|
113
145
|
rot?: Vec3;
|
|
114
146
|
scale?: Vec3;
|
|
147
|
+
/** Objects placed relative to this one: they move, turn and scale with it. Read every frame */
|
|
148
|
+
children?: SceneObjectInput[];
|
|
149
|
+
/** Set to false to hide this object and everything under it (default true) */
|
|
150
|
+
visible?: boolean;
|
|
151
|
+
/** A name, used by `exportOBJ` and handy for finding objects */
|
|
152
|
+
name?: string;
|
|
115
153
|
/** Wireframe color (default: the scene's color) */
|
|
116
154
|
color?: string;
|
|
117
155
|
/** Wireframe width (default: the scene's lineWidth) */
|
|
118
156
|
lineWidth?: number;
|
|
119
|
-
/** Draw faces instead of only lines */
|
|
120
|
-
material?: Material;
|
|
157
|
+
/** Draw faces instead of only lines. A list gives each group of faces its own (see `Mesh.faceMaterials`) */
|
|
158
|
+
material?: Material | Material[];
|
|
121
159
|
/** Set to false to make `DragObject` ignore this object */
|
|
122
160
|
draggable?: boolean;
|
|
123
161
|
/** Set to false to make `HoverHighlight` ignore this object */
|
|
@@ -128,7 +166,12 @@ export interface SceneObjectInput {
|
|
|
128
166
|
* An object in a scene, after `scene.add` filled in its transform.
|
|
129
167
|
* Extra fields you add (like `{ mesh, name: "box" }`) are kept in the type.
|
|
130
168
|
*/
|
|
131
|
-
export type SceneObject<T extends SceneObjectInput = SceneObjectInput> = T & Transform
|
|
169
|
+
export type SceneObject<T extends SceneObjectInput = SceneObjectInput> = T & Transform & {
|
|
170
|
+
/** The group it's a child of, or null at the top. Kept up to date by the scene (not enumerable) */
|
|
171
|
+
parent: SceneObject | null;
|
|
172
|
+
/** World matrix from the last frame: parents' transforms × its own (not enumerable). See `worldMatrix` */
|
|
173
|
+
world: Mat4;
|
|
174
|
+
};
|
|
132
175
|
|
|
133
176
|
// ---------------------------------------------------------------------------
|
|
134
177
|
// Scene
|
|
@@ -191,6 +234,10 @@ export class Scene {
|
|
|
191
234
|
start(update?: (dt: number, time: number, scene: Scene) => void): this;
|
|
192
235
|
/** Stops the frame loop. The last frame stays on the canvas. */
|
|
193
236
|
stop(): void;
|
|
237
|
+
/** Draws a new frame and returns it as an image file. The page's canvas doesn't change. */
|
|
238
|
+
screenshot(opts?: ScreenshotOptions): Promise<Blob>;
|
|
239
|
+
/** Starts recording the canvas as a video. */
|
|
240
|
+
record(opts?: RecordOptions): Recording;
|
|
194
241
|
/** Stops the loop, removes every tool and frees the renderer's resources. */
|
|
195
242
|
destroy(): void;
|
|
196
243
|
/** Whether the frame loop is running. */
|
|
@@ -202,30 +249,139 @@ export class Scene {
|
|
|
202
249
|
// ---------------------------------------------------------------------------
|
|
203
250
|
|
|
204
251
|
export interface ShapeOptions {
|
|
205
|
-
/** Cube size (default 0.5) */
|
|
252
|
+
/** Cube size, or plane width (default 0.5 cube, 1 plane) */
|
|
206
253
|
size?: number;
|
|
207
254
|
/** Box width (default 0.6) */
|
|
208
255
|
w?: number;
|
|
209
|
-
/** Box height (default 0.6) */
|
|
256
|
+
/** Box height (default 0.6), or cylinder / cone height (default 0.8) */
|
|
210
257
|
h?: number;
|
|
211
258
|
/** Box depth (default 0.6) */
|
|
212
259
|
d?: number;
|
|
213
|
-
/**
|
|
260
|
+
/** Radius: sphere (0.45), cylinder (0.3), cone base (0.35) */
|
|
214
261
|
r?: number;
|
|
215
262
|
/** Sphere latitude bands (default 12) */
|
|
216
263
|
rings?: number;
|
|
217
|
-
/**
|
|
264
|
+
/** Points around: sphere (24), cylinder / cone (32), torus (48) */
|
|
218
265
|
segments?: number;
|
|
266
|
+
/** Cone top radius: 0 = pointed, > 0 = tapered cylinder (default 0) */
|
|
267
|
+
rTop?: number;
|
|
268
|
+
/** Torus: distance from the center to the middle of the tube (default 0.35) */
|
|
269
|
+
R?: number;
|
|
270
|
+
/** Torus tube radius (default 0.12) */
|
|
271
|
+
tube?: number;
|
|
272
|
+
/** Torus points around the tube (default 20) */
|
|
273
|
+
tubeSegments?: number;
|
|
274
|
+
/** Plane cells per side (default 8) */
|
|
275
|
+
div?: number;
|
|
276
|
+
/** Plane: lifts each vertex, for terrain */
|
|
277
|
+
height?: (x: number, z: number) => number;
|
|
219
278
|
}
|
|
220
279
|
|
|
221
|
-
export type ShapeKind = "cube" | "box" | "sphere";
|
|
280
|
+
export type ShapeKind = "cube" | "box" | "sphere" | "cylinder" | "cone" | "torus" | "plane";
|
|
222
281
|
|
|
223
|
-
/**
|
|
282
|
+
/**
|
|
283
|
+
* Creates a built-in mesh (with edges, faces and texture coordinates), centered
|
|
284
|
+
* on the origin. Cylinders, cones and tori stand along Y; the plane lies in XZ facing +Y.
|
|
285
|
+
*/
|
|
224
286
|
export function makeShape(kind: ShapeKind, opts?: ShapeOptions): Mesh;
|
|
225
287
|
|
|
288
|
+
/** A point of a `lathe` profile: distance from the Y axis and height. */
|
|
289
|
+
export interface ProfilePoint {
|
|
290
|
+
r: number;
|
|
291
|
+
y: number;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export interface LatheOptions {
|
|
295
|
+
/** Points around the axis (default 32) */
|
|
296
|
+
segments?: number;
|
|
297
|
+
/** Close the bottom with a flat cap (default false) */
|
|
298
|
+
capBottom?: boolean;
|
|
299
|
+
/** Close the top with a flat cap (default false) */
|
|
300
|
+
capTop?: boolean;
|
|
301
|
+
/** The profile's last point joins its first, for torus-like shapes (default false) */
|
|
302
|
+
closed?: boolean;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Spins a profile around the Y axis (vases, bottles, columns, chess pieces).
|
|
307
|
+
* Walk the profile so the outside is on its right: bottom to top for a vase.
|
|
308
|
+
*/
|
|
309
|
+
export function lathe(profile: ProfilePoint[], opts?: LatheOptions): Mesh;
|
|
310
|
+
|
|
311
|
+
/** A 2D point (x right, y up). */
|
|
312
|
+
export interface Point2 {
|
|
313
|
+
x: number;
|
|
314
|
+
y: number;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Turns a flat outline in the XY plane into a solid `depth` thick along Z
|
|
319
|
+
* (default 0.2), centered on the origin. Either direction, concave is fine, no holes.
|
|
320
|
+
*/
|
|
321
|
+
export interface ExtrudeOptions {
|
|
322
|
+
/** How much the edges between sides and front / back are cut, up to half the depth (default 0) */
|
|
323
|
+
bevel?: number;
|
|
324
|
+
/** Steps around a bevel: 1 = flat chamfer, more = rounded (default 1) */
|
|
325
|
+
bevelSegments?: number;
|
|
326
|
+
/** Size of the back compared to the front, around the outline's middle (default 1) */
|
|
327
|
+
taper?: number;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export function extrude(outline: Point2[], depth?: number, opts?: ExtrudeOptions): Mesh;
|
|
331
|
+
|
|
332
|
+
/** Cuts a counter-clockwise polygon into counter-clockwise triangles (ear clipping). */
|
|
333
|
+
export function triangulate(pts: Point2[]): number[][];
|
|
334
|
+
|
|
226
335
|
/** Scales a mesh's vertices in place. Returns the same mesh. */
|
|
227
336
|
export function scaleMesh<M extends { vertices: Vec3[] }>(mesh: M, sx?: number, sy?: number, sz?: number): M;
|
|
228
337
|
|
|
338
|
+
/** A transform to bake into a mesh; parts left out change nothing. A scene object fits. */
|
|
339
|
+
export interface MeshTransform {
|
|
340
|
+
pos?: Partial<Vec3>;
|
|
341
|
+
rot?: Partial<Vec3>;
|
|
342
|
+
scale?: Partial<Vec3>;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Deep copy of a mesh (vertices, edges, faces, UVs, normals, materials). */
|
|
346
|
+
export function cloneMesh<M extends Mesh>(mesh: M): M;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Bakes a transform into a mesh's vertices, in place (scale, rotate X→Y→Z, move).
|
|
350
|
+
* Normals turn with it; a mirroring scale reverses the faces. Returns the same mesh.
|
|
351
|
+
*/
|
|
352
|
+
export function transformMesh<M extends Mesh>(mesh: M, transform: MeshTransform): M;
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Moves every vertex to `fn(vertex, index)`, in place. Removes the mesh's own normals
|
|
356
|
+
* (they no longer fit), so the renderers compute new ones. Returns the same mesh.
|
|
357
|
+
*/
|
|
358
|
+
export function displaceMesh<M extends Mesh>(mesh: M, fn: (v: Vec3, index: number) => Vec3): M;
|
|
359
|
+
|
|
360
|
+
export interface MergeOptions {
|
|
361
|
+
/** Faces of the i-th mesh use material i (default false: keep each mesh's faceMaterials) */
|
|
362
|
+
materialPerMesh?: boolean;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Joins meshes into a new one, keeping faces, edges, UVs, normals and materials.
|
|
367
|
+
* Scene objects in the list are merged where they stand (transform baked in).
|
|
368
|
+
*/
|
|
369
|
+
export function mergeMeshes(items: (Mesh | SceneObjectInput)[], opts?: MergeOptions): Mesh;
|
|
370
|
+
|
|
371
|
+
/** A box around some geometry. */
|
|
372
|
+
export interface Bounds {
|
|
373
|
+
min: Vec3;
|
|
374
|
+
max: Vec3;
|
|
375
|
+
center: Vec3;
|
|
376
|
+
size: Vec3;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* The box around a mesh, a scene object, a list of them or a Scene (objects measured
|
|
381
|
+
* where they stand). Null when there are no vertices.
|
|
382
|
+
*/
|
|
383
|
+
export function meshBounds(input: Mesh | SceneObjectInput | (Mesh | SceneObjectInput)[] | Scene): Bounds | null;
|
|
384
|
+
|
|
229
385
|
// ---------------------------------------------------------------------------
|
|
230
386
|
// Renderers
|
|
231
387
|
// ---------------------------------------------------------------------------
|
|
@@ -237,6 +393,9 @@ export const DEFAULT_AMBIENT: number;
|
|
|
237
393
|
/** Default far distance (WebGL renderer). */
|
|
238
394
|
export const DEFAULT_FAR: number;
|
|
239
395
|
|
|
396
|
+
/** An object's materials as a list, or null when it's a wireframe. */
|
|
397
|
+
export function materialsOf(obj: { material?: Material | Material[] }): Material[] | null;
|
|
398
|
+
|
|
240
399
|
export interface CanvasRendererOptions {
|
|
241
400
|
/**
|
|
242
401
|
* Split faces bigger than this fraction of their mesh's size (like 0.05)
|
|
@@ -255,6 +414,8 @@ export class CanvasRenderer implements Renderer {
|
|
|
255
414
|
export interface WebGLRendererOptions {
|
|
256
415
|
/** Smooth edges (default true) */
|
|
257
416
|
antialias?: boolean;
|
|
417
|
+
/** Free meshes and textures not drawn for this many frames (default 300, about 5 s). Infinity: never */
|
|
418
|
+
releaseAfter?: number;
|
|
258
419
|
}
|
|
259
420
|
|
|
260
421
|
/** Draws a scene with WebGL and a depth buffer. */
|
|
@@ -266,7 +427,13 @@ export class WebGLRenderer implements Renderer {
|
|
|
266
427
|
/** The hidden canvas WebGL draws on. */
|
|
267
428
|
canvas: HTMLCanvasElement;
|
|
268
429
|
gl: WebGLRenderingContext | WebGL2RenderingContext;
|
|
430
|
+
/** Frames a mesh or texture can go undrawn before it's freed (Infinity: never). */
|
|
431
|
+
releaseAfter: number;
|
|
432
|
+
/** What's on the graphics card right now. */
|
|
433
|
+
readonly memory: { meshes: number; buffers: number; textures: number };
|
|
269
434
|
render(scene: Scene): void;
|
|
435
|
+
/** Frees a mesh's buffers or a texture now; it's sent again if drawn again. */
|
|
436
|
+
release(item: Mesh | TextureSource): void;
|
|
270
437
|
/** Frees the graphics card memory. The renderer can't be used afterwards. */
|
|
271
438
|
dispose(): void;
|
|
272
439
|
}
|
|
@@ -394,6 +561,41 @@ export function uniformType(value: unknown): "float" | "vec2" | "vec3" | "vec4"
|
|
|
394
561
|
/** The GLSL declaration of `Surface`, shared by every effect. */
|
|
395
562
|
export const SURFACE_GLSL: string;
|
|
396
563
|
|
|
564
|
+
// ---------------------------------------------------------------------------
|
|
565
|
+
// Texture mapping
|
|
566
|
+
// ---------------------------------------------------------------------------
|
|
567
|
+
|
|
568
|
+
/** Texture coordinates for every face corner. */
|
|
569
|
+
export interface MeshUVs {
|
|
570
|
+
uvs: UV[];
|
|
571
|
+
faceUVs: number[][];
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/** The mapping types. */
|
|
575
|
+
export const MAPPINGS: readonly MappingType[];
|
|
576
|
+
|
|
577
|
+
/** Texture coordinates made from a mesh's shape. The mesh isn't changed. */
|
|
578
|
+
export function computeUVs(mesh: Mesh, mapping: Mapping): MeshUVs;
|
|
579
|
+
|
|
580
|
+
/** Replaces a mesh's texture coordinates with ones made from its shape, in place. */
|
|
581
|
+
export function mapUVs<M extends Mesh>(mesh: M, mapping: Mapping): M & MeshUVs;
|
|
582
|
+
|
|
583
|
+
/** The texture coordinates a renderer uses for a mesh and mapping (cached). */
|
|
584
|
+
export function uvsFor(mesh: Mesh, mapping?: Mapping): { uvs?: UV[]; faceUVs?: (number[] | null)[] };
|
|
585
|
+
|
|
586
|
+
/** A material's repeat, offset and rotation as [a, b, c, d, e, f], or null when they change nothing. */
|
|
587
|
+
export function uvTransform(material: Material): [number, number, number, number, number, number] | null;
|
|
588
|
+
|
|
589
|
+
/** Applies a `uvTransform` matrix to one texture coordinate. */
|
|
590
|
+
export function applyUVTransform(m: number[] | null, uv: UV): UV;
|
|
591
|
+
export function applyUVTransform(m: number[] | null, uv: UV | null): UV | null;
|
|
592
|
+
|
|
593
|
+
/** A mapping as `{ type, axis }`. Throws for an unknown type or axis. */
|
|
594
|
+
export function mappingOf(mapping?: Mapping): { type: MappingType; axis?: "x" | "y" | "z" };
|
|
595
|
+
|
|
596
|
+
/** A short string naming a mapping, for caches ("" for "uv"). */
|
|
597
|
+
export function mappingKey(mapping?: Mapping): string;
|
|
598
|
+
|
|
397
599
|
// ---------------------------------------------------------------------------
|
|
398
600
|
// Normals
|
|
399
601
|
// ---------------------------------------------------------------------------
|
|
@@ -417,12 +619,35 @@ export function newell(pts: Vec3[]): Vec3;
|
|
|
417
619
|
/** A mesh loaded from an OBJ file. Always has faces. */
|
|
418
620
|
export interface ObjMesh extends Mesh {
|
|
419
621
|
faces: number[][];
|
|
622
|
+
/** Material names from `usemtl` lines, in the order they first appear */
|
|
623
|
+
materialNames?: string[];
|
|
624
|
+
/** The .mtl file the OBJ names (`mtllib`) */
|
|
625
|
+
mtllib?: string;
|
|
626
|
+
/** With `loadOBJ(url, { materials: true })`: one material per `materialNames` entry, from the .mtl file */
|
|
627
|
+
materials?: Material[];
|
|
420
628
|
}
|
|
421
629
|
|
|
422
630
|
export interface ObjOptions {
|
|
423
631
|
/** Center the model and scale it so its largest side is this long */
|
|
424
632
|
fit?: number;
|
|
633
|
+
/** `loadOBJ` only: also load the .mtl file and its textures into `mesh.materials` (default false) */
|
|
634
|
+
materials?: boolean;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/** A material from an MTL file. */
|
|
638
|
+
export interface MtlMaterial {
|
|
639
|
+
name: string;
|
|
640
|
+
/** "#rrggbb" from `Kd`, or "rgba(...)" when see-through */
|
|
641
|
+
fill?: string;
|
|
642
|
+
/** From `d` / `Tr`, 0 to 1 */
|
|
643
|
+
opacity?: number;
|
|
644
|
+
/** The texture's file name (`map_Kd`), relative to the .mtl file */
|
|
645
|
+
textureFile?: string;
|
|
425
646
|
}
|
|
647
|
+
/** Parses the text of an MTL file: materials by name. */
|
|
648
|
+
export function parseMTL(text: string): Record<string, MtlMaterial>;
|
|
649
|
+
/** The materials of a parsed OBJ from its .mtl file (one per `materialNames` entry), textures loaded. */
|
|
650
|
+
export function loadMaterials(mesh: ObjMesh, base: URL | string): Promise<Material[]>;
|
|
426
651
|
|
|
427
652
|
/** Parses the text of an OBJ file. */
|
|
428
653
|
export function parseOBJ(text: string, opts?: ObjOptions): ObjMesh;
|
|
@@ -441,8 +666,118 @@ export function loadTexture(url: string): Promise<HTMLImageElement>;
|
|
|
441
666
|
export function textureReady(src: TextureSource | null | undefined): boolean;
|
|
442
667
|
/** Pixel size of a texture source. */
|
|
443
668
|
export function textureSize(src: TextureSource): { w: number; h: number };
|
|
444
|
-
/** Whether a
|
|
445
|
-
export function textureIsLive(src: TextureSource): boolean;
|
|
669
|
+
/** Whether a texture is read again every frame: videos, or any source whose material has `liveTexture: true`. */
|
|
670
|
+
export function textureIsLive(src: TextureSource, material?: { liveTexture?: boolean }): boolean;
|
|
671
|
+
/**
|
|
672
|
+
* Tells the renderers a texture changed (call it after drawing on a canvas used as a texture):
|
|
673
|
+
* it's read again once, on the next frame. Canvases are otherwise read only once.
|
|
674
|
+
*/
|
|
675
|
+
export function updateTexture(src: TextureSource): void;
|
|
676
|
+
/** How many times `updateTexture` was called for a source (0 when never). */
|
|
677
|
+
export function textureVersion(src: TextureSource): number;
|
|
678
|
+
|
|
679
|
+
// ---------------------------------------------------------------------------
|
|
680
|
+
// Exporting
|
|
681
|
+
// ---------------------------------------------------------------------------
|
|
682
|
+
|
|
683
|
+
export interface ExportOBJOptions {
|
|
684
|
+
/**
|
|
685
|
+
* Write texture coordinates (default true). For an object whose material has a
|
|
686
|
+
* `mapping` or texture repeat/offset/rotation, the coordinates it's drawn with are written.
|
|
687
|
+
*/
|
|
688
|
+
uvs?: boolean;
|
|
689
|
+
/** Write the mesh's normals when it has them (default true) */
|
|
690
|
+
normals?: boolean;
|
|
691
|
+
/** Write edges that aren't the side of a face as lines (default true) */
|
|
692
|
+
lines?: boolean;
|
|
693
|
+
/** Decimals kept in numbers (default 6) */
|
|
694
|
+
precision?: number;
|
|
695
|
+
/** Comment at the top of the file; "" for none (default "Exported by Trid") */
|
|
696
|
+
header?: string;
|
|
697
|
+
/** Link this .mtl file and name every material (the names `exportMTL` writes) */
|
|
698
|
+
mtllib?: string;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/** A material description for `exportMTL`. */
|
|
702
|
+
export interface MtlDescription {
|
|
703
|
+
name: string;
|
|
704
|
+
fill?: string;
|
|
705
|
+
opacity?: number;
|
|
706
|
+
/** Texture file name */
|
|
707
|
+
texture?: string;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/** The materials an export names, with each texture's file name. */
|
|
711
|
+
export function objMaterials(
|
|
712
|
+
input: OBJExportable | OBJExportable[] | Scene,
|
|
713
|
+
opts?: { textureFile?: (name: string, texture: TextureSource) => string },
|
|
714
|
+
): { name: string; material: Material | null; texture: TextureSource | null; file: string | null }[];
|
|
715
|
+
/** Writes an MTL file: for what `exportOBJ` takes (same names), or for plain descriptions. */
|
|
716
|
+
export function exportMTL(
|
|
717
|
+
input: OBJExportable | OBJExportable[] | Scene | MtlDescription[],
|
|
718
|
+
opts?: { textureFile?: (name: string, texture: TextureSource) => string; header?: string },
|
|
719
|
+
): string;
|
|
720
|
+
/** A texture image as a PNG (or other) file. */
|
|
721
|
+
export function textureToBlob(src: TextureSource, type?: string): Promise<Blob>;
|
|
722
|
+
/** Every file of a model: name.obj, name.mtl and one PNG per texture. */
|
|
723
|
+
export function exportModel(
|
|
724
|
+
input: OBJExportable | OBJExportable[] | Scene,
|
|
725
|
+
opts?: { name?: string; obj?: ExportOBJOptions },
|
|
726
|
+
): Promise<{ name: string; data: string | Blob }[]>;
|
|
727
|
+
|
|
728
|
+
/** Something exportOBJ can write: a mesh, or an object placed in a scene. */
|
|
729
|
+
export type OBJExportable = Mesh | (SceneObjectInput & Partial<Transform> & { name?: string });
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Writes meshes as the text of an OBJ file. Objects are written where they are
|
|
733
|
+
* in the scene; a list or a Scene gives one `o` per object.
|
|
734
|
+
*/
|
|
735
|
+
export function exportOBJ(input: OBJExportable | OBJExportable[] | Scene, opts?: ExportOBJOptions): string;
|
|
736
|
+
|
|
737
|
+
export interface ScreenshotOptions {
|
|
738
|
+
/** "image/png" (default), "image/jpeg" or "image/webp" */
|
|
739
|
+
type?: string;
|
|
740
|
+
/** For JPEG and WebP, from 0 to 1 (default 0.92) */
|
|
741
|
+
quality?: number;
|
|
742
|
+
/** Image width in pixels (default: the canvas's) */
|
|
743
|
+
width?: number;
|
|
744
|
+
/** Image height in pixels (default: the canvas's) */
|
|
745
|
+
height?: number;
|
|
746
|
+
/** Include what tools draw on top (default true) */
|
|
747
|
+
tools?: boolean;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
export interface RecordOptions {
|
|
751
|
+
/** Frames per second (default 60) */
|
|
752
|
+
fps?: number;
|
|
753
|
+
/** Video format, like "video/webm" (default: the best one the browser has) */
|
|
754
|
+
type?: string;
|
|
755
|
+
/** Quality: higher is sharper and bigger (default 8,000,000) */
|
|
756
|
+
bitsPerSecond?: number;
|
|
757
|
+
/** Stop by itself after this many seconds */
|
|
758
|
+
duration?: number;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/** A video being recorded. */
|
|
762
|
+
export interface Recording {
|
|
763
|
+
/** The video format being recorded */
|
|
764
|
+
readonly type: string;
|
|
765
|
+
/** Whether it's still recording */
|
|
766
|
+
readonly recording: boolean;
|
|
767
|
+
/** Resolves with the video once recording stops */
|
|
768
|
+
readonly done: Promise<Blob>;
|
|
769
|
+
/** Stops recording; resolves with the video */
|
|
770
|
+
stop(): Promise<Blob>;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/** Draws a new frame of a scene and returns it as an image file. */
|
|
774
|
+
export function screenshot(scene: Scene, opts?: ScreenshotOptions): Promise<Blob>;
|
|
775
|
+
|
|
776
|
+
/** Records a scene's canvas as a video. Throws if the browser can't. */
|
|
777
|
+
export function record(scene: Scene, opts?: RecordOptions): Recording;
|
|
778
|
+
|
|
779
|
+
/** Saves a file or text in the browser's downloads. */
|
|
780
|
+
export function download(data: Blob | string | Promise<Blob | string>, filename: string): Promise<void>;
|
|
446
781
|
|
|
447
782
|
// ---------------------------------------------------------------------------
|
|
448
783
|
// Tools
|
|
@@ -529,6 +864,12 @@ export interface OrbitCameraOptions {
|
|
|
529
864
|
pan?: boolean;
|
|
530
865
|
/** Allow zooming (default true) */
|
|
531
866
|
zoom?: boolean;
|
|
867
|
+
/** Turn around the target on its own, paused while dragging (default false) */
|
|
868
|
+
autoRotate?: boolean;
|
|
869
|
+
/** Auto-rotate speed in radians per second; negative turns the other way (default 0.5) */
|
|
870
|
+
autoRotateSpeed?: number;
|
|
871
|
+
/** Seconds to wait after a drag before auto-rotating again (default 0) */
|
|
872
|
+
autoRotateDelay?: number;
|
|
532
873
|
}
|
|
533
874
|
|
|
534
875
|
/** Mouse camera controls that turn around a target point. */
|
|
@@ -548,9 +889,14 @@ export class OrbitCamera implements Tool {
|
|
|
548
889
|
rotate: boolean;
|
|
549
890
|
pan: boolean;
|
|
550
891
|
zoom: boolean;
|
|
892
|
+
autoRotate: boolean;
|
|
893
|
+
autoRotateSpeed: number;
|
|
894
|
+
autoRotateDelay: number;
|
|
551
895
|
blockContextMenu: boolean;
|
|
552
896
|
/** Places the camera from the target, distance, yaw and pitch. */
|
|
553
897
|
apply(camera: Camera): void;
|
|
898
|
+
/** Restarts the auto-rotate wait, as if the user had just dragged (for tools that turn the camera). */
|
|
899
|
+
holdAutoRotate(): void;
|
|
554
900
|
attach(scene: Scene): void;
|
|
555
901
|
pointerDown(e: ToolPointerEvent): boolean;
|
|
556
902
|
pointerMove(e: ToolPointerEvent, scene: Scene): void;
|
|
@@ -589,6 +935,10 @@ export interface DragObjectOptions {
|
|
|
589
935
|
button?: number;
|
|
590
936
|
/** Which objects can be dragged (default: those without `draggable: false`) */
|
|
591
937
|
filter?: (obj: SceneObject) => boolean;
|
|
938
|
+
/** Pick by triangles instead of bounding boxes (default false, see `pickHit`) */
|
|
939
|
+
exact?: boolean;
|
|
940
|
+
/** Drag the top-level object (the whole group) of what was clicked (default false) */
|
|
941
|
+
root?: boolean;
|
|
592
942
|
/** Called when an object is picked */
|
|
593
943
|
onPick?: (obj: SceneObject) => void;
|
|
594
944
|
/** Called each time the object moves */
|
|
@@ -602,6 +952,8 @@ export class DragObject implements Tool {
|
|
|
602
952
|
constructor(opts?: DragObjectOptions);
|
|
603
953
|
button: number;
|
|
604
954
|
filter: (obj: SceneObject) => boolean;
|
|
955
|
+
exact: boolean;
|
|
956
|
+
root: boolean;
|
|
605
957
|
onPick?: (obj: SceneObject) => void;
|
|
606
958
|
onMove?: (obj: SceneObject) => void;
|
|
607
959
|
onDrop?: (obj: SceneObject) => void;
|
|
@@ -618,6 +970,8 @@ export interface HoverHighlightOptions {
|
|
|
618
970
|
color?: string;
|
|
619
971
|
/** Which objects can be highlighted (default: those without `hoverable: false`) */
|
|
620
972
|
filter?: (obj: SceneObject) => boolean;
|
|
973
|
+
/** Pick by triangles instead of bounding boxes (default false, see `pickHit`) */
|
|
974
|
+
exact?: boolean;
|
|
621
975
|
/** Called when the hovered object changes */
|
|
622
976
|
onChange?: (obj: SceneObject | null) => void;
|
|
623
977
|
}
|
|
@@ -627,6 +981,7 @@ export class HoverHighlight implements Tool {
|
|
|
627
981
|
constructor(opts?: HoverHighlightOptions);
|
|
628
982
|
color: string;
|
|
629
983
|
filter: (obj: SceneObject) => boolean;
|
|
984
|
+
exact: boolean;
|
|
630
985
|
onChange?: (obj: SceneObject | null) => void;
|
|
631
986
|
/** The object under the pointer, or null. */
|
|
632
987
|
hovered: SceneObject | null;
|
|
@@ -694,6 +1049,97 @@ export class ObjUploader implements Tool {
|
|
|
694
1049
|
draw(ctx: CanvasRenderingContext2D, scene: Scene): void;
|
|
695
1050
|
}
|
|
696
1051
|
|
|
1052
|
+
export interface ViewGizmoOptions {
|
|
1053
|
+
/** Camera controls to turn (default: the scene's first OrbitCamera). Without one, it only shows the axes */
|
|
1054
|
+
orbit?: OrbitCamera;
|
|
1055
|
+
/** Where it sits (default "top-right") */
|
|
1056
|
+
corner?: "top-right" | "top-left" | "bottom-right" | "bottom-left";
|
|
1057
|
+
/** Radius in CSS pixels (default 42) */
|
|
1058
|
+
size?: number;
|
|
1059
|
+
/** Distance from the canvas corner in CSS pixels (default 14) */
|
|
1060
|
+
margin?: number | { x: number; y: number };
|
|
1061
|
+
/** Seconds the camera takes to turn to a clicked axis (default 0.35) */
|
|
1062
|
+
duration?: number;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* The X, Y, Z axes in a corner, turning with the camera; click one to look along it.
|
|
1067
|
+
* Add it after the OrbitCamera.
|
|
1068
|
+
*/
|
|
1069
|
+
export class ViewGizmo implements Tool {
|
|
1070
|
+
constructor(opts?: ViewGizmoOptions);
|
|
1071
|
+
orbit: OrbitCamera | null;
|
|
1072
|
+
corner: "top-right" | "top-left" | "bottom-right" | "bottom-left";
|
|
1073
|
+
size: number;
|
|
1074
|
+
margin: { x: number; y: number };
|
|
1075
|
+
duration: number;
|
|
1076
|
+
/** Hide or show the gizmo without removing the tool. */
|
|
1077
|
+
visible: boolean;
|
|
1078
|
+
/** Whether a canvas pixel is on the gizmo (as last drawn). */
|
|
1079
|
+
contains(x: number, y: number): boolean;
|
|
1080
|
+
/** Turns the camera smoothly to look at its target from `dir` ({ x: 0, y: 1, z: 0 }: from above). */
|
|
1081
|
+
lookAlong(dir: Vec3): void;
|
|
1082
|
+
attach(scene: Scene): void;
|
|
1083
|
+
detach(): void;
|
|
1084
|
+
pointerDown(e: ToolPointerEvent): boolean;
|
|
1085
|
+
update(dt: number, scene: Scene): void;
|
|
1086
|
+
draw(ctx: CanvasRenderingContext2D, scene: Scene): void;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
export type TransformMode = "move" | "rotate" | "scale";
|
|
1090
|
+
|
|
1091
|
+
/** A move, rotate or scale in world space, as `TransformGizmo` reports it. */
|
|
1092
|
+
export type TransformOp =
|
|
1093
|
+
| { mode: "move"; delta: Vec3 }
|
|
1094
|
+
/** A right-handed turn of `angle` radians around the unit `axis`, about `center` */
|
|
1095
|
+
| { mode: "rotate"; axis: Vec3; angle: number; center: Vec3 }
|
|
1096
|
+
/** `factor` about `center`: uniform when `axis` is null, otherwise along that unit axis */
|
|
1097
|
+
| { mode: "scale"; axis: Vec3 | null; factor: number; center: Vec3 };
|
|
1098
|
+
|
|
1099
|
+
export interface TransformGizmoOptions {
|
|
1100
|
+
/** Default "move" */
|
|
1101
|
+
mode?: TransformMode;
|
|
1102
|
+
/** Objects it edits (default none) */
|
|
1103
|
+
targets?: SceneObject[];
|
|
1104
|
+
/** Handle length in CSS pixels (default 70) */
|
|
1105
|
+
size?: number;
|
|
1106
|
+
/** Change the targets' transforms while dragging (default true) */
|
|
1107
|
+
apply?: boolean;
|
|
1108
|
+
/** A handle was grabbed */
|
|
1109
|
+
onGrab?: (targets: SceneObject[]) => void;
|
|
1110
|
+
/** While dragging: the operation since the grab */
|
|
1111
|
+
onChange?: (op: TransformOp, targets: SceneObject[]) => void;
|
|
1112
|
+
/** On release: the whole operation */
|
|
1113
|
+
onDrop?: (op: TransformOp, targets: SceneObject[]) => void;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Move arrows, rotate rings or scale handles on one or more objects, around their
|
|
1118
|
+
* shared center. Add it after the camera tool.
|
|
1119
|
+
*/
|
|
1120
|
+
export class TransformGizmo implements Tool {
|
|
1121
|
+
constructor(opts?: TransformGizmoOptions);
|
|
1122
|
+
mode: TransformMode;
|
|
1123
|
+
targets: SceneObject[];
|
|
1124
|
+
size: number;
|
|
1125
|
+
apply: boolean;
|
|
1126
|
+
onGrab?: (targets: SceneObject[]) => void;
|
|
1127
|
+
onChange?: (op: TransformOp, targets: SceneObject[]) => void;
|
|
1128
|
+
onDrop?: (op: TransformOp, targets: SceneObject[]) => void;
|
|
1129
|
+
/** Hide the handles (and ignore clicks) without removing the tool. */
|
|
1130
|
+
visible: boolean;
|
|
1131
|
+
/** True while a handle is being dragged. */
|
|
1132
|
+
readonly dragging: boolean;
|
|
1133
|
+
/** Middle of the targets' bounding box in world space, or null. */
|
|
1134
|
+
center(): Vec3 | null;
|
|
1135
|
+
draw(ctx: CanvasRenderingContext2D, scene: Scene): void;
|
|
1136
|
+
pointerDown(e: ToolPointerEvent, scene: Scene): boolean;
|
|
1137
|
+
pointerMove(e: ToolPointerEvent, scene: Scene): void;
|
|
1138
|
+
pointerUp(): void;
|
|
1139
|
+
pointerLeave(scene: Scene): void;
|
|
1140
|
+
detach(scene: Scene): void;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
697
1143
|
export interface ScreenBox {
|
|
698
1144
|
minX: number;
|
|
699
1145
|
minY: number;
|
|
@@ -706,9 +1152,31 @@ export function pick(
|
|
|
706
1152
|
scene: Scene,
|
|
707
1153
|
x: number,
|
|
708
1154
|
y: number,
|
|
709
|
-
opts?: { filter?: (obj: SceneObject) => boolean; padding?: number },
|
|
1155
|
+
opts?: { filter?: (obj: SceneObject) => boolean; padding?: number; exact?: boolean },
|
|
710
1156
|
): SceneObject | null;
|
|
711
1157
|
|
|
1158
|
+
/** What `pickHit` found. */
|
|
1159
|
+
export interface PickHit {
|
|
1160
|
+
object: SceneObject;
|
|
1161
|
+
/** Index in `mesh.faces`, or -1 for a line of a wireframe */
|
|
1162
|
+
face: number;
|
|
1163
|
+
/** Distance in front of the camera */
|
|
1164
|
+
depth: number;
|
|
1165
|
+
/** The object, then its groups up to the top: `[part, group, ..., root]` */
|
|
1166
|
+
path: SceneObject[];
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* Exact picking: the nearest object whose triangles (or, without faces, lines
|
|
1171
|
+
* within `padding` pixels) are under a canvas pixel.
|
|
1172
|
+
*/
|
|
1173
|
+
export function pickHit(
|
|
1174
|
+
scene: Scene,
|
|
1175
|
+
x: number,
|
|
1176
|
+
y: number,
|
|
1177
|
+
opts?: { filter?: (obj: SceneObject) => boolean; padding?: number; objects?: SceneObject[] },
|
|
1178
|
+
): PickHit | null;
|
|
1179
|
+
|
|
712
1180
|
/** Screen-space bounding box of an object, or null if it's all behind the camera. */
|
|
713
1181
|
export function screenBounds(scene: Scene, obj: SceneObject): ScreenBox | null;
|
|
714
1182
|
|
|
@@ -742,9 +1210,13 @@ export function drawInstance(
|
|
|
742
1210
|
h: number,
|
|
743
1211
|
color: string,
|
|
744
1212
|
lineWidth?: number,
|
|
1213
|
+
/** World matrix to place it with (e.g. `obj.world` inside a group); default: its own transform */
|
|
1214
|
+
world?: Mat4,
|
|
745
1215
|
): void;
|
|
746
1216
|
/** Turns edge definitions into pairs of vertex indices. */
|
|
747
|
-
export function edgeSegments(edges
|
|
1217
|
+
export function edgeSegments(edges?: number[][]): Generator<[number, number]>;
|
|
1218
|
+
/** The lines a wireframe draws for a mesh: its `edges`, or its face outlines when it has none. */
|
|
1219
|
+
export function wireEdges(mesh: { edges?: number[][]; faces?: number[][] }): number[][];
|
|
748
1220
|
|
|
749
1221
|
/** Runs `update` every animation frame. Returns a function that stops it. */
|
|
750
1222
|
export function loop(update: (dt: number, time: number) => void, opts?: { maxDt?: number }): () => void;
|
|
@@ -781,3 +1253,145 @@ export function rotateXYZ(p: Vec3, rot: Vec3): Vec3;
|
|
|
781
1253
|
export function project(p: Vec3, fov?: number, aspect?: number): Vec2;
|
|
782
1254
|
/** Normalized coordinates to canvas pixels. */
|
|
783
1255
|
export function screen(p: Vec2, w: number, h: number): Vec2;
|
|
1256
|
+
|
|
1257
|
+
// ---------------------------------------------------------------------------
|
|
1258
|
+
// Rotations
|
|
1259
|
+
// ---------------------------------------------------------------------------
|
|
1260
|
+
|
|
1261
|
+
/** 3×3 matrix, row-major (m[row][col]), applied as M · v. */
|
|
1262
|
+
export type Mat3 = [[number, number, number], [number, number, number], [number, number, number]];
|
|
1263
|
+
|
|
1264
|
+
/** The matrix `rotateXYZ(p, rot)` applies. */
|
|
1265
|
+
export function matFromEuler(rot: Vec3): Mat3;
|
|
1266
|
+
/** Angles for `rotateXYZ` (an object's `rot`) from a rotation matrix; the inverse of `matFromEuler`. */
|
|
1267
|
+
export function eulerFromMat(m: Mat3): Vec3;
|
|
1268
|
+
/** A right-handed turn of `angle` radians around a unit `axis`. */
|
|
1269
|
+
export function matFromAxisAngle(axis: Vec3, angle: number): Mat3;
|
|
1270
|
+
/** Matrix product a · b (b is applied first). */
|
|
1271
|
+
export function mulMat(a: Mat3, b: Mat3): Mat3;
|
|
1272
|
+
/** m · v */
|
|
1273
|
+
export function mulVec(m: Mat3, v: Vec3): Vec3;
|
|
1274
|
+
/** Applies a world-space move / rotate / scale to a transform and returns the new one. */
|
|
1275
|
+
export function applyTransformOp(t: Transform, op: TransformOp): Transform;
|
|
1276
|
+
|
|
1277
|
+
// ---------------------------------------------------------------------------
|
|
1278
|
+
// Procedural textures
|
|
1279
|
+
// ---------------------------------------------------------------------------
|
|
1280
|
+
|
|
1281
|
+
export type TextureStyle = "noise" | "marble" | "wood" | "bricks" | "checker" | "bark" | "spots" | "stripes" | "solid";
|
|
1282
|
+
/** The built-in styles of `makeTexture`. */
|
|
1283
|
+
export const TEXTURE_STYLES: TextureStyle[];
|
|
1284
|
+
|
|
1285
|
+
export interface MakeTextureOptions {
|
|
1286
|
+
/** Width and height in pixels (default 256) */
|
|
1287
|
+
size?: number;
|
|
1288
|
+
/** [first, second]: hex, rgb() / rgba(), CSS names or [r, g, b, a?] (default: suits the style) */
|
|
1289
|
+
colors?: (string | number[])[];
|
|
1290
|
+
/** How many times the pattern repeats across, a whole number (default 4) */
|
|
1291
|
+
scale?: number;
|
|
1292
|
+
/** Another whole number gives another texture of the same style (default 0) */
|
|
1293
|
+
seed?: number;
|
|
1294
|
+
/** Fine speckles on top, 0 to 1 (default 0) */
|
|
1295
|
+
grain?: number;
|
|
1296
|
+
/** Paint into this canvas instead of a new one (calls `updateTexture` for you) */
|
|
1297
|
+
canvas?: HTMLCanvasElement | OffscreenCanvas;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* Paints a seamless procedural texture on a canvas. `style` is a built-in style, or
|
|
1302
|
+
* `(u, v) => t` (0: first color, 1: second).
|
|
1303
|
+
*/
|
|
1304
|
+
export function makeTexture(
|
|
1305
|
+
style?: TextureStyle | ((u: number, v: number) => number),
|
|
1306
|
+
opts?: MakeTextureOptions,
|
|
1307
|
+
): HTMLCanvasElement | OffscreenCanvas;
|
|
1308
|
+
/** The pixels of a procedural texture (RGBA, top row first), without a canvas. */
|
|
1309
|
+
export function texturePixels(
|
|
1310
|
+
style?: TextureStyle | ((u: number, v: number) => number),
|
|
1311
|
+
opts?: Omit<MakeTextureOptions, "canvas">,
|
|
1312
|
+
): { width: number; height: number; data: Uint8ClampedArray };
|
|
1313
|
+
/** [r, g, b, a] (0..255, a 0..1) from a color string or array. */
|
|
1314
|
+
export function colorBytes(color: string | number[]): [number, number, number, number];
|
|
1315
|
+
|
|
1316
|
+
// ---------------------------------------------------------------------------
|
|
1317
|
+
// Groups (scene graph)
|
|
1318
|
+
// ---------------------------------------------------------------------------
|
|
1319
|
+
|
|
1320
|
+
/**
|
|
1321
|
+
* Every visible object of a scene (or of objects and their subtrees), parents first,
|
|
1322
|
+
* with `parent` and `world` set. Groups without a mesh are included.
|
|
1323
|
+
*/
|
|
1324
|
+
export function worldObjects(input: Scene | SceneObjectInput | SceneObjectInput[]): SceneObject[];
|
|
1325
|
+
/** An object's world matrix right now, from its transform and its parents'. */
|
|
1326
|
+
export function worldMatrix(obj: SceneObjectInput): Mat4;
|
|
1327
|
+
/** Where an object's origin is in the world right now. */
|
|
1328
|
+
export function worldPosition(obj: SceneObjectInput): Vec3;
|
|
1329
|
+
/** The chain from an object up to the top: `[obj, parent, ..., root]`. */
|
|
1330
|
+
export function ancestors(obj: SceneObject): SceneObject[];
|
|
1331
|
+
/**
|
|
1332
|
+
* Calls `fn(obj, world, parent)` for every visible object under some roots, parents first,
|
|
1333
|
+
* without changing anything. `baseOf(root)` is the matrix a root goes under (null: none).
|
|
1334
|
+
*/
|
|
1335
|
+
export function forEachPlaced(
|
|
1336
|
+
roots: SceneObjectInput[],
|
|
1337
|
+
baseOf: (root: SceneObjectInput) => Mat4 | null,
|
|
1338
|
+
fn: (obj: SceneObjectInput, world: Mat4, parent: SceneObjectInput | null) => void,
|
|
1339
|
+
): void;
|
|
1340
|
+
|
|
1341
|
+
// ---------------------------------------------------------------------------
|
|
1342
|
+
// Matrices
|
|
1343
|
+
// ---------------------------------------------------------------------------
|
|
1344
|
+
|
|
1345
|
+
/** 4×4 transform matrix, 16 numbers in column-major order (`m[col * 4 + row]`), like WebGL. */
|
|
1346
|
+
export type Mat4 = number[];
|
|
1347
|
+
|
|
1348
|
+
/** The identity matrix. */
|
|
1349
|
+
export function identityMat4(): Mat4;
|
|
1350
|
+
/** The matrix of a transform: scale, rotate X → Y → Z, then move. */
|
|
1351
|
+
export function mat4FromTransform(t: MeshTransform): Mat4;
|
|
1352
|
+
/** a · b (b applied first): a child's world matrix is `mulMat4(parentWorld, childLocal)`. */
|
|
1353
|
+
export function mulMat4(a: Mat4, b: Mat4): Mat4;
|
|
1354
|
+
/** Inverse of a transform matrix (identity if it flattens space). */
|
|
1355
|
+
export function invertMat4(m: Mat4): Mat4;
|
|
1356
|
+
/** Determinant of the 3×3 part: < 0 when the matrix mirrors. */
|
|
1357
|
+
export function determinantMat4(m: Mat4): number;
|
|
1358
|
+
/** A point through a matrix. */
|
|
1359
|
+
export function transformPoint(m: Mat4, p: Vec3): Vec3;
|
|
1360
|
+
/** A direction or offset through a matrix (not moved). */
|
|
1361
|
+
export function transformDirection(m: Mat4, v: Vec3): Vec3;
|
|
1362
|
+
/** The 3×3 normal matrix (inverse transpose), column-major. */
|
|
1363
|
+
export function normalMatrix(m: Mat4): number[];
|
|
1364
|
+
/** A normal through a normal matrix, unit length. */
|
|
1365
|
+
export function transformNormal(nm: number[], n: Vec3): Vec3;
|
|
1366
|
+
/** A world-space `TransformOp` in a parent's space, for objects inside groups. */
|
|
1367
|
+
export function transformOpToLocal(op: TransformOp, parentWorld: Mat4): TransformOp;
|
|
1368
|
+
|
|
1369
|
+
// ---------------------------------------------------------------------------
|
|
1370
|
+
// Random numbers and noise
|
|
1371
|
+
// ---------------------------------------------------------------------------
|
|
1372
|
+
|
|
1373
|
+
/** A seeded random generator (mulberry32): each call returns the next number in [0, 1). */
|
|
1374
|
+
export function rng(seed?: number): () => number;
|
|
1375
|
+
|
|
1376
|
+
export interface NoiseOptions {
|
|
1377
|
+
/** Whole number; another seed gives other noise (default 0) */
|
|
1378
|
+
seed?: number;
|
|
1379
|
+
/** Repeat every this many units, a whole number, for seamless textures (default 0: never) */
|
|
1380
|
+
period?: number;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
export interface FbmOptions extends NoiseOptions {
|
|
1384
|
+
/** Layers of detail (default 5) */
|
|
1385
|
+
octaves?: number;
|
|
1386
|
+
/** Strength of each layer compared to the one before (default 0.5) */
|
|
1387
|
+
gain?: number;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/** Smooth 2D value noise in [0, 1). */
|
|
1391
|
+
export function noise2(x: number, y: number, opts?: NoiseOptions): number;
|
|
1392
|
+
/** Smooth 3D value noise in [0, 1). */
|
|
1393
|
+
export function noise3(x: number, y: number, z: number, opts?: NoiseOptions): number;
|
|
1394
|
+
/** Fractal 2D noise: octaves of noise2, each twice as fine. About [0, 1), averaging 0.5. */
|
|
1395
|
+
export function fbm2(x: number, y: number, opts?: FbmOptions): number;
|
|
1396
|
+
/** Fractal 3D noise: octaves of noise3, each twice as fine. About [0, 1), averaging 0.5. */
|
|
1397
|
+
export function fbm3(x: number, y: number, z: number, opts?: FbmOptions): number;
|