trid3d 0.3.0 → 0.4.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 +43 -15
- package/package.json +1 -1
- package/trid/index.d.ts +247 -10
- package/trid/index.js +8 -1
- package/trid/render/canvasRenderer.js +99 -48
- package/trid/render/effects.js +16 -9
- package/trid/render/grid.js +177 -0
- package/trid/render/lights.js +162 -0
- package/trid/render/post.js +325 -0
- package/trid/render/webglRenderer.js +341 -19
- package/trid/scene.js +48 -6
- package/trid/tools/helpers.js +107 -9
- package/trid/tools/index.js +1 -1
- package/trid/tools/transformGizmo.js +40 -6
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
Trid gives you a scene, a camera, shapes, model loading and mouse/keyboard tools, all in plain ES modules you can drop next to your page.
|
|
12
12
|
|
|
13
|
-
> **Status:** early.
|
|
13
|
+
> **Status:** early (0.x): the API can still change between minor versions. See [Upgrading](#upgrading).
|
|
14
14
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
@@ -18,15 +18,17 @@ Trid gives you a scene, a camera, shapes, model loading and mouse/keyboard tools
|
|
|
18
18
|
- **Groups** — give any object `children` and they move, turn and scale with it (models made of parts, a moon orbiting a planet).
|
|
19
19
|
- **Shapes** — cubes, boxes, spheres, cylinders, cones, tori and planes built in, `lathe` for round shapes and `extrude` for flat ones, or any mesh you define as vertices and edges.
|
|
20
20
|
- **Mesh helpers** — clone, transform, displace, merge and measure meshes; seeded random numbers and smooth noise (`fbm2`, `fbm3`, tileable) for rocks, terrain and procedural textures.
|
|
21
|
-
- **Filled faces** — give an object a `material` to fill and shade its faces, flat or smooth
|
|
21
|
+
- **Filled faces** — give an object a `material` to fill and shade its faces, flat or smooth.
|
|
22
|
+
- **Lights** — ambient, directional and point lights, with colors and intensities, as many as you need (up to 8 at once besides ambient).
|
|
22
23
|
- **Textures** — images, canvases or videos on faces, with texture coordinates from built-in shapes and OBJ files, or made from the shape (planar, box, sphere and cylinder mapping). Repeat, offset and rotate them, or give each face its own material. Or paint one in code: wood, marble, bricks and more, all seamless.
|
|
23
24
|
- **Effects** — stack shader effects like toon, rim and edge glow, gradients and fog on a material, or write your own in GLSL.
|
|
25
|
+
- **Post effects** — bloom, vignette, color grading and film grain over the whole picture, or your own full-screen shaders (several passes if needed).
|
|
24
26
|
- **Two renderers** — the canvas 2D context by default, or `WebGLRenderer` for exact depth and big models, with the same scene code.
|
|
25
27
|
- **OBJ files** — load models from a URL (with their `.mtl` colors and textures), or let users drop their own `.obj` files on the canvas.
|
|
26
28
|
- **Export** — `scene.screenshot()` and `scene.record()` save images and videos of the canvas; `exportOBJ` / `exportModel` write meshes, objects or whole scenes as OBJ files with their MTL materials and textures.
|
|
27
29
|
- **Camera** — position, yaw, pitch and field of view, with near-plane clipping.
|
|
28
|
-
- **Tools** — orbit and fly cameras, object dragging, hover highlight, a move / rotate / scale gizmo, a view axes gizmo, an FPS meter and an OBJ uploader, one line each. Exact picking by triangles. Writing your own is a plain object with a few methods.
|
|
29
|
-
- **Pure math** — every transform and projection step is exported, so you can use the pipeline piece by piece.
|
|
30
|
+
- **Tools** — orbit and fly cameras, object dragging, hover highlight, a move / rotate / scale gizmo (with a pivot of your choice), a view axes gizmo, a floor grid, an FPS meter and an OBJ uploader, one line each. Exact picking by triangles, with the hit point and texture coordinates under the mouse. Writing your own is a plain object with a few methods.
|
|
31
|
+
- **Pure math** — every transform and projection step is exported, plus 4×4 matrices and rotations, so you can use the pipeline piece by piece.
|
|
30
32
|
|
|
31
33
|
## Install
|
|
32
34
|
|
|
@@ -38,7 +40,7 @@ No bundler? Use the CDN with an import map, or copy the `trid/` folder next to y
|
|
|
38
40
|
|
|
39
41
|
```html
|
|
40
42
|
<script type="importmap">
|
|
41
|
-
{ "imports": { "trid3d": "https://cdn.jsdelivr.net/npm/trid3d@0.
|
|
43
|
+
{ "imports": { "trid3d": "https://cdn.jsdelivr.net/npm/trid3d@0.3/trid/index.js" } }
|
|
42
44
|
</script>
|
|
43
45
|
```
|
|
44
46
|
|
|
@@ -69,8 +71,8 @@ Without a bundler, serve the folder (`python3 -m http.server`) instead of openin
|
|
|
69
71
|
```js
|
|
70
72
|
import { loadOBJ } from "trid3d";
|
|
71
73
|
|
|
72
|
-
const mesh = await loadOBJ("models/teapot.obj", { fit: 1 }); // centered, 1 unit wide
|
|
73
|
-
scene.add({ mesh });
|
|
74
|
+
const mesh = await loadOBJ("models/teapot.obj", { fit: 1, materials: true }); // centered, 1 unit wide
|
|
75
|
+
scene.add({ mesh, material: mesh.materials }); // colors and textures from its .mtl file
|
|
74
76
|
```
|
|
75
77
|
|
|
76
78
|
Or let users load their own: `scene.use(new ObjUploader())` accepts dropped `.obj` files, and `uploader.open()` shows a file dialog.
|
|
@@ -81,12 +83,14 @@ Or let users load their own: `scene.use(new ObjUploader())` accepts dropped `.ob
|
|
|
81
83
|
| --- | --- |
|
|
82
84
|
| `trid/index.js` | Entry file: exports everything (`"trid3d"`) |
|
|
83
85
|
| `trid/scene.js` | The `Scene` class |
|
|
84
|
-
| `trid/
|
|
85
|
-
| `trid/
|
|
86
|
-
| `trid/
|
|
87
|
-
| `trid/
|
|
88
|
-
| `trid/
|
|
86
|
+
| `trid/sceneGraph.js` | Groups: `children`, world matrices |
|
|
87
|
+
| `trid/math/` | Transforms, camera directions, projection, matrices, rotations, random numbers and noise |
|
|
88
|
+
| `trid/render/` | Renderers (Canvas 2D, WebGL), lights, effects, post effects, shapes, grids, mesh helpers, procedural textures, drawing, frame loop |
|
|
89
|
+
| `trid/loaders/` | OBJ, MTL and texture loading |
|
|
90
|
+
| `trid/export/` | Screenshots, video recording, OBJ and MTL export |
|
|
91
|
+
| `trid/tools/` | Camera, object, gizmo and overlay tools |
|
|
89
92
|
| `docs/` | Documentation site with live demos |
|
|
93
|
+
| `test/` | Tests (`npm test`) |
|
|
90
94
|
|
|
91
95
|
## Documentation
|
|
92
96
|
|
|
@@ -101,11 +105,35 @@ npm run docs:dev
|
|
|
101
105
|
|
|
102
106
|
See [`docs/README.md`](https://github.com/ZachR622/Trid/blob/master/docs/README.md) for building and editing the docs.
|
|
103
107
|
|
|
108
|
+
## Tests
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npm test
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Uses Node's built-in test runner (Node 21+), so there's nothing to install. The tests cover shapes, mesh helpers, noise, textures, OBJ / MTL, picking, tools, groups and matrices, lights, post effects, grids, and the WebGL renderer's GPU memory on a fake WebGL context.
|
|
115
|
+
|
|
116
|
+
## Upgrading
|
|
117
|
+
|
|
118
|
+
### From 0.3 to 0.4
|
|
119
|
+
|
|
120
|
+
- **Lights are a list**: `scene.lights`. A scene still starts with one directional light and an ambient level, and looks the same. `scene.light` and `scene.ambient` are now shortcuts for the first directional light's direction and the first ambient light's intensity.
|
|
121
|
+
- Setting `scene.ambient` after the scene is made no longer dims the directional light (it used to be `1 - ambient` all the time; now that's only how the default lights start). To keep the old look, also set `scene.lights[1].intensity = 1 - ambient`.
|
|
122
|
+
- `scene.light` is `null` for a scene whose `lights` have no directional light.
|
|
123
|
+
- Effects get `s.lightColor`, and `toon` and `gradient` are tinted by colored lights (no change with white lights).
|
|
124
|
+
|
|
125
|
+
### From 0.2 to 0.3
|
|
126
|
+
|
|
127
|
+
- **Canvas textures are read once.** A canvas used as a `texture` is now uploaded once (faster, and sharper with mipmaps). If you draw on it again, call `updateTexture(canvas)` after drawing, or give its material `liveTexture: true` to read it every frame. Videos still play on their own. See [Changing a canvas](https://zachr622.github.io/Trid/textures#changing-a-canvas).
|
|
128
|
+
- **The WebGL renderer frees unused GPU memory**: meshes and textures not drawn for 300 frames are freed (and sent again if they come back). Set `new WebGLRenderer({ releaseAfter: Infinity })` to keep the old behavior.
|
|
129
|
+
- **Objects can have `children`**, and `mesh` is optional for a group. Code that walks `scene.objects` only sees the top level; use `worldObjects(scene)` to include children.
|
|
130
|
+
- `parseOBJ` now sets `materialNames` / `faceMaterials` for a file with a single material too.
|
|
131
|
+
|
|
104
132
|
## Roadmap
|
|
105
133
|
|
|
106
134
|
Roughly in order:
|
|
107
135
|
|
|
108
136
|
- **More import and export formats** — STL; basic glTF later
|
|
109
|
-
- **More tools** — a selection outline
|
|
110
|
-
- **
|
|
111
|
-
- **More tests** —
|
|
137
|
+
- **More tools** — a selection outline
|
|
138
|
+
- **More post effects** — outlines (from depth), antialiasing (FXAA)
|
|
139
|
+
- **More tests** — the canvas renderer's drawing and the remaining math functions
|
package/package.json
CHANGED
package/trid/index.d.ts
CHANGED
|
@@ -91,6 +91,8 @@ export type TextureSource = CanvasImageSource;
|
|
|
91
91
|
|
|
92
92
|
/** How an object's faces look. Objects without one are drawn as wireframes. */
|
|
93
93
|
export interface Material {
|
|
94
|
+
/** A name: `exportOBJ` / `exportMTL` write it as the material's name (`usemtl` / `newmtl`) */
|
|
95
|
+
name?: string;
|
|
94
96
|
/** Face color, any CSS color (default: the scene's color, or white with a texture) */
|
|
95
97
|
fill?: string;
|
|
96
98
|
/** Darken faces that turn away from the light (default true) */
|
|
@@ -160,6 +162,8 @@ export interface SceneObjectInput {
|
|
|
160
162
|
draggable?: boolean;
|
|
161
163
|
/** Set to false to make `HoverHighlight` ignore this object */
|
|
162
164
|
hoverable?: boolean;
|
|
165
|
+
/** Set to false so `pick` / `pickHit` never find this object or its children (helpers like a grid) */
|
|
166
|
+
pickable?: boolean;
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
/**
|
|
@@ -196,10 +200,17 @@ export interface SceneOptions {
|
|
|
196
200
|
lineWidth?: number;
|
|
197
201
|
/** Camera (default { z: -1 }) */
|
|
198
202
|
camera?: Camera;
|
|
199
|
-
/** Direction light comes from (default: above, left and in front) */
|
|
203
|
+
/** Direction light comes from (default: above, left and in front). Ignored when `lights` is given */
|
|
200
204
|
light?: Vec3;
|
|
201
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* Brightness of faces turned away from the light, 0..1 (default 0.25).
|
|
207
|
+
* The directional light gets `1 - ambient`. Ignored when `lights` is given
|
|
208
|
+
*/
|
|
202
209
|
ambient?: number;
|
|
210
|
+
/** Every light, instead of `light` and `ambient` */
|
|
211
|
+
lights?: Light[];
|
|
212
|
+
/** Post effects run on the picture, in order (default none) */
|
|
213
|
+
post?: PostEffect[];
|
|
203
214
|
/** What draws the scene (default: a new CanvasRenderer) */
|
|
204
215
|
renderer?: Renderer;
|
|
205
216
|
}
|
|
@@ -214,7 +225,19 @@ export class Scene {
|
|
|
214
225
|
color: string;
|
|
215
226
|
lineWidth: number;
|
|
216
227
|
camera: Camera;
|
|
217
|
-
light
|
|
228
|
+
/** Every light. Edit it freely; it's read every frame */
|
|
229
|
+
lights: Light[];
|
|
230
|
+
/** Post effects, run in order on the picture before tools draw */
|
|
231
|
+
post: PostEffect[];
|
|
232
|
+
/**
|
|
233
|
+
* Shortcut for the first directional light's direction (null if there's none).
|
|
234
|
+
* Setting it when there's none adds one.
|
|
235
|
+
*/
|
|
236
|
+
light: Vec3 | null;
|
|
237
|
+
/**
|
|
238
|
+
* Shortcut for the first ambient light's intensity (0 if there's none).
|
|
239
|
+
* Setting it when there's none adds one; the directional light keeps its intensity.
|
|
240
|
+
*/
|
|
218
241
|
ambient: number;
|
|
219
242
|
renderer: Renderer;
|
|
220
243
|
objects: SceneObject[];
|
|
@@ -382,6 +405,106 @@ export interface Bounds {
|
|
|
382
405
|
*/
|
|
383
406
|
export function meshBounds(input: Mesh | SceneObjectInput | (Mesh | SceneObjectInput)[] | Scene): Bounds | null;
|
|
384
407
|
|
|
408
|
+
export type GridPlane = "xz" | "xy" | "yz";
|
|
409
|
+
|
|
410
|
+
/** A square grid of lines centered on the origin, as a line-only mesh. */
|
|
411
|
+
export function gridMesh(opts?: { size?: number; divisions?: number; plane?: GridPlane }): Mesh;
|
|
412
|
+
|
|
413
|
+
export interface GridHelperOptions {
|
|
414
|
+
/** Width of the whole grid (default 4) */
|
|
415
|
+
size?: number;
|
|
416
|
+
/** Cells along each side (default 40) */
|
|
417
|
+
divisions?: number;
|
|
418
|
+
/** A major line every this many cells, 0 for none (default 10) */
|
|
419
|
+
major?: number;
|
|
420
|
+
/** The plane it lies in (default "xz", a floor) */
|
|
421
|
+
plane?: GridPlane;
|
|
422
|
+
/** Minor lines (default "rgba(255, 255, 255, 0.12)") */
|
|
423
|
+
color?: string;
|
|
424
|
+
/** Major lines (default "rgba(255, 255, 255, 0.25)") */
|
|
425
|
+
majorColor?: string;
|
|
426
|
+
/** Draw the axes through the origin (default true), or their colors like `{ x: "#f00" }` */
|
|
427
|
+
axes?: boolean | { x?: string; y?: string; z?: string };
|
|
428
|
+
/** Fade toward the edge (default true); a number is where the fade starts (0 = center, 1 = edge) */
|
|
429
|
+
fade?: boolean | number;
|
|
430
|
+
/** Line width in pixels (default 1) */
|
|
431
|
+
lineWidth?: number;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** A floor grid with major lines, colored axes and a fade: a group to `scene.add`, never picked. */
|
|
435
|
+
export function gridHelper(opts?: GridHelperOptions): SceneObjectInput & { pickable: false; children: SceneObjectInput[] };
|
|
436
|
+
|
|
437
|
+
// ---------------------------------------------------------------------------
|
|
438
|
+
// Lights
|
|
439
|
+
// ---------------------------------------------------------------------------
|
|
440
|
+
|
|
441
|
+
/** Light from everywhere: lights every side of every face the same. */
|
|
442
|
+
export interface AmbientLight {
|
|
443
|
+
type: "ambient";
|
|
444
|
+
/** Any CSS color (default white) */
|
|
445
|
+
color?: string;
|
|
446
|
+
/** Multiplies the color (default 1) */
|
|
447
|
+
intensity?: number;
|
|
448
|
+
/** Set to false to turn it off without removing it */
|
|
449
|
+
enabled?: boolean;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/** Light from far away in one direction, like the sun. */
|
|
453
|
+
export interface DirectionalLight {
|
|
454
|
+
type: "directional";
|
|
455
|
+
/** Direction light comes from (any length) */
|
|
456
|
+
direction: Vec3;
|
|
457
|
+
color?: string;
|
|
458
|
+
intensity?: number;
|
|
459
|
+
enabled?: boolean;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** Light from a point, like a bulb. */
|
|
463
|
+
export interface PointLight {
|
|
464
|
+
type: "point";
|
|
465
|
+
/** World position */
|
|
466
|
+
position: Vec3;
|
|
467
|
+
color?: string;
|
|
468
|
+
intensity?: number;
|
|
469
|
+
/** Fades out smoothly and reaches nothing past this distance (default: no fading) */
|
|
470
|
+
range?: number;
|
|
471
|
+
enabled?: boolean;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export type Light = AmbientLight | DirectionalLight | PointLight;
|
|
475
|
+
|
|
476
|
+
/** Most directional + point lights the renderers use; extra ones are ignored. */
|
|
477
|
+
export const MAX_LIGHTS: number;
|
|
478
|
+
|
|
479
|
+
/** The default lights: ambient at `ambient`, white directional from `direction` at `1 - ambient`. */
|
|
480
|
+
export function defaultLights(direction?: Vec3, ambient?: number): Light[];
|
|
481
|
+
|
|
482
|
+
/** A scene's lights ready for shading (used by the renderers). */
|
|
483
|
+
export interface SceneLights {
|
|
484
|
+
/** Summed ambient color [r, g, b] */
|
|
485
|
+
ambient: [number, number, number];
|
|
486
|
+
/** Brightest channel of `ambient` */
|
|
487
|
+
ambientLevel: number;
|
|
488
|
+
lights: { point: boolean; dir: Vec3 | null; pos: Vec3 | null; color: [number, number, number]; range: number }[];
|
|
489
|
+
/** Unit direction of the first directional light */
|
|
490
|
+
mainDir: Vec3;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** A scene's lights, colors parsed and multiplied by intensity, directions unit length. */
|
|
494
|
+
export function sceneLights(
|
|
495
|
+
scene: { lights?: Light[]; light?: Vec3 | null; ambient?: number },
|
|
496
|
+
rgba: (css: string) => number[],
|
|
497
|
+
): SceneLights;
|
|
498
|
+
|
|
499
|
+
/** The light reaching a point, [r, g, b] (can go above 1). */
|
|
500
|
+
export function lightAt(lights: SceneLights, normal: Vec3, position: Vec3): [number, number, number];
|
|
501
|
+
|
|
502
|
+
/** Brightness (brightest channel) and diffuse share (0..1) of a light color. */
|
|
503
|
+
export function lightLevels(color: number[], ambientLevel: number): { light: number; diffuse: number };
|
|
504
|
+
|
|
505
|
+
/** How much of a point light reaches `dist` away (1 up close, 0 at `range`; range 0 = no fading). */
|
|
506
|
+
export function rangeFade(dist: number, range: number): number;
|
|
507
|
+
|
|
385
508
|
// ---------------------------------------------------------------------------
|
|
386
509
|
// Renderers
|
|
387
510
|
// ---------------------------------------------------------------------------
|
|
@@ -462,13 +585,15 @@ export interface Surface {
|
|
|
462
585
|
local: Vec3;
|
|
463
586
|
/** Unit direction from the point to the camera */
|
|
464
587
|
view: Vec3;
|
|
465
|
-
/** Unit direction light comes from */
|
|
588
|
+
/** Unit direction the scene's first directional light comes from */
|
|
466
589
|
lightDir: Vec3;
|
|
467
|
-
/** How much the
|
|
590
|
+
/** How much of the light comes from the lights rather than the ambient, 0..1 (one light: how much the point faces it) */
|
|
468
591
|
diffuse: number;
|
|
469
|
-
/** Brightness Trid used: ambient + (1 - ambient) × diffuse */
|
|
592
|
+
/** Brightness Trid used (brightest channel of `lightColor`): ambient + (1 - ambient) × diffuse with the default lights */
|
|
470
593
|
light: number;
|
|
471
|
-
/** The
|
|
594
|
+
/** The light reaching the point, [r, g, b] (every light added up; can go above 1). Trid's color is `base × lightColor` */
|
|
595
|
+
lightColor: [number, number, number];
|
|
596
|
+
/** The scene's ambient level (brightest channel) */
|
|
472
597
|
ambient: number;
|
|
473
598
|
/** Distance to the camera */
|
|
474
599
|
depth: number;
|
|
@@ -561,6 +686,89 @@ export function uniformType(value: unknown): "float" | "vec2" | "vec3" | "vec4"
|
|
|
561
686
|
/** The GLSL declaration of `Surface`, shared by every effect. */
|
|
562
687
|
export const SURFACE_GLSL: string;
|
|
563
688
|
|
|
689
|
+
// ---------------------------------------------------------------------------
|
|
690
|
+
// Post effects
|
|
691
|
+
// ---------------------------------------------------------------------------
|
|
692
|
+
|
|
693
|
+
/** What a post effect's `canvas` function knows about the picture. */
|
|
694
|
+
export interface PostFrame {
|
|
695
|
+
width: number;
|
|
696
|
+
height: number;
|
|
697
|
+
/** Seconds since the renderer started */
|
|
698
|
+
time: number;
|
|
699
|
+
/** The scene's background color */
|
|
700
|
+
background: RGBA;
|
|
701
|
+
/** The canvas being changed */
|
|
702
|
+
canvas: HTMLCanvasElement;
|
|
703
|
+
/** Turns a uniform value (CSS color, array) into RGBA 0..1 */
|
|
704
|
+
rgba(value: UniformValue): RGBA;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/** One pass of a post effect. */
|
|
708
|
+
export interface PostPass {
|
|
709
|
+
/** GLSL defining `vec4 post(vec4 color, Frame f)` */
|
|
710
|
+
glsl: string;
|
|
711
|
+
/** Size of this pass's picture, relative to the canvas (default 1) */
|
|
712
|
+
scale?: number;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/** A shader run on the whole picture after the scene is drawn. */
|
|
716
|
+
export interface PostEffect<U extends Record<string, UniformValue> = Record<string, UniformValue>> {
|
|
717
|
+
name?: string;
|
|
718
|
+
/** GLSL defining `vec4 post(vec4 color, Frame f)`: one pass (WebGL renderer) */
|
|
719
|
+
glsl?: string;
|
|
720
|
+
/** Instead of `glsl`: passes run in order (each can read the last with `frame(uv)`, the start with `source(uv)`) */
|
|
721
|
+
passes?: PostPass[];
|
|
722
|
+
/** Changes the 2D canvas directly: used by the canvas renderer (and by WebGL for effects without GLSL) */
|
|
723
|
+
canvas?(ctx: CanvasRenderingContext2D, frame: PostFrame, uniforms: U): void;
|
|
724
|
+
/** Settings read every frame */
|
|
725
|
+
uniforms?: U;
|
|
726
|
+
/** Set to false to turn it off without removing it */
|
|
727
|
+
enabled?: boolean;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/** Darkens the corners of the picture. */
|
|
731
|
+
export function vignette(opts?: { strength?: number; radius?: number; softness?: number; color?: string }): PostEffect<{
|
|
732
|
+
uStrength: number;
|
|
733
|
+
uRadius: number;
|
|
734
|
+
uSoftness: number;
|
|
735
|
+
uColor: string;
|
|
736
|
+
}>;
|
|
737
|
+
|
|
738
|
+
/** Glow around the bright parts. */
|
|
739
|
+
export function bloom(opts?: { threshold?: number; strength?: number; radius?: number }): PostEffect<{
|
|
740
|
+
uThreshold: number;
|
|
741
|
+
uStrength: number;
|
|
742
|
+
uRadius: number;
|
|
743
|
+
}>;
|
|
744
|
+
|
|
745
|
+
/** Brightness, contrast, saturation and a tint, in that order. */
|
|
746
|
+
export function grade(opts?: { brightness?: number; contrast?: number; saturation?: number; tint?: string }): PostEffect<{
|
|
747
|
+
uBrightness: number;
|
|
748
|
+
uContrast: number;
|
|
749
|
+
uSaturation: number;
|
|
750
|
+
uTint: string;
|
|
751
|
+
}>;
|
|
752
|
+
|
|
753
|
+
/** Film grain: random noise over the picture. */
|
|
754
|
+
export function grain(opts?: { amount?: number; size?: number; animated?: boolean }): PostEffect<{
|
|
755
|
+
uAmount: number;
|
|
756
|
+
uGrain: number;
|
|
757
|
+
uAnimated: boolean;
|
|
758
|
+
}>;
|
|
759
|
+
|
|
760
|
+
/** A post effect's passes (empty when it only has a canvas version). */
|
|
761
|
+
export function postPasses(effect: PostEffect): { glsl: string; scale: number }[];
|
|
762
|
+
|
|
763
|
+
/** The effects of a list that are on. */
|
|
764
|
+
export function activePost(list: PostEffect[] | undefined): PostEffect[];
|
|
765
|
+
|
|
766
|
+
/** Runs post effects' `canvas` functions on a scene's canvas (used by the renderers). */
|
|
767
|
+
export function runCanvasPost(scene: Scene, list: PostEffect[] | undefined, start: number): void;
|
|
768
|
+
|
|
769
|
+
/** The GLSL declaration of `Frame` and the `frame` / `source` helpers. */
|
|
770
|
+
export const FRAME_GLSL: string;
|
|
771
|
+
|
|
564
772
|
// ---------------------------------------------------------------------------
|
|
565
773
|
// Texture mapping
|
|
566
774
|
// ---------------------------------------------------------------------------
|
|
@@ -1105,6 +1313,8 @@ export interface TransformGizmoOptions {
|
|
|
1105
1313
|
size?: number;
|
|
1106
1314
|
/** Change the targets' transforms while dragging (default true) */
|
|
1107
1315
|
apply?: boolean;
|
|
1316
|
+
/** Where the handles sit and what rotate / scale go around (default "bounds") */
|
|
1317
|
+
pivot?: GizmoPivot;
|
|
1108
1318
|
/** A handle was grabbed */
|
|
1109
1319
|
onGrab?: (targets: SceneObject[]) => void;
|
|
1110
1320
|
/** While dragging: the operation since the grab */
|
|
@@ -1114,8 +1324,17 @@ export interface TransformGizmoOptions {
|
|
|
1114
1324
|
}
|
|
1115
1325
|
|
|
1116
1326
|
/**
|
|
1117
|
-
*
|
|
1118
|
-
*
|
|
1327
|
+
* Where a `TransformGizmo` puts its handles and turns / scales around:
|
|
1328
|
+
* - `"bounds"`: the middle of the targets' bounding box
|
|
1329
|
+
* - `"origin"`: the targets' origins in the world (averaged)
|
|
1330
|
+
* - a world point (moved along when the gizmo moves the targets)
|
|
1331
|
+
* - a function asked every frame
|
|
1332
|
+
*/
|
|
1333
|
+
export type GizmoPivot = "bounds" | "origin" | Vec3 | ((targets: SceneObject[]) => Vec3 | null);
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* Move arrows, rotate rings or scale handles on one or more objects, around a
|
|
1337
|
+
* pivot (default: the middle of their bounding box). Add it after the camera tool.
|
|
1119
1338
|
*/
|
|
1120
1339
|
export class TransformGizmo implements Tool {
|
|
1121
1340
|
constructor(opts?: TransformGizmoOptions);
|
|
@@ -1123,6 +1342,7 @@ export class TransformGizmo implements Tool {
|
|
|
1123
1342
|
targets: SceneObject[];
|
|
1124
1343
|
size: number;
|
|
1125
1344
|
apply: boolean;
|
|
1345
|
+
pivot: GizmoPivot;
|
|
1126
1346
|
onGrab?: (targets: SceneObject[]) => void;
|
|
1127
1347
|
onChange?: (op: TransformOp, targets: SceneObject[]) => void;
|
|
1128
1348
|
onDrop?: (op: TransformOp, targets: SceneObject[]) => void;
|
|
@@ -1130,7 +1350,7 @@ export class TransformGizmo implements Tool {
|
|
|
1130
1350
|
visible: boolean;
|
|
1131
1351
|
/** True while a handle is being dragged. */
|
|
1132
1352
|
readonly dragging: boolean;
|
|
1133
|
-
/**
|
|
1353
|
+
/** The pivot in world space, or null when there are no targets. */
|
|
1134
1354
|
center(): Vec3 | null;
|
|
1135
1355
|
draw(ctx: CanvasRenderingContext2D, scene: Scene): void;
|
|
1136
1356
|
pointerDown(e: ToolPointerEvent, scene: Scene): boolean;
|
|
@@ -1164,8 +1384,25 @@ export interface PickHit {
|
|
|
1164
1384
|
depth: number;
|
|
1165
1385
|
/** The object, then its groups up to the top: `[part, group, ..., root]` */
|
|
1166
1386
|
path: SceneObject[];
|
|
1387
|
+
/** Where the hit is, in the world */
|
|
1388
|
+
point: Vec3;
|
|
1389
|
+
/** Where the hit is, in the mesh's own space */
|
|
1390
|
+
local: Vec3;
|
|
1391
|
+
/** The 3 vertex indices of the triangle hit (polygons are fans from their first corner); null for a line */
|
|
1392
|
+
triangle: [number, number, number] | null;
|
|
1393
|
+
/** Weights of those vertices at the hit (they add up to 1); null for a line */
|
|
1394
|
+
barycentric: [number, number, number] | null;
|
|
1395
|
+
/** Unit normal of the face hit, in the world, on its front side; null for a line */
|
|
1396
|
+
normal: Vec3 | null;
|
|
1397
|
+
/** Texture coordinates at the hit (the material's mapping, before repeat / offset / rotation); null without any */
|
|
1398
|
+
uv: UV | null;
|
|
1399
|
+
/** Where the texture is read: `uv` with the material's repeat, offset and rotation; null without texture coordinates */
|
|
1400
|
+
textureUV: UV | null;
|
|
1167
1401
|
}
|
|
1168
1402
|
|
|
1403
|
+
/** Whether picking can find an object (not when it or a group above it has `pickable: false`). */
|
|
1404
|
+
export function isPickable(obj: SceneObjectInput & { parent?: SceneObjectInput | null }): boolean;
|
|
1405
|
+
|
|
1169
1406
|
/**
|
|
1170
1407
|
* Exact picking: the nearest object whose triangles (or, without faces, lines
|
|
1171
1408
|
* within `padding` pixels) are under a canvas pixel.
|
package/trid/index.js
CHANGED
|
@@ -15,18 +15,25 @@ export { worldObjects, worldMatrix, worldPosition, ancestors, forEachPlaced } fr
|
|
|
15
15
|
|
|
16
16
|
// Shapes and meshes
|
|
17
17
|
export { makeShape, scaleMesh, lathe, extrude, triangulate } from "./render/shapes.js";
|
|
18
|
+
export { gridMesh, gridHelper } from "./render/grid.js";
|
|
18
19
|
export { cloneMesh, transformMesh, displaceMesh, mergeMeshes, meshBounds } from "./render/meshUtils.js";
|
|
19
20
|
|
|
20
21
|
// Renderers
|
|
21
22
|
export { CanvasRenderer, DEFAULT_LIGHT, DEFAULT_AMBIENT, materialsOf } from "./render/canvasRenderer.js";
|
|
22
23
|
export { WebGLRenderer, DEFAULT_FAR } from "./render/webglRenderer.js";
|
|
23
24
|
|
|
25
|
+
// Lights
|
|
26
|
+
export { defaultLights, sceneLights, lightAt, lightLevels, rangeFade, MAX_LIGHTS } from "./render/lights.js";
|
|
27
|
+
|
|
24
28
|
// Effects
|
|
25
29
|
export {
|
|
26
30
|
toon, rim, edgeGlow, unlit, gradient, fog,
|
|
27
31
|
buildEffects, effectsKey, uniformType, SURFACE_GLSL,
|
|
28
32
|
} from "./render/effects.js";
|
|
29
33
|
|
|
34
|
+
// Post effects
|
|
35
|
+
export { vignette, bloom, grade, grain, postPasses, activePost, runCanvasPost, FRAME_GLSL } from "./render/post.js";
|
|
36
|
+
|
|
30
37
|
// Procedural textures
|
|
31
38
|
export { makeTexture, texturePixels, colorBytes, TEXTURE_STYLES } from "./render/proceduralTextures.js";
|
|
32
39
|
|
|
@@ -50,7 +57,7 @@ export { screenshot, record, download } from "./export/capture.js";
|
|
|
50
57
|
export {
|
|
51
58
|
OrbitCamera, FlyCamera, DragObject, HoverHighlight, FpsMeter, ObjUploader,
|
|
52
59
|
ViewGizmo, TransformGizmo,
|
|
53
|
-
ToolManager, pick, pickHit, screenBounds, worldPerPixel,
|
|
60
|
+
ToolManager, pick, pickHit, isPickable, screenBounds, worldPerPixel,
|
|
54
61
|
} from "./tools/index.js";
|
|
55
62
|
|
|
56
63
|
// Drawing and the frame loop
|