luxscura 0.2.0 → 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 +99 -10
- package/dist/glossy.js.map +1 -1
- package/dist/index.js +21 -15
- package/dist/index.js.map +1 -1
- package/dist/matte.js.map +1 -1
- package/dist/pbr.js.map +1 -1
- package/dist/program.d.ts +12 -13
- package/dist/renderer.d.ts +10 -6
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -246,9 +246,11 @@ const appearance = createPbrAppearance({
|
|
|
246
246
|
|
|
247
247
|
### Program — `createRaymarchProgram`
|
|
248
248
|
|
|
249
|
-
A program describes what to render. `createRaymarchProgram`
|
|
250
|
-
callbacks
|
|
251
|
-
|
|
249
|
+
A program describes what to render. `createRaymarchProgram` accepts either GPU
|
|
250
|
+
callbacks directly or a factory that creates them from typed dependencies. It
|
|
251
|
+
stores a factory and compilation options in a versioned `RaymarchProgramDefinition`;
|
|
252
|
+
the direct form is wrapped in a factory automatically. Defining a program does
|
|
253
|
+
not invoke the factory or allocate GPU resources. Pass the definition to a renderer.
|
|
252
254
|
|
|
253
255
|
Using named GPU callbacks keeps the call small (their implementations follow the
|
|
254
256
|
same pattern as the quick start):
|
|
@@ -269,6 +271,68 @@ const program = createRaymarchProgram({
|
|
|
269
271
|
})
|
|
270
272
|
```
|
|
271
273
|
|
|
274
|
+
When callbacks need resources supplied later, pass compilation options as the
|
|
275
|
+
first argument and a factory as the second:
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import type { TgpuUniform } from 'typegpu'
|
|
279
|
+
import { f32, vec3f, vec4f } from 'typegpu/data'
|
|
280
|
+
import { length } from 'typegpu/std'
|
|
281
|
+
import { AABB, createRaymarchProgram, type RaymarchCamera } from 'luxscura'
|
|
282
|
+
|
|
283
|
+
type SphereContext = {
|
|
284
|
+
camera: () => RaymarchCamera
|
|
285
|
+
radius: TgpuUniform<typeof f32>
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const sphereProgram = createRaymarchProgram(
|
|
289
|
+
{ epsilon: 0.001 },
|
|
290
|
+
({ camera, radius }: SphereContext) => ({
|
|
291
|
+
camera,
|
|
292
|
+
surface: {
|
|
293
|
+
bounds: () => {
|
|
294
|
+
'use gpu'
|
|
295
|
+
return AABB({ min: vec3f(-radius.$), max: vec3f(radius.$) })
|
|
296
|
+
},
|
|
297
|
+
sd: (point) => {
|
|
298
|
+
'use gpu'
|
|
299
|
+
return length(point) - radius.$
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
appearance: () => {
|
|
303
|
+
'use gpu'
|
|
304
|
+
return vec4f(1, 0.2, 0.1, 1)
|
|
305
|
+
},
|
|
306
|
+
}),
|
|
307
|
+
)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Create the resources in application setup and supply them to the renderer:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
const radius = root.createUniform(f32, 0.5)
|
|
314
|
+
const renderSphere = createRaymarchRenderer({
|
|
315
|
+
root,
|
|
316
|
+
program: sphereProgram,
|
|
317
|
+
context: { camera: getCamera, radius },
|
|
318
|
+
})
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
The program determines the required context type. Missing or incompatible
|
|
322
|
+
context is a type error. Direct programs and zero-argument factories do not
|
|
323
|
+
require a `context` argument.
|
|
324
|
+
|
|
325
|
+
The factory is a synchronous JavaScript setup function; the callbacks it returns
|
|
326
|
+
are GPU functions. Luxscura invokes it during renderer creation and again when
|
|
327
|
+
the program version changes, before running `prepare` and compiling the pipeline.
|
|
328
|
+
It does not run on ordinary draws. Updating `radius` with `radius.write(...)`
|
|
329
|
+
changes what the shaders read without rebuilding the program.
|
|
330
|
+
|
|
331
|
+
Context belongs to each renderer, so several renderers can share one program
|
|
332
|
+
with different resources. Luxscura retains and passes the supplied context; it
|
|
333
|
+
does not create or destroy its resources. Allocate caller-owned GPU resources
|
|
334
|
+
outside the factory so shader rebuilds can reuse them.
|
|
335
|
+
|
|
272
336
|
The property paths below follow the nesting in the call above. Callback types
|
|
273
337
|
include argument and return types; `v3f` and `v4f` are TypeGPU float vector types
|
|
274
338
|
from `typegpu/data`. Values in `options` are used when compiling the pipeline.
|
|
@@ -462,10 +526,22 @@ Your application's TypeGPU root, used to create the pipeline.
|
|
|
462
526
|
|
|
463
527
|
| Type | Default |
|
|
464
528
|
| --- | --- |
|
|
465
|
-
| `Readonly<RaymarchProgramDefinition
|
|
529
|
+
| `Readonly<RaymarchProgramDefinition<TContext>>` | Required |
|
|
466
530
|
|
|
467
531
|
The definition returned by `createRaymarchProgram`.
|
|
468
532
|
|
|
533
|
+
#### `context`
|
|
534
|
+
|
|
535
|
+
| Type | Default |
|
|
536
|
+
| --- | --- |
|
|
537
|
+
| `TContext` (inferred from `program`) | Required unless the type accepts `undefined` |
|
|
538
|
+
|
|
539
|
+
Setup-time dependencies passed to the program factory. The same context is used
|
|
540
|
+
when this renderer rebuilds after a program update. Changing the context object
|
|
541
|
+
itself does not trigger recompilation; use buffers or uniforms for changing GPU
|
|
542
|
+
data. If an edit adds required dependencies, recreate the renderer with a context
|
|
543
|
+
that supplies them.
|
|
544
|
+
|
|
469
545
|
#### `renderTarget`
|
|
470
546
|
|
|
471
547
|
| Type | Default |
|
|
@@ -508,8 +584,9 @@ color resolve target.
|
|
|
508
584
|
| --- | --- |
|
|
509
585
|
| `(program: RaymarchProgram) => RaymarchProgram` | None |
|
|
510
586
|
|
|
511
|
-
Transforms the camera, surface, or appearance callbacks
|
|
512
|
-
resulting `RaymarchProgram`, for example to
|
|
587
|
+
Transforms the camera, surface, or appearance callbacks after the factory runs
|
|
588
|
+
and before compilation. Return the resulting `RaymarchProgram`, for example to
|
|
589
|
+
decorate its appearance or adapt its geometry.
|
|
513
590
|
|
|
514
591
|
#### `preparePipeline`
|
|
515
592
|
|
|
@@ -574,8 +651,9 @@ per-instance values in a GPU buffer to change how the program renders that insta
|
|
|
574
651
|
## Hot module reloading
|
|
575
652
|
|
|
576
653
|
If shader edits cause a full page reload or do not update the renderer, enable
|
|
577
|
-
Luxscura's hot reload support. With Vite, pass `import.meta.hot` as the
|
|
578
|
-
argument to `createRaymarchProgram` and call `import.meta.hot?.accept()
|
|
654
|
+
Luxscura's hot reload support. With Vite, pass `import.meta.hot` as the final
|
|
655
|
+
argument to `createRaymarchProgram` and call `import.meta.hot?.accept()`. It is
|
|
656
|
+
the second argument for the direct form:
|
|
579
657
|
|
|
580
658
|
```ts
|
|
581
659
|
const program = createRaymarchProgram({
|
|
@@ -588,8 +666,19 @@ const program = createRaymarchProgram({
|
|
|
588
666
|
import.meta.hot?.accept()
|
|
589
667
|
```
|
|
590
668
|
|
|
669
|
+
For the factory form, it is the third argument:
|
|
670
|
+
|
|
671
|
+
```ts
|
|
672
|
+
const program = createRaymarchProgram(options, createProgram, import.meta.hot)
|
|
673
|
+
|
|
674
|
+
import.meta.hot?.accept()
|
|
675
|
+
```
|
|
676
|
+
|
|
591
677
|
On a module update, Luxscura preserves the program definition and increments its
|
|
592
|
-
version.
|
|
593
|
-
|
|
678
|
+
version. Each existing renderer invokes the updated factory with its original
|
|
679
|
+
context and rebuilds its pipeline on its next draw, using the updated options.
|
|
680
|
+
Both preparation hooks run again; caller-owned buffers and uniforms remain in
|
|
681
|
+
place. Changing the required context shape may require recreating the renderer
|
|
682
|
+
or reloading the application.
|
|
594
683
|
|
|
595
684
|
Currently, only one HMR-backed program can be defined per module.
|
package/dist/glossy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glossy.js","names":[],"sources":["../src/appearances/glossy/appearance.ts","../src/appearances/glossy/material.ts"],"sourcesContent":["import { type v4f, vec4f } from 'typegpu/data'\nimport { dot, max, normalize, pow, saturate } from 'typegpu/std'\nimport type { RaymarchLighting } from '../../lighting'\nimport type { RaymarchAppearance, RaymarchResult } from '../../program'\nimport type { GlossyMaterial } from './material'\n\n/** GPU function sampling a glossy material from the raymarch result. */\nexport type GlossyMaterialSampler = (result: RaymarchResult) => GlossyMaterial\n\n/**\n * Creates a glossy appearance using diffuse lighting and Blinn-Phong highlights.\n * Ambient fill affects the diffuse color; emission is added independently.\n * Material opacity applies to the entire shaded result during blending.\n *\n * Material sampling runs for hits and misses so derivatives remain available.\n * Lighting runs only for hits. Colors and lighting values are linear RGB.\n */\nexport function createGlossyAppearance({\n\tmaterial,\n\tlighting,\n}: {\n\tmaterial: GlossyMaterialSampler\n\tlighting: () => RaymarchLighting\n}): RaymarchAppearance {\n\treturn function glossyAppearance(result: RaymarchResult): v4f {\n\t\t'use gpu'\n\t\tconst materialSample = material(result)\n\t\tif (!result.isHit) return vec4f(0)\n\n\t\tconst lights = lighting()\n\t\tlet color =\n\t\t\tmaterialSample.baseColor * lights.ambient + materialSample.emission\n\t\tconst viewDirection = -1 * result.rayDirection\n\t\tconst facingCamera = dot(result.normal, viewDirection) > 0\n\t\tconst shininess = max(materialSample.shininess, 1)\n\n\t\tfor (const light of lights.directionalLights) {\n\t\t\tif (light.intensity === 0) continue\n\n\t\t\tconst lightDirection = -1 * normalize(light.direction)\n\t\t\tconst diffuse = saturate(dot(result.normal, lightDirection))\n\t\t\tif (diffuse === 0) continue\n\n\t\t\tlet response = materialSample.baseColor * diffuse\n\t\t\tif (facingCamera) {\n\t\t\t\tconst halfwayDirection = normalize(viewDirection + lightDirection)\n\t\t\t\tconst highlight = pow(\n\t\t\t\t\tsaturate(dot(result.normal, halfwayDirection)),\n\t\t\t\t\tshininess,\n\t\t\t\t)\n\t\t\t\tresponse += materialSample.specular * highlight\n\t\t\t}\n\n\t\t\tcolor += light.color * light.intensity * response\n\t\t}\n\n\t\treturn vec4f(color, materialSample.opacity)\n\t}\n}\n","import { f32, type Infer, struct, vec3f } from 'typegpu/data'\nimport { mix } from 'typegpu/std'\n\n/**\n * GPU material schema for a surface with adjustable shiny highlights and opacity.\n * Colors are linear RGB. Callers must supply finite values within the documented\n * ranges; constructing this struct does not clamp or validate material values.\n */\nexport const GlossyMaterial = struct({\n\t/** Diffuse surface color. Each channel is in [0, 1]. */\n\tbaseColor: vec3f,\n\n\t/** Highlight color and strength. Each channel is in [0, 1]; black disables highlights. */\n\tspecular: vec3f,\n\n\t/**\n\t * Highlight tightness: lower values produce broad highlights, higher values\n\t * small ones. Use values of at least 1; shading applies an internal floor of 1.\n\t */\n\tshininess: f32,\n\n\t/** Nonnegative outgoing linear RGB added independently of illumination; may exceed 1. */\n\temission: vec3f,\n\n\t/** Opacity of the entire shaded surface in [0, 1]: 0 is transparent, 1 is opaque. */\n\topacity: f32,\n})\nexport type GlossyMaterial = Infer<typeof GlossyMaterial>\n\n/** Linearly blends all material properties. Amount is 0 for a, 1 for b, and is not clamped. */\nexport function mixGlossyMaterials(\n\ta: GlossyMaterial,\n\tb: GlossyMaterial,\n\tamount: number,\n): GlossyMaterial {\n\t'use gpu'\n\treturn GlossyMaterial({\n\t\tbaseColor: mix(a.baseColor, b.baseColor, amount),\n\t\tspecular: mix(a.specular, b.specular, amount),\n\t\tshininess: mix(a.shininess, b.shininess, amount),\n\t\temission: mix(a.emission, b.emission, amount),\n\t\topacity: mix(a.opacity, b.opacity, amount),\n\t})\n}\n"],"mappings":";;;AAiBA,
|
|
1
|
+
{"version":3,"file":"glossy.js","names":["createGlossyAppearance","materialSample","material","result","vec4f","lights","lighting","color","viewDirection","facingCamera","dot","shininess","max","light","lightDirection","normalize","diffuse","saturate","response","halfwayDirection","highlight","pow","\"params\"","\"type\"","\"name\"","\"body\"","\"material\"","\"vec4f\"","\"lighting\"","\"dot\"","\"max\"","\"normalize\"","\"saturate\"","\"pow\"","$","mixGlossyMaterials","GlossyMaterial","mix","a","b","amount","\"baseColor\"","\"specular\"","\"shininess\"","\"emission\"","\"opacity\"","\"GlossyMaterial\"","\"mix\"","struct","vec3f","f32"],"sources":["../src/appearances/glossy/appearance.ts","../src/appearances/glossy/material.ts"],"sourcesContent":["import { type v4f, vec4f } from 'typegpu/data'\nimport { dot, max, normalize, pow, saturate } from 'typegpu/std'\nimport type { RaymarchLighting } from '../../lighting'\nimport type { RaymarchAppearance, RaymarchResult } from '../../program'\nimport type { GlossyMaterial } from './material'\n\n/** GPU function sampling a glossy material from the raymarch result. */\nexport type GlossyMaterialSampler = (result: RaymarchResult) => GlossyMaterial\n\n/**\n * Creates a glossy appearance using diffuse lighting and Blinn-Phong highlights.\n * Ambient fill affects the diffuse color; emission is added independently.\n * Material opacity applies to the entire shaded result during blending.\n *\n * Material sampling runs for hits and misses so derivatives remain available.\n * Lighting runs only for hits. Colors and lighting values are linear RGB.\n */\nexport function createGlossyAppearance({\n\tmaterial,\n\tlighting,\n}: {\n\tmaterial: GlossyMaterialSampler\n\tlighting: () => RaymarchLighting\n}): RaymarchAppearance {\n\treturn function glossyAppearance(result: RaymarchResult): v4f {\n\t\t'use gpu'\n\t\tconst materialSample = material(result)\n\t\tif (!result.isHit) return vec4f(0)\n\n\t\tconst lights = lighting()\n\t\tlet color =\n\t\t\tmaterialSample.baseColor * lights.ambient + materialSample.emission\n\t\tconst viewDirection = -1 * result.rayDirection\n\t\tconst facingCamera = dot(result.normal, viewDirection) > 0\n\t\tconst shininess = max(materialSample.shininess, 1)\n\n\t\tfor (const light of lights.directionalLights) {\n\t\t\tif (light.intensity === 0) continue\n\n\t\t\tconst lightDirection = -1 * normalize(light.direction)\n\t\t\tconst diffuse = saturate(dot(result.normal, lightDirection))\n\t\t\tif (diffuse === 0) continue\n\n\t\t\tlet response = materialSample.baseColor * diffuse\n\t\t\tif (facingCamera) {\n\t\t\t\tconst halfwayDirection = normalize(viewDirection + lightDirection)\n\t\t\t\tconst highlight = pow(\n\t\t\t\t\tsaturate(dot(result.normal, halfwayDirection)),\n\t\t\t\t\tshininess,\n\t\t\t\t)\n\t\t\t\tresponse += materialSample.specular * highlight\n\t\t\t}\n\n\t\t\tcolor += light.color * light.intensity * response\n\t\t}\n\n\t\treturn vec4f(color, materialSample.opacity)\n\t}\n}\n","import { f32, type Infer, struct, vec3f } from 'typegpu/data'\nimport { mix } from 'typegpu/std'\n\n/**\n * GPU material schema for a surface with adjustable shiny highlights and opacity.\n * Colors are linear RGB. Callers must supply finite values within the documented\n * ranges; constructing this struct does not clamp or validate material values.\n */\nexport const GlossyMaterial = struct({\n\t/** Diffuse surface color. Each channel is in [0, 1]. */\n\tbaseColor: vec3f,\n\n\t/** Highlight color and strength. Each channel is in [0, 1]; black disables highlights. */\n\tspecular: vec3f,\n\n\t/**\n\t * Highlight tightness: lower values produce broad highlights, higher values\n\t * small ones. Use values of at least 1; shading applies an internal floor of 1.\n\t */\n\tshininess: f32,\n\n\t/** Nonnegative outgoing linear RGB added independently of illumination; may exceed 1. */\n\temission: vec3f,\n\n\t/** Opacity of the entire shaded surface in [0, 1]: 0 is transparent, 1 is opaque. */\n\topacity: f32,\n})\nexport type GlossyMaterial = Infer<typeof GlossyMaterial>\n\n/** Linearly blends all material properties. Amount is 0 for a, 1 for b, and is not clamped. */\nexport function mixGlossyMaterials(\n\ta: GlossyMaterial,\n\tb: GlossyMaterial,\n\tamount: number,\n): GlossyMaterial {\n\t'use gpu'\n\treturn GlossyMaterial({\n\t\tbaseColor: mix(a.baseColor, b.baseColor, amount),\n\t\tspecular: mix(a.specular, b.specular, amount),\n\t\tshininess: mix(a.shininess, b.shininess, amount),\n\t\temission: mix(a.emission, b.emission, amount),\n\t\topacity: mix(a.opacity, b.opacity, amount),\n\t})\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -347,13 +347,19 @@ var E = /*#__PURE__*/ (globalThis.__TYPEGPU_AUTONAME__ ?? ((e) => e))(o({
|
|
|
347
347
|
instanceIndex: s,
|
|
348
348
|
bounds: x
|
|
349
349
|
}), "RaymarchResult"), O = "raymarchProgramDefinition";
|
|
350
|
-
function k(
|
|
351
|
-
let r
|
|
350
|
+
function k(e, t, n) {
|
|
351
|
+
let r, i;
|
|
352
|
+
if (typeof t == "function") r = e, i = t;
|
|
353
|
+
else {
|
|
354
|
+
let { options: a, ...o } = e;
|
|
355
|
+
r = a, i = () => o, n = t;
|
|
356
|
+
}
|
|
357
|
+
let a = n?.data[O] ?? {
|
|
352
358
|
version: 0,
|
|
353
|
-
options:
|
|
354
|
-
|
|
359
|
+
options: r,
|
|
360
|
+
create: i
|
|
355
361
|
};
|
|
356
|
-
return
|
|
362
|
+
return a.version += 1, a.options = r, a.create = i, n && (n.data[O] = a), a;
|
|
357
363
|
}
|
|
358
364
|
//#endregion
|
|
359
365
|
//#region src/cube-vertices.ts
|
|
@@ -1372,22 +1378,22 @@ function P({ root: e, options: t, camera: r, appearance: a, surface: o, prepareP
|
|
|
1372
1378
|
g.withColorAttachment({ color: e }).withDepthStencilAttachment(t).draw(A.$.length, n);
|
|
1373
1379
|
};
|
|
1374
1380
|
}
|
|
1375
|
-
function F({ root: e, program: t,
|
|
1376
|
-
function
|
|
1377
|
-
let { camera:
|
|
1381
|
+
function F({ root: e, program: t, context: n = void 0, renderTarget: r, prepare: i = (e) => e, preparePipeline: a }) {
|
|
1382
|
+
function o() {
|
|
1383
|
+
let { camera: o, surface: s, appearance: c } = i(t.create(n));
|
|
1378
1384
|
return P({
|
|
1379
1385
|
root: e,
|
|
1380
1386
|
options: t.options,
|
|
1381
|
-
surface:
|
|
1382
|
-
camera:
|
|
1383
|
-
appearance:
|
|
1384
|
-
preparePipeline:
|
|
1385
|
-
renderTarget:
|
|
1387
|
+
surface: s,
|
|
1388
|
+
camera: o,
|
|
1389
|
+
appearance: c,
|
|
1390
|
+
preparePipeline: a,
|
|
1391
|
+
renderTarget: r
|
|
1386
1392
|
});
|
|
1387
1393
|
}
|
|
1388
|
-
let
|
|
1394
|
+
let s = t.version, c = o();
|
|
1389
1395
|
return function(e) {
|
|
1390
|
-
|
|
1396
|
+
s !== t.version && (c = o(), s = t.version), c(e);
|
|
1391
1397
|
};
|
|
1392
1398
|
}
|
|
1393
1399
|
//#endregion
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/aabb.ts","../src/lighting.ts","../src/program.ts","../src/cube-vertices.ts","../src/renderer.ts"],"sourcesContent":["import { f32, type Infer, struct, type v3f, vec3b, vec3f } from 'typegpu/data'\nimport { min, select } from 'typegpu/std'\n\nexport const AABB = struct({\n\tmin: vec3f,\n\tmax: vec3f,\n})\nexport type AABB = Infer<typeof AABB>\n\nexport function aabbPoint(aabb: AABB, corner: v3f): v3f {\n\t'use gpu'\n\treturn select(\n\t\taabb.min,\n\t\taabb.max,\n\t\tvec3b(corner.x > 0, corner.y > 0, corner.z > 0),\n\t)\n}\n\nexport function aabbCenter(aabb: AABB): v3f {\n\t'use gpu'\n\treturn (aabb.min + aabb.max) * 0.5\n}\n\nexport function aabbExitDistance(\n\taabb: AABB,\n\tpoint: v3f,\n\tdirection: v3f,\n): number {\n\t'use gpu'\n\n\treturn min(\n\t\taxisExitDistance(point.x, direction.x, aabb.min.x, aabb.max.x),\n\t\tmin(\n\t\t\taxisExitDistance(point.y, direction.y, aabb.min.y, aabb.max.y),\n\t\t\taxisExitDistance(point.z, direction.z, aabb.min.z, aabb.max.z),\n\t\t),\n\t)\n}\n\nfunction axisExitDistance(\n\tposition: number,\n\tdirection: number,\n\tminimum: number,\n\tmaximum: number,\n): number {\n\t'use gpu'\n\n\tif (direction > 0) return (maximum - position) / direction\n\tif (direction < 0) return (minimum - position) / direction\n\treturn f32(1e9)\n}\n","import { arrayOf, f32, type Infer, struct, vec3f } from 'typegpu/data'\n\n/** Shared GPU schema for a directional light used by lit appearances. */\nexport const RaymarchDirectionalLight = struct({\n\t/** Nonzero world-space direction of travel; normalized during shading. */\n\tdirection: vec3f,\n\n\t/** Linear RGB light color. */\n\tcolor: vec3f,\n\n\t/** Brightness multiplier; zero disables the light. */\n\tintensity: f32,\n})\n\n/** Directional-light values accepted by lighting providers. */\nexport type RaymarchDirectionalLight = Infer<typeof RaymarchDirectionalLight>\n\nconst fallbackDirectionalLights = [\n\tRaymarchDirectionalLight({\n\t\tdirection: vec3f(0, -1, 0),\n\t\tcolor: vec3f(0),\n\t\tintensity: 0,\n\t}),\n]\n\n/**\n * Creates a GPU lighting schema with a fixed number of light slots.\n * @throws {RangeError} If capacity is not a positive integer.\n */\nfunction createRaymarchLightingStruct(capacity: number) {\n\tif (!Number.isInteger(capacity) || capacity < 1) {\n\t\tthrow new RangeError('Lighting capacity must be a positive integer.')\n\t}\n\n\treturn struct({\n\t\t/** Additive linear RGB diffuse fill; black adds no ambient illumination. */\n\t\tambient: vec3f,\n\n\t\t/** Directional lights evaluated independently and added together. */\n\t\tdirectionalLights: arrayOf(RaymarchDirectionalLight, capacity),\n\t})\n}\n/** Ambient fill and directional-light values returned by a GPU lighting provider. */\nexport type RaymarchLighting = Infer<\n\tReturnType<typeof createRaymarchLightingStruct>\n>\n\n/**\n * Creates a GPU lighting callback with values embedded during shader compilation.\n * Infers capacity from directionalLights; an empty list uses one disabled slot.\n */\nexport function createRaymarchConstantLighting(lighting: RaymarchLighting) {\n\tconst directionalLights =\n\t\tlighting.directionalLights.length > 0\n\t\t\t? lighting.directionalLights\n\t\t\t: fallbackDirectionalLights\n\n\tconst RaymarchConstantLighting = createRaymarchLightingStruct(\n\t\tdirectionalLights.length,\n\t)\n\n\treturn function raymarchLighting() {\n\t\t'use gpu'\n\t\treturn RaymarchConstantLighting({\n\t\t\tambient: lighting.ambient,\n\t\t\tdirectionalLights: directionalLights,\n\t\t})\n\t}\n}\n","import {\n\tbool,\n\tf32,\n\ttype Infer,\n\tmat4x4f,\n\tstruct,\n\tu32,\n\ttype v3f,\n\ttype v4f,\n\tvec2f,\n\tvec3f,\n} from 'typegpu/data'\nimport { AABB } from './aabb'\n\nexport const RaymarchCamera = struct({\n\tposition: vec3f,\n\tviewProjectionMatrix: mat4x4f,\n})\nexport type RaymarchCamera = Infer<typeof RaymarchCamera>\n\n/** Result of the primary ray march, with data available for appearance. */\nexport const RaymarchResult = struct({\n\t/** Whether the primary ray reached the surface within the march limits. */\n\tisHit: bool,\n\t/** Hit position, or the final ray sample position on a miss, in world space. */\n\tposition: vec3f,\n\t/** Outward surface normal on a hit; -rayDirection on a miss. */\n\tnormal: vec3f,\n\t/** Camera position in world space. */\n\trayOrigin: vec3f,\n\t/** Unit direction from the camera into the scene. */\n\trayDirection: vec3f,\n\t/** World-space distance from rayOrigin to position. */\n\trayDistance: f32,\n\t/** Number of primary ray-march iterations, excluding normal/shadow samples. */\n\tstepCount: u32,\n\t/** Projected depth written for a hit; 1 on a miss. */\n\tprojectedDepth: f32,\n\t/** Pixel-space fragment coordinates, with pixel centers at half-integers. */\n\tfragmentCoord: vec2f,\n\t/** Index of the bounds instance being rendered. */\n\tinstanceIndex: u32,\n\t/** World-space bounds for this instance. */\n\tbounds: AABB,\n})\nexport type RaymarchResult = Infer<typeof RaymarchResult>\n\n/**\n * GPU function calculating unpremultiplied linear RGB and opacity for every\n * visible fragment after marching. Alpha is opacity in [0, 1]. The renderer uses\n * the result only on hits and writes surface depth regardless of alpha, subject\n * to the program's depth settings. Derivative-dependent work must run outside\n * hit-dependent branches.\n */\nexport type RaymarchAppearance = (result: RaymarchResult) => v4f\n\nexport type RaymarchBoundsProvider = (instanceIdx: number) => AABB\n\nexport type RaymarchInitializer = (instanceIdx: number) => void\n\nexport type RaymarchVisibilityTest = (\n\trayPoint: v3f,\n\tinstanceIdx: number,\n\tbounds: AABB,\n) => boolean\n\nexport type RaymarchDistanceFunction = (\n\tpoint: v3f,\n\tinstanceIdx: number,\n\taabb: AABB,\n) => number\n\nexport type RaymarchProgramOptions = {\n\t/** Diagnostic metadata for consumers. Unused by the renderer. */\n\tlabel?: string\n\t/** Surface hit tolerance in world units. */\n\tepsilon: number\n\t/** Normal sampling offset; defaults to epsilon. */\n\tepsilonNormal?: number\n\t/** Maximum number of marching steps per ray; defaults to 100. */\n\tmaxSteps?: number\n\t/**\n\t * Multiplier applied to each raymarch step; defaults to 1.\n\t * Values between 0 and 1 reduce overshooting from domain warping at the cost\n\t * of more marching steps.\n\t */\n\tstepScale?: number\n\t/** Write surface hit depth to the depth buffer; defaults to true. */\n\tdepthWriteEnabled?: boolean\n\t/** Comparison used to test surface hit depth against the depth buffer; defaults to 'less'. */\n\tdepthCompare?: GPUCompareFunction\n} & (\n\t| {\n\t\t\t/** Allow marching past the bounding-box exit. Defaults to false; requires maxDistance when true. */\n\t\t\tmarchBeyondBounds?: false\n\t\t\t/** Maximum distance to march from the bounding-box entry point, in world units. */\n\t\t\tmaxDistance?: number\n\t }\n\t| {\n\t\t\t/** Allow marching past the bounding-box exit. Defaults to false; requires maxDistance when true. */\n\t\t\tmarchBeyondBounds: true\n\t\t\t/** Maximum distance to march from the bounding-box entry point, in world units. */\n\t\t\tmaxDistance: number\n\t }\n)\n\n/** Geometry and visibility callbacks compiled into a raymarching pipeline. */\nexport interface RaymarchSurface {\n\t/** GPU function initializing per-fragment state before raymarching. */\n\tinit?: RaymarchInitializer\n\n\t/** GPU function providing each instance's axis-aligned bounding box. */\n\tbounds: RaymarchBoundsProvider\n\n\t/**\n\t * GPU function masking out rays that should not render. Returning false\n\t * skips raymarching for that fragment.\n\t */\n\tisRayVisible?: RaymarchVisibilityTest\n\n\t/** GPU function returning the signed distance from a point to the surface. */\n\tsd: RaymarchDistanceFunction\n}\n\n/** Camera, geometry, and appearance compiled into one raymarching pipeline. */\nexport interface RaymarchProgram {\n\t/** GPU function providing the current camera state. */\n\tcamera: () => RaymarchCamera\n\n\t/** Surface bounds, signed distance, and optional visibility behavior. */\n\tsurface: RaymarchSurface\n\n\t/** GPU function returning unpremultiplied linear RGB and opacity for the raymarch result. */\n\tappearance: RaymarchAppearance\n}\n\n/** Versioned program with its pipeline compilation options. */\nexport interface RaymarchProgramDefinition {\n\tversion: number\n\toptions: RaymarchProgramOptions\n\tprogram: RaymarchProgram\n}\n\n/** Minimal hot-module context used to retain a program across reevaluations. */\nexport interface RaymarchHotContext {\n\tdata: Record<string, unknown>\n}\n\nconst HOT_DATA_KEY = 'raymarchProgramDefinition'\n\n/**\n * Creates a versioned program definition without allocating GPU resources. It\n * holds the surface, camera, and appearance callbacks,\n * and the options used to compile them into a raymarching pipeline. Callbacks\n * may read changing buffer data without rebuilding the pipeline.\n *\n * ```ts\n * const program = createRaymarchProgram({ ...program, options })\n * ```\n *\n * ## Vite Hot Reloading\n *\n * When `hot` is provided, reevaluating the module updates the existing program\n * definition and increments its version. Renderer instances observe that\n * version and rebuild their pipelines using the updated callbacks. The\n * defining module must call `import.meta.hot?.accept()` for this behavior, and\n * may currently define only one HMR-backed raymarch program.\n *\n * ```ts\n * const program = createRaymarchProgram({ ...program, options }, import.meta.hot)\n * import.meta.hot?.accept()\n * ```\n *\n * @returns A read-only program definition consumed by raymarch renderer factories.\n */\nexport function createRaymarchProgram(\n\t{\n\t\toptions,\n\t\t...program\n\t}: RaymarchProgram & {\n\t\toptions: RaymarchProgramOptions\n\t},\n\n\t/**\n\t * Optional hot-module context used to preserve and update the program\n\t * across module reevaluations.\n\t */\n\thot?: RaymarchHotContext,\n): Readonly<RaymarchProgramDefinition> {\n\tconst definition = (hot?.data[HOT_DATA_KEY] as\n\t\t| RaymarchProgramDefinition\n\t\t| undefined) ?? { version: 0, options, program }\n\n\tdefinition.version += 1\n\tdefinition.options = options\n\tdefinition.program = program\n\tif (hot) hot.data[HOT_DATA_KEY] = definition\n\n\treturn definition\n}\n","import { tgpu } from 'typegpu'\nimport { arrayOf, vec3f } from 'typegpu/data'\n\nexport const cubeVertices = tgpu.const(arrayOf(vec3f, 36), [\n\tvec3f(0, 0, 1),\n\tvec3f(1, 0, 1),\n\tvec3f(1, 1, 1),\n\tvec3f(1, 1, 1),\n\tvec3f(0, 1, 1),\n\tvec3f(0, 0, 1),\n\tvec3f(1, 0, 0),\n\tvec3f(0, 0, 0),\n\tvec3f(0, 1, 0),\n\tvec3f(0, 1, 0),\n\tvec3f(1, 1, 0),\n\tvec3f(1, 0, 0),\n\tvec3f(0, 1, 1),\n\tvec3f(1, 1, 1),\n\tvec3f(1, 1, 0),\n\tvec3f(1, 1, 0),\n\tvec3f(0, 1, 0),\n\tvec3f(0, 1, 1),\n\tvec3f(0, 0, 0),\n\tvec3f(1, 0, 0),\n\tvec3f(1, 0, 1),\n\tvec3f(1, 0, 1),\n\tvec3f(0, 0, 1),\n\tvec3f(0, 0, 0),\n\tvec3f(1, 0, 1),\n\tvec3f(1, 0, 0),\n\tvec3f(1, 1, 0),\n\tvec3f(1, 1, 0),\n\tvec3f(1, 1, 1),\n\tvec3f(1, 0, 1),\n\tvec3f(0, 0, 0),\n\tvec3f(0, 0, 1),\n\tvec3f(0, 1, 1),\n\tvec3f(0, 1, 1),\n\tvec3f(0, 1, 0),\n\tvec3f(0, 0, 0),\n])\n","import {\n\ttype ColorAttachment,\n\ttype DepthStencilAttachment,\n\ttype TgpuRenderPipeline,\n\ttype TgpuRoot,\n\ttgpu,\n} from 'typegpu'\nimport {\n\tbool,\n\tbuiltin,\n\tf32,\n\ttype Infer,\n\tinterpolate,\n\tstruct,\n\tu32,\n\ttype Vec4f,\n\ttype v3f,\n\tvec2f,\n\tvec3f,\n\tvec4f,\n} from 'typegpu/data'\nimport { discard, length, min, normalize } from 'typegpu/std'\nimport { type AABB, aabbExitDistance, aabbPoint } from './aabb'\nimport { cubeVertices } from './cube-vertices'\nimport {\n\ttype RaymarchAppearance,\n\ttype RaymarchCamera,\n\ttype RaymarchDistanceFunction,\n\ttype RaymarchProgram,\n\ttype RaymarchProgramDefinition,\n\ttype RaymarchProgramOptions,\n\tRaymarchResult,\n\ttype RaymarchSurface,\n\ttype RaymarchVisibilityTest,\n} from './program'\n\nexport interface RaymarchRenderTargetOptions {\n\t/**\n\t * Format of the color attachment.\n\t * @default navigator.gpu.getPreferredCanvasFormat()\n\t */\n\tcolorFormat?: GPUTextureFormat\n\n\t/**\n\t * Format of the depth/stencil attachment.\n\t * @default 'depth24plus'\n\t */\n\tdepthStencilFormat?: Extract<GPUTextureFormat, `depth${string}`>\n\n\t/**\n\t * Number of samples per pixel in each attachment.\n\t * @default 1\n\t */\n\tsampleCount?: 1 | 4\n}\n\n/** Attachments and instance count for one raymarch draw submission. */\nexport interface RaymarchRenderOptions {\n\tcolorAttachment: ColorAttachment\n\tdepthStencilAttachment: DepthStencilAttachment\n\t/** @default 1 */\n\tinstances?: number\n}\n\nconst RayHit = struct({\n\tisHit: bool,\n\tpos: vec3f,\n\tdepth: f32,\n\trayDirection: vec3f,\n\trayDistance: f32,\n\tstepCount: u32,\n})\ntype RayHit = Infer<typeof RayHit>\n\nfunction createRaymarch({\n\tsdSurface,\n\tmaxSteps,\n\tstepScale,\n\tmaxDistance,\n\tepsilon,\n\tmarchBeyondBounds,\n}: {\n\tsdSurface: RaymarchDistanceFunction\n\tmaxSteps: number\n\tstepScale: number\n\tmaxDistance?: number\n\tepsilon: number\n\tmarchBeyondBounds: boolean\n}) {\n\treturn function raymarch(\n\t\tcamera: RaymarchCamera,\n\t\tworldPosition: v3f,\n\t\taabb: AABB,\n\t\tinstanceIndex: number,\n\t): RayHit {\n\t\t'use gpu'\n\t\tconst triangleDifference = worldPosition.xyz - camera.position\n\t\tconst triangleDistance = length(triangleDifference)\n\t\tconst rayDirection = normalize(triangleDifference)\n\n\t\tlet marchedDistance = f32(0)\n\t\tlet point = camera.position + rayDirection * triangleDistance\n\t\tlet stepCount = u32(0)\n\n\t\tlet marchLimit = aabbExitDistance(aabb, point, rayDirection)\n\t\tif (marchBeyondBounds) {\n\t\t\tmarchLimit = f32(maxDistance ?? 0)\n\t\t} else if (maxDistance !== undefined) {\n\t\t\tmarchLimit = min(marchLimit, maxDistance)\n\t\t}\n\n\t\tfor (let stepIndex = 0; stepIndex < maxSteps; stepIndex++) {\n\t\t\tif (marchedDistance > marchLimit) break\n\t\t\tstepCount += 1\n\n\t\t\tpoint =\n\t\t\t\tcamera.position + rayDirection * (triangleDistance + marchedDistance)\n\n\t\t\tconst distance = sdSurface(point, instanceIndex, aabb)\n\n\t\t\tif (distance < epsilon) {\n\t\t\t\tconst hitClipPosition = camera.viewProjectionMatrix * vec4f(point, 1)\n\n\t\t\t\treturn RayHit({\n\t\t\t\t\tisHit: true,\n\t\t\t\t\tpos: point,\n\t\t\t\t\tdepth: hitClipPosition.z / hitClipPosition.w,\n\t\t\t\t\trayDirection,\n\t\t\t\t\trayDistance: triangleDistance + marchedDistance,\n\t\t\t\t\tstepCount,\n\t\t\t\t})\n\t\t\t}\n\t\t\tmarchedDistance += distance * stepScale\n\t\t}\n\n\t\treturn RayHit({\n\t\t\tisHit: false,\n\t\t\tpos: point,\n\t\t\tdepth: 1,\n\t\t\trayDirection,\n\t\t\trayDistance: length(point - camera.position),\n\t\t\tstepCount,\n\t\t})\n\t}\n}\n\nfunction createCalculateNormal({\n\tsdSurface,\n\tepsilonNormal,\n}: {\n\tsdSurface: RaymarchDistanceFunction\n\tepsilonNormal: number\n}) {\n\treturn function calculateNormal(\n\t\tpoint: v3f,\n\t\taabb: AABB,\n\t\tinstanceIndex: number,\n\t): v3f {\n\t\t'use gpu'\n\t\tconst k = vec2f(1, -1)\n\t\treturn normalize(\n\t\t\tk.xyy * sdSurface(point + k.xyy * epsilonNormal, instanceIndex, aabb) +\n\t\t\t\t(k.yyx * sdSurface(point + k.yyx * epsilonNormal, instanceIndex, aabb) +\n\t\t\t\t\t(k.yxy *\n\t\t\t\t\t\tsdSurface(point + k.yxy * epsilonNormal, instanceIndex, aabb) +\n\t\t\t\t\t\tk.xxx *\n\t\t\t\t\t\t\tsdSurface(point + k.xxx * epsilonNormal, instanceIndex, aabb))),\n\t\t)\n\t}\n}\n\n/**\n * Creates a GPU pipeline that renders a raymarched surface.\n *\n * @returns A function that draws the requested number of instances.\n */\nfunction createRaymarchPipeline({\n\troot,\n\toptions,\n\tcamera,\n\tappearance,\n\tsurface,\n\tpreparePipeline = (pipeline) => pipeline,\n\trenderTarget,\n}: {\n\troot: TgpuRoot\n\toptions: RaymarchProgramOptions\n\tcamera: () => RaymarchCamera\n\tappearance: RaymarchAppearance\n\tsurface: RaymarchSurface\n\tpreparePipeline?: (\n\t\tpipeline: TgpuRenderPipeline<{ color: Vec4f }>,\n\t) => TgpuRenderPipeline<{ color: Vec4f }>\n\trenderTarget?: Readonly<RaymarchRenderTargetOptions>\n}) {\n\tconst isRayVisible: RaymarchVisibilityTest =\n\t\tsurface.isRayVisible ??\n\t\t(() => {\n\t\t\t'use gpu'\n\t\t\treturn true\n\t\t})\n\n\tconst calculateNormal = createCalculateNormal({\n\t\tsdSurface: surface.sd,\n\t\tepsilonNormal: options.epsilonNormal ?? options.epsilon,\n\t})\n\n\tconst raymarch = createRaymarch({\n\t\tsdSurface: surface.sd,\n\t\tepsilon: options.epsilon,\n\t\tmaxSteps: options.maxSteps ?? 100,\n\t\tstepScale: options.stepScale ?? 1,\n\t\tmaxDistance: options.maxDistance,\n\t\tmarchBeyondBounds: options.marchBeyondBounds ?? false,\n\t})\n\n\tconst pipeline = preparePipeline(\n\t\troot.createRenderPipeline({\n\t\t\tmultisample: { count: renderTarget?.sampleCount },\n\t\t\tdepthStencil: {\n\t\t\t\tformat: renderTarget?.depthStencilFormat ?? 'depth24plus',\n\t\t\t\tdepthWriteEnabled: options.depthWriteEnabled ?? true,\n\t\t\t\tdepthCompare: options.depthCompare ?? 'less',\n\t\t\t},\n\t\t\tprimitive: { topology: 'triangle-list', cullMode: 'back' },\n\t\t\ttargets: {\n\t\t\t\tcolor: {\n\t\t\t\t\tformat: renderTarget?.colorFormat,\n\t\t\t\t\tblend: {\n\t\t\t\t\t\tcolor: {\n\t\t\t\t\t\t\tsrcFactor: 'src-alpha',\n\t\t\t\t\t\t\tdstFactor: 'one-minus-src-alpha',\n\t\t\t\t\t\t\toperation: 'add',\n\t\t\t\t\t\t},\n\t\t\t\t\t\talpha: {\n\t\t\t\t\t\t\tsrcFactor: 'one',\n\t\t\t\t\t\t\tdstFactor: 'one-minus-src-alpha',\n\t\t\t\t\t\t\toperation: 'add',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tvertex: tgpu.vertexFn({\n\t\t\t\tin: {\n\t\t\t\t\tvertexIdx: builtin.vertexIndex,\n\t\t\t\t\tinstanceIdx: builtin.instanceIndex,\n\t\t\t\t},\n\t\t\t\tout: {\n\t\t\t\t\tposition: builtin.position,\n\t\t\t\t\tworldPos: vec3f,\n\t\t\t\t\tinstanceIdx: interpolate('flat, either', u32),\n\t\t\t\t},\n\t\t\t})(({ vertexIdx, instanceIdx }) => {\n\t\t\t\t'use gpu'\n\n\t\t\t\tconst aabb = surface.bounds(instanceIdx)\n\t\t\t\tconst localPos = cubeVertices.$[vertexIdx]\n\t\t\t\tconst worldPos = aabbPoint(aabb, localPos)\n\t\t\t\tconst position = camera().viewProjectionMatrix * vec4f(worldPos, 1)\n\n\t\t\t\treturn {\n\t\t\t\t\tposition,\n\t\t\t\t\tworldPos,\n\t\t\t\t\tinstanceIdx,\n\t\t\t\t}\n\t\t\t}),\n\n\t\t\tfragment: ({ $position, worldPos, instanceIdx }) => {\n\t\t\t\t'use gpu'\n\n\t\t\t\tconst aabb = surface.bounds(instanceIdx)\n\t\t\t\tif (surface.init !== undefined) surface.init(instanceIdx)\n\t\t\t\tif (!isRayVisible(worldPos.xyz, instanceIdx, aabb)) discard()\n\n\t\t\t\tconst activeCamera = camera()\n\t\t\t\tconst hit = raymarch(activeCamera, worldPos.xyz, aabb, instanceIdx)\n\t\t\t\tlet normal = -1 * hit.rayDirection\n\n\t\t\t\tif (hit.isHit) {\n\t\t\t\t\tnormal = calculateNormal(hit.pos, aabb, instanceIdx)\n\t\t\t\t}\n\n\t\t\t\t// Appearance runs before the hit branch so it may use derivatives.\n\t\t\t\tconst color = appearance(\n\t\t\t\t\tRaymarchResult({\n\t\t\t\t\t\tisHit: hit.isHit,\n\t\t\t\t\t\tposition: hit.pos,\n\t\t\t\t\t\tnormal,\n\t\t\t\t\t\trayOrigin: activeCamera.position,\n\t\t\t\t\t\trayDirection: hit.rayDirection,\n\t\t\t\t\t\trayDistance: hit.rayDistance,\n\t\t\t\t\t\tstepCount: hit.stepCount,\n\t\t\t\t\t\tprojectedDepth: hit.depth,\n\t\t\t\t\t\tfragmentCoord: $position.xy,\n\t\t\t\t\t\tinstanceIndex: instanceIdx,\n\t\t\t\t\t\tbounds: aabb,\n\t\t\t\t\t}),\n\t\t\t\t)\n\n\t\t\t\tif (hit.isHit) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcolor,\n\t\t\t\t\t\t$fragDepth: hit.depth,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcolor: vec4f(),\n\t\t\t\t\t$fragDepth: 1,\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\t)\n\n\treturn function render({\n\t\tcolorAttachment,\n\t\tdepthStencilAttachment,\n\t\tinstances = 1,\n\t}: RaymarchRenderOptions) {\n\t\tpipeline\n\t\t\t.withColorAttachment({ color: colorAttachment })\n\t\t\t.withDepthStencilAttachment(depthStencilAttachment)\n\t\t\t.draw(cubeVertices.$.length, instances)\n\t}\n}\n\n/**\n * Creates a renderer for a raymarch program. It adds bounds rendering,\n * raymarching, normal calculation, appearance, depth, and draw submission to the\n * surface supplied by the program.\n *\n * Program preparation and pipeline compilation are repeated when the program\n * version changes, allowing shader HMR to use the updated callbacks.\n *\n * @returns A function that draws a requested number of raymarched instances.\n */\nexport function createRaymarchRenderer({\n\troot,\n\tprogram: programDefinition,\n\trenderTarget,\n\tprepare = (program) => program,\n\tpreparePipeline,\n}: {\n\troot: TgpuRoot\n\n\t/** Program providing pipeline options, a version, and shader callbacks. */\n\tprogram: Readonly<RaymarchProgramDefinition>\n\n\t/** Render target configuration used to create a compatible pipeline. */\n\trenderTarget?: Readonly<RaymarchRenderTargetOptions>\n\n\t/**\n\t * Optional program transformation applied before pipeline compilation.\n\t */\n\tprepare?: (program: RaymarchProgram) => RaymarchProgram\n\n\t/**\n\t * Optional pipeline transformation applied after pipeline creation and before\n\t * the pipeline is captured by the render function.\n\t */\n\tpreparePipeline?: (\n\t\tpipeline: TgpuRenderPipeline<{ color: Vec4f }>,\n\t) => TgpuRenderPipeline<{ color: Vec4f }>\n}) {\n\tfunction createRenderer() {\n\t\tconst { camera, surface, appearance } = prepare(programDefinition.program)\n\t\tconst renderer = createRaymarchPipeline({\n\t\t\troot,\n\t\t\toptions: programDefinition.options,\n\t\t\tsurface,\n\t\t\tcamera,\n\t\t\tappearance,\n\t\t\tpreparePipeline,\n\t\t\trenderTarget,\n\t\t})\n\n\t\treturn renderer\n\t}\n\n\tlet activeVersion = programDefinition.version\n\tlet activeRenderer = createRenderer()\n\n\treturn function renderRaymarchedInstances(options: RaymarchRenderOptions) {\n\t\tif (activeVersion !== programDefinition.version) {\n\t\t\tconst nextRenderer = createRenderer()\n\n\t\t\tactiveRenderer = nextRenderer\n\t\t\tactiveVersion = programDefinition.version\n\t\t}\n\n\t\tactiveRenderer(options)\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["axisExitDistance","direction","maximum","position","minimum","f32","\"params\"","\"type\"","\"name\"","\"body\"","\"f32\"","$","aabbExitDistance","min","point","aabb","\"min\"","\"axisExitDistance\"","aabbPoint","select","vec3b","corner","\"select\"","\"vec3b\"","AABB","a","struct","vec3f","RaymarchDirectionalLight","fallbackDirectionalLights","createRaymarchLightingStruct","capacity","arrayOf","createRaymarchConstantLighting","directionalLights","lighting","RaymarchConstantLighting","\"ambient\"","\"directionalLights\"","\"RaymarchConstantLighting\"","RaymarchCamera","mat4x4f","RaymarchResult","bool","u32","vec2f","HOT_DATA_KEY","createRaymarchProgram","options","create","createOrHot","input","directOptions","program","definition","hot","cubeVertices","tgpu","RayHit","createRaymarch","triangleDifference","worldPosition","camera","triangleDistance","length","rayDirection","normalize","marchedDistance","stepCount","marchLimit","marchBeyondBounds","maxDistance","stepIndex","maxSteps","distance","sdSurface","instanceIndex","epsilon","hitClipPosition","vec4f","stepScale","\"isHit\"","\"pos\"","\"depth\"","\"rayDirection\"","\"rayDistance\"","\"stepCount\"","\"length\"","\"normalize\"","\"u32\"","\"aabbExitDistance\"","\"marchBeyondBounds\"","\"maxDistance\"","\"undefined\"","\"maxSteps\"","\"sdSurface\"","\"epsilon\"","\"vec4f\"","\"RayHit\"","\"stepScale\"","createCalculateNormal","k","epsilonNormal","\"vec2f\"","\"epsilonNormal\"","createRaymarchPipeline","pipeline","isRayVisible","surface","calculateNormal","raymarch","preparePipeline","root","renderTarget","builtin","interpolate","instanceIdx","localPos","vertexIdx","worldPos","\"props\"","\"alias\"","\"position\"","\"worldPos\"","\"instanceIdx\"","\"cubeVertices\"","\"aabbPoint\"","\"camera\"","discard","activeCamera","hit","normal","color","appearance","$position","\"normal\"","\"rayOrigin\"","\"projectedDepth\"","\"fragmentCoord\"","\"instanceIndex\"","\"bounds\"","\"color\"","\"$fragDepth\"","\"isRayVisible\"","\"discard\"","\"raymarch\"","\"calculateNormal\"","\"appearance\"","\"RaymarchResult\"","colorAttachment","depthStencilAttachment","instances","createRaymarchRenderer","programDefinition","createRenderer","prepare","context","activeVersion","activeRenderer"],"sources":["../src/aabb.ts","../src/lighting.ts","../src/program.ts","../src/cube-vertices.ts","../src/renderer.ts"],"sourcesContent":["import { f32, type Infer, struct, type v3f, vec3b, vec3f } from 'typegpu/data'\nimport { min, select } from 'typegpu/std'\n\nexport const AABB = struct({\n\tmin: vec3f,\n\tmax: vec3f,\n})\nexport type AABB = Infer<typeof AABB>\n\nexport function aabbPoint(aabb: AABB, corner: v3f): v3f {\n\t'use gpu'\n\treturn select(\n\t\taabb.min,\n\t\taabb.max,\n\t\tvec3b(corner.x > 0, corner.y > 0, corner.z > 0),\n\t)\n}\n\nexport function aabbCenter(aabb: AABB): v3f {\n\t'use gpu'\n\treturn (aabb.min + aabb.max) * 0.5\n}\n\nexport function aabbExitDistance(\n\taabb: AABB,\n\tpoint: v3f,\n\tdirection: v3f,\n): number {\n\t'use gpu'\n\n\treturn min(\n\t\taxisExitDistance(point.x, direction.x, aabb.min.x, aabb.max.x),\n\t\tmin(\n\t\t\taxisExitDistance(point.y, direction.y, aabb.min.y, aabb.max.y),\n\t\t\taxisExitDistance(point.z, direction.z, aabb.min.z, aabb.max.z),\n\t\t),\n\t)\n}\n\nfunction axisExitDistance(\n\tposition: number,\n\tdirection: number,\n\tminimum: number,\n\tmaximum: number,\n): number {\n\t'use gpu'\n\n\tif (direction > 0) return (maximum - position) / direction\n\tif (direction < 0) return (minimum - position) / direction\n\treturn f32(1e9)\n}\n","import { arrayOf, f32, type Infer, struct, vec3f } from 'typegpu/data'\n\n/** Shared GPU schema for a directional light used by lit appearances. */\nexport const RaymarchDirectionalLight = struct({\n\t/** Nonzero world-space direction of travel; normalized during shading. */\n\tdirection: vec3f,\n\n\t/** Linear RGB light color. */\n\tcolor: vec3f,\n\n\t/** Brightness multiplier; zero disables the light. */\n\tintensity: f32,\n})\n\n/** Directional-light values accepted by lighting providers. */\nexport type RaymarchDirectionalLight = Infer<typeof RaymarchDirectionalLight>\n\nconst fallbackDirectionalLights = [\n\tRaymarchDirectionalLight({\n\t\tdirection: vec3f(0, -1, 0),\n\t\tcolor: vec3f(0),\n\t\tintensity: 0,\n\t}),\n]\n\n/**\n * Creates a GPU lighting schema with a fixed number of light slots.\n * @throws {RangeError} If capacity is not a positive integer.\n */\nfunction createRaymarchLightingStruct(capacity: number) {\n\tif (!Number.isInteger(capacity) || capacity < 1) {\n\t\tthrow new RangeError('Lighting capacity must be a positive integer.')\n\t}\n\n\treturn struct({\n\t\t/** Additive linear RGB diffuse fill; black adds no ambient illumination. */\n\t\tambient: vec3f,\n\n\t\t/** Directional lights evaluated independently and added together. */\n\t\tdirectionalLights: arrayOf(RaymarchDirectionalLight, capacity),\n\t})\n}\n/** Ambient fill and directional-light values returned by a GPU lighting provider. */\nexport type RaymarchLighting = Infer<\n\tReturnType<typeof createRaymarchLightingStruct>\n>\n\n/**\n * Creates a GPU lighting callback with values embedded during shader compilation.\n * Infers capacity from directionalLights; an empty list uses one disabled slot.\n */\nexport function createRaymarchConstantLighting(lighting: RaymarchLighting) {\n\tconst directionalLights =\n\t\tlighting.directionalLights.length > 0\n\t\t\t? lighting.directionalLights\n\t\t\t: fallbackDirectionalLights\n\n\tconst RaymarchConstantLighting = createRaymarchLightingStruct(\n\t\tdirectionalLights.length,\n\t)\n\n\treturn function raymarchLighting() {\n\t\t'use gpu'\n\t\treturn RaymarchConstantLighting({\n\t\t\tambient: lighting.ambient,\n\t\t\tdirectionalLights: directionalLights,\n\t\t})\n\t}\n}\n","import {\n\tbool,\n\tf32,\n\ttype Infer,\n\tmat4x4f,\n\tstruct,\n\tu32,\n\ttype v3f,\n\ttype v4f,\n\tvec2f,\n\tvec3f,\n} from 'typegpu/data'\nimport { AABB } from './aabb'\n\nexport const RaymarchCamera = struct({\n\tposition: vec3f,\n\tviewProjectionMatrix: mat4x4f,\n})\nexport type RaymarchCamera = Infer<typeof RaymarchCamera>\n\n/** Result of the primary ray march, with data available for appearance. */\nexport const RaymarchResult = struct({\n\t/** Whether the primary ray reached the surface within the march limits. */\n\tisHit: bool,\n\t/** Hit position, or the final ray sample position on a miss, in world space. */\n\tposition: vec3f,\n\t/** Outward surface normal on a hit; -rayDirection on a miss. */\n\tnormal: vec3f,\n\t/** Camera position in world space. */\n\trayOrigin: vec3f,\n\t/** Unit direction from the camera into the scene. */\n\trayDirection: vec3f,\n\t/** World-space distance from rayOrigin to position. */\n\trayDistance: f32,\n\t/** Number of primary ray-march iterations, excluding normal/shadow samples. */\n\tstepCount: u32,\n\t/** Projected depth written for a hit; 1 on a miss. */\n\tprojectedDepth: f32,\n\t/** Pixel-space fragment coordinates, with pixel centers at half-integers. */\n\tfragmentCoord: vec2f,\n\t/** Index of the bounds instance being rendered. */\n\tinstanceIndex: u32,\n\t/** World-space bounds for this instance. */\n\tbounds: AABB,\n})\nexport type RaymarchResult = Infer<typeof RaymarchResult>\n\n/**\n * GPU function calculating unpremultiplied linear RGB and opacity for every\n * visible fragment after marching. Alpha is opacity in [0, 1]. The renderer uses\n * the result only on hits and writes surface depth regardless of alpha, subject\n * to the program's depth settings. Derivative-dependent work must run outside\n * hit-dependent branches.\n */\nexport type RaymarchAppearance = (result: RaymarchResult) => v4f\n\nexport type RaymarchBoundsProvider = (instanceIdx: number) => AABB\n\nexport type RaymarchInitializer = (instanceIdx: number) => void\n\nexport type RaymarchVisibilityTest = (\n\trayPoint: v3f,\n\tinstanceIdx: number,\n\tbounds: AABB,\n) => boolean\n\nexport type RaymarchDistanceFunction = (\n\tpoint: v3f,\n\tinstanceIdx: number,\n\taabb: AABB,\n) => number\n\nexport type RaymarchProgramOptions = {\n\t/** Diagnostic metadata for consumers. Unused by the renderer. */\n\tlabel?: string\n\t/** Surface hit tolerance in world units. */\n\tepsilon: number\n\t/** Normal sampling offset; defaults to epsilon. */\n\tepsilonNormal?: number\n\t/** Maximum number of marching steps per ray; defaults to 100. */\n\tmaxSteps?: number\n\t/**\n\t * Multiplier applied to each raymarch step; defaults to 1.\n\t * Values between 0 and 1 reduce overshooting from domain warping at the cost\n\t * of more marching steps.\n\t */\n\tstepScale?: number\n\t/** Write surface hit depth to the depth buffer; defaults to true. */\n\tdepthWriteEnabled?: boolean\n\t/** Comparison used to test surface hit depth against the depth buffer; defaults to 'less'. */\n\tdepthCompare?: GPUCompareFunction\n} & (\n\t| {\n\t\t\t/** Allow marching past the bounding-box exit. Defaults to false; requires maxDistance when true. */\n\t\t\tmarchBeyondBounds?: false\n\t\t\t/** Maximum distance to march from the bounding-box entry point, in world units. */\n\t\t\tmaxDistance?: number\n\t }\n\t| {\n\t\t\t/** Allow marching past the bounding-box exit. Defaults to false; requires maxDistance when true. */\n\t\t\tmarchBeyondBounds: true\n\t\t\t/** Maximum distance to march from the bounding-box entry point, in world units. */\n\t\t\tmaxDistance: number\n\t }\n)\n\n/** Geometry and visibility callbacks compiled into a raymarching pipeline. */\nexport interface RaymarchSurface {\n\t/** GPU function initializing per-fragment state before raymarching. */\n\tinit?: RaymarchInitializer\n\n\t/** GPU function providing each instance's axis-aligned bounding box. */\n\tbounds: RaymarchBoundsProvider\n\n\t/**\n\t * GPU function masking out rays that should not render. Returning false\n\t * skips raymarching for that fragment.\n\t */\n\tisRayVisible?: RaymarchVisibilityTest\n\n\t/** GPU function returning the signed distance from a point to the surface. */\n\tsd: RaymarchDistanceFunction\n}\n\n/** Camera, geometry, and appearance compiled into one raymarching pipeline. */\nexport interface RaymarchProgram {\n\t/** GPU function providing the current camera state. */\n\tcamera: () => RaymarchCamera\n\n\t/** Surface bounds, signed distance, and optional visibility behavior. */\n\tsurface: RaymarchSurface\n\n\t/** GPU function returning unpremultiplied linear RGB and opacity for the raymarch result. */\n\tappearance: RaymarchAppearance\n}\n\n/** Versioned program factory with its pipeline compilation options. */\nexport interface RaymarchProgramDefinition<TContext = undefined> {\n\tversion: number\n\toptions: RaymarchProgramOptions\n\tcreate: (context: TContext) => RaymarchProgram\n}\n\n/** Minimal hot-module context used to retain a program across reevaluations. */\nexport interface RaymarchHotContext {\n\tdata: Record<string, unknown>\n}\n\nconst HOT_DATA_KEY = 'raymarchProgramDefinition'\n\n/**\n * Creates a versioned program definition without allocating GPU resources. It\n * stores a factory for surface, camera, and appearance callbacks,\n * and the options used to compile them into a raymarching pipeline. Callbacks\n * may read changing buffer data without rebuilding the pipeline.\n *\n * ```ts\n * const program = createRaymarchProgram({ ...program, options })\n * const dependentProgram = createRaymarchProgram(options, (context: Context) => ({ ...callbacks }))\n * ```\n *\n * ## Vite Hot Reloading\n *\n * When `hot` is provided, reevaluating the module updates the existing program\n * definition and increments its version. Renderer instances observe that\n * version and rerun the factory with each renderer's existing context before\n * rebuilding its pipeline. Factories run during renderer setup and rebuilding,\n * not on every draw. Caller-owned resources should be created outside the factory.\n * The defining module must call `import.meta.hot?.accept()` for this behavior, and\n * may currently define only one HMR-backed raymarch program.\n *\n * ```ts\n * const program = createRaymarchProgram({ ...program, options }, import.meta.hot)\n * import.meta.hot?.accept()\n * ```\n *\n * @returns A read-only program definition consumed by raymarch renderer factories.\n */\nexport function createRaymarchProgram(\n\tprogram: RaymarchProgram & { options: RaymarchProgramOptions },\n\thot?: RaymarchHotContext,\n): Readonly<RaymarchProgramDefinition>\n\nexport function createRaymarchProgram<TContext = undefined>(\n\toptions: RaymarchProgramOptions,\n\tcreate: (context: TContext) => RaymarchProgram,\n\thot?: RaymarchHotContext,\n): Readonly<RaymarchProgramDefinition<TContext>>\n\nexport function createRaymarchProgram<TContext = undefined>(\n\tinput:\n\t\t| RaymarchProgramOptions\n\t\t| (RaymarchProgram & { options: RaymarchProgramOptions }),\n\tcreateOrHot?: ((context: TContext) => RaymarchProgram) | RaymarchHotContext,\n\thot?: RaymarchHotContext,\n): Readonly<RaymarchProgramDefinition<TContext>> {\n\tlet options: RaymarchProgramOptions\n\tlet create: (context: TContext) => RaymarchProgram\n\tif (typeof createOrHot === 'function') {\n\t\toptions = input as RaymarchProgramOptions\n\t\tcreate = createOrHot\n\t} else {\n\t\tconst { options: directOptions, ...program } = input as RaymarchProgram & {\n\t\t\toptions: RaymarchProgramOptions\n\t\t}\n\t\toptions = directOptions\n\t\tcreate = () => program\n\t\thot = createOrHot\n\t}\n\n\tconst definition = (hot?.data[HOT_DATA_KEY] as\n\t\t| RaymarchProgramDefinition<TContext>\n\t\t| undefined) ?? { version: 0, options, create }\n\n\tdefinition.version += 1\n\tdefinition.options = options\n\tdefinition.create = create\n\tif (hot) hot.data[HOT_DATA_KEY] = definition\n\n\treturn definition\n}\n","import { tgpu } from 'typegpu'\nimport { arrayOf, vec3f } from 'typegpu/data'\n\nexport const cubeVertices = tgpu.const(arrayOf(vec3f, 36), [\n\tvec3f(0, 0, 1),\n\tvec3f(1, 0, 1),\n\tvec3f(1, 1, 1),\n\tvec3f(1, 1, 1),\n\tvec3f(0, 1, 1),\n\tvec3f(0, 0, 1),\n\tvec3f(1, 0, 0),\n\tvec3f(0, 0, 0),\n\tvec3f(0, 1, 0),\n\tvec3f(0, 1, 0),\n\tvec3f(1, 1, 0),\n\tvec3f(1, 0, 0),\n\tvec3f(0, 1, 1),\n\tvec3f(1, 1, 1),\n\tvec3f(1, 1, 0),\n\tvec3f(1, 1, 0),\n\tvec3f(0, 1, 0),\n\tvec3f(0, 1, 1),\n\tvec3f(0, 0, 0),\n\tvec3f(1, 0, 0),\n\tvec3f(1, 0, 1),\n\tvec3f(1, 0, 1),\n\tvec3f(0, 0, 1),\n\tvec3f(0, 0, 0),\n\tvec3f(1, 0, 1),\n\tvec3f(1, 0, 0),\n\tvec3f(1, 1, 0),\n\tvec3f(1, 1, 0),\n\tvec3f(1, 1, 1),\n\tvec3f(1, 0, 1),\n\tvec3f(0, 0, 0),\n\tvec3f(0, 0, 1),\n\tvec3f(0, 1, 1),\n\tvec3f(0, 1, 1),\n\tvec3f(0, 1, 0),\n\tvec3f(0, 0, 0),\n])\n","import {\n\ttype ColorAttachment,\n\ttype DepthStencilAttachment,\n\ttype TgpuRenderPipeline,\n\ttype TgpuRoot,\n\ttgpu,\n} from 'typegpu'\nimport {\n\tbool,\n\tbuiltin,\n\tf32,\n\ttype Infer,\n\tinterpolate,\n\tstruct,\n\tu32,\n\ttype Vec4f,\n\ttype v3f,\n\tvec2f,\n\tvec3f,\n\tvec4f,\n} from 'typegpu/data'\nimport { discard, length, min, normalize } from 'typegpu/std'\nimport { type AABB, aabbExitDistance, aabbPoint } from './aabb'\nimport { cubeVertices } from './cube-vertices'\nimport {\n\ttype RaymarchAppearance,\n\ttype RaymarchCamera,\n\ttype RaymarchDistanceFunction,\n\ttype RaymarchProgram,\n\ttype RaymarchProgramDefinition,\n\ttype RaymarchProgramOptions,\n\tRaymarchResult,\n\ttype RaymarchSurface,\n\ttype RaymarchVisibilityTest,\n} from './program'\n\nexport interface RaymarchRenderTargetOptions {\n\t/**\n\t * Format of the color attachment.\n\t * @default navigator.gpu.getPreferredCanvasFormat()\n\t */\n\tcolorFormat?: GPUTextureFormat\n\n\t/**\n\t * Format of the depth/stencil attachment.\n\t * @default 'depth24plus'\n\t */\n\tdepthStencilFormat?: Extract<GPUTextureFormat, `depth${string}`>\n\n\t/**\n\t * Number of samples per pixel in each attachment.\n\t * @default 1\n\t */\n\tsampleCount?: 1 | 4\n}\n\n/** Attachments and instance count for one raymarch draw submission. */\nexport interface RaymarchRenderOptions {\n\tcolorAttachment: ColorAttachment\n\tdepthStencilAttachment: DepthStencilAttachment\n\t/** @default 1 */\n\tinstances?: number\n}\n\nconst RayHit = struct({\n\tisHit: bool,\n\tpos: vec3f,\n\tdepth: f32,\n\trayDirection: vec3f,\n\trayDistance: f32,\n\tstepCount: u32,\n})\ntype RayHit = Infer<typeof RayHit>\n\nfunction createRaymarch({\n\tsdSurface,\n\tmaxSteps,\n\tstepScale,\n\tmaxDistance,\n\tepsilon,\n\tmarchBeyondBounds,\n}: {\n\tsdSurface: RaymarchDistanceFunction\n\tmaxSteps: number\n\tstepScale: number\n\tmaxDistance?: number\n\tepsilon: number\n\tmarchBeyondBounds: boolean\n}) {\n\treturn function raymarch(\n\t\tcamera: RaymarchCamera,\n\t\tworldPosition: v3f,\n\t\taabb: AABB,\n\t\tinstanceIndex: number,\n\t): RayHit {\n\t\t'use gpu'\n\t\tconst triangleDifference = worldPosition.xyz - camera.position\n\t\tconst triangleDistance = length(triangleDifference)\n\t\tconst rayDirection = normalize(triangleDifference)\n\n\t\tlet marchedDistance = f32(0)\n\t\tlet point = camera.position + rayDirection * triangleDistance\n\t\tlet stepCount = u32(0)\n\n\t\tlet marchLimit = aabbExitDistance(aabb, point, rayDirection)\n\t\tif (marchBeyondBounds) {\n\t\t\tmarchLimit = f32(maxDistance ?? 0)\n\t\t} else if (maxDistance !== undefined) {\n\t\t\tmarchLimit = min(marchLimit, maxDistance)\n\t\t}\n\n\t\tfor (let stepIndex = 0; stepIndex < maxSteps; stepIndex++) {\n\t\t\tif (marchedDistance > marchLimit) break\n\t\t\tstepCount += 1\n\n\t\t\tpoint =\n\t\t\t\tcamera.position + rayDirection * (triangleDistance + marchedDistance)\n\n\t\t\tconst distance = sdSurface(point, instanceIndex, aabb)\n\n\t\t\tif (distance < epsilon) {\n\t\t\t\tconst hitClipPosition = camera.viewProjectionMatrix * vec4f(point, 1)\n\n\t\t\t\treturn RayHit({\n\t\t\t\t\tisHit: true,\n\t\t\t\t\tpos: point,\n\t\t\t\t\tdepth: hitClipPosition.z / hitClipPosition.w,\n\t\t\t\t\trayDirection,\n\t\t\t\t\trayDistance: triangleDistance + marchedDistance,\n\t\t\t\t\tstepCount,\n\t\t\t\t})\n\t\t\t}\n\t\t\tmarchedDistance += distance * stepScale\n\t\t}\n\n\t\treturn RayHit({\n\t\t\tisHit: false,\n\t\t\tpos: point,\n\t\t\tdepth: 1,\n\t\t\trayDirection,\n\t\t\trayDistance: length(point - camera.position),\n\t\t\tstepCount,\n\t\t})\n\t}\n}\n\nfunction createCalculateNormal({\n\tsdSurface,\n\tepsilonNormal,\n}: {\n\tsdSurface: RaymarchDistanceFunction\n\tepsilonNormal: number\n}) {\n\treturn function calculateNormal(\n\t\tpoint: v3f,\n\t\taabb: AABB,\n\t\tinstanceIndex: number,\n\t): v3f {\n\t\t'use gpu'\n\t\tconst k = vec2f(1, -1)\n\t\treturn normalize(\n\t\t\tk.xyy * sdSurface(point + k.xyy * epsilonNormal, instanceIndex, aabb) +\n\t\t\t\t(k.yyx * sdSurface(point + k.yyx * epsilonNormal, instanceIndex, aabb) +\n\t\t\t\t\t(k.yxy *\n\t\t\t\t\t\tsdSurface(point + k.yxy * epsilonNormal, instanceIndex, aabb) +\n\t\t\t\t\t\tk.xxx *\n\t\t\t\t\t\t\tsdSurface(point + k.xxx * epsilonNormal, instanceIndex, aabb))),\n\t\t)\n\t}\n}\n\n/**\n * Creates a GPU pipeline that renders a raymarched surface.\n *\n * @returns A function that draws the requested number of instances.\n */\nfunction createRaymarchPipeline({\n\troot,\n\toptions,\n\tcamera,\n\tappearance,\n\tsurface,\n\tpreparePipeline = (pipeline) => pipeline,\n\trenderTarget,\n}: {\n\troot: TgpuRoot\n\toptions: RaymarchProgramOptions\n\tcamera: () => RaymarchCamera\n\tappearance: RaymarchAppearance\n\tsurface: RaymarchSurface\n\tpreparePipeline?: (\n\t\tpipeline: TgpuRenderPipeline<{ color: Vec4f }>,\n\t) => TgpuRenderPipeline<{ color: Vec4f }>\n\trenderTarget?: Readonly<RaymarchRenderTargetOptions>\n}) {\n\tconst isRayVisible: RaymarchVisibilityTest =\n\t\tsurface.isRayVisible ??\n\t\t(() => {\n\t\t\t'use gpu'\n\t\t\treturn true\n\t\t})\n\n\tconst calculateNormal = createCalculateNormal({\n\t\tsdSurface: surface.sd,\n\t\tepsilonNormal: options.epsilonNormal ?? options.epsilon,\n\t})\n\n\tconst raymarch = createRaymarch({\n\t\tsdSurface: surface.sd,\n\t\tepsilon: options.epsilon,\n\t\tmaxSteps: options.maxSteps ?? 100,\n\t\tstepScale: options.stepScale ?? 1,\n\t\tmaxDistance: options.maxDistance,\n\t\tmarchBeyondBounds: options.marchBeyondBounds ?? false,\n\t})\n\n\tconst pipeline = preparePipeline(\n\t\troot.createRenderPipeline({\n\t\t\tmultisample: { count: renderTarget?.sampleCount },\n\t\t\tdepthStencil: {\n\t\t\t\tformat: renderTarget?.depthStencilFormat ?? 'depth24plus',\n\t\t\t\tdepthWriteEnabled: options.depthWriteEnabled ?? true,\n\t\t\t\tdepthCompare: options.depthCompare ?? 'less',\n\t\t\t},\n\t\t\tprimitive: { topology: 'triangle-list', cullMode: 'back' },\n\t\t\ttargets: {\n\t\t\t\tcolor: {\n\t\t\t\t\tformat: renderTarget?.colorFormat,\n\t\t\t\t\tblend: {\n\t\t\t\t\t\tcolor: {\n\t\t\t\t\t\t\tsrcFactor: 'src-alpha',\n\t\t\t\t\t\t\tdstFactor: 'one-minus-src-alpha',\n\t\t\t\t\t\t\toperation: 'add',\n\t\t\t\t\t\t},\n\t\t\t\t\t\talpha: {\n\t\t\t\t\t\t\tsrcFactor: 'one',\n\t\t\t\t\t\t\tdstFactor: 'one-minus-src-alpha',\n\t\t\t\t\t\t\toperation: 'add',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tvertex: tgpu.vertexFn({\n\t\t\t\tin: {\n\t\t\t\t\tvertexIdx: builtin.vertexIndex,\n\t\t\t\t\tinstanceIdx: builtin.instanceIndex,\n\t\t\t\t},\n\t\t\t\tout: {\n\t\t\t\t\tposition: builtin.position,\n\t\t\t\t\tworldPos: vec3f,\n\t\t\t\t\tinstanceIdx: interpolate('flat, either', u32),\n\t\t\t\t},\n\t\t\t})(({ vertexIdx, instanceIdx }) => {\n\t\t\t\t'use gpu'\n\n\t\t\t\tconst aabb = surface.bounds(instanceIdx)\n\t\t\t\tconst localPos = cubeVertices.$[vertexIdx]\n\t\t\t\tconst worldPos = aabbPoint(aabb, localPos)\n\t\t\t\tconst position = camera().viewProjectionMatrix * vec4f(worldPos, 1)\n\n\t\t\t\treturn {\n\t\t\t\t\tposition,\n\t\t\t\t\tworldPos,\n\t\t\t\t\tinstanceIdx,\n\t\t\t\t}\n\t\t\t}),\n\n\t\t\tfragment: ({ $position, worldPos, instanceIdx }) => {\n\t\t\t\t'use gpu'\n\n\t\t\t\tconst aabb = surface.bounds(instanceIdx)\n\t\t\t\tif (surface.init !== undefined) surface.init(instanceIdx)\n\t\t\t\tif (!isRayVisible(worldPos.xyz, instanceIdx, aabb)) discard()\n\n\t\t\t\tconst activeCamera = camera()\n\t\t\t\tconst hit = raymarch(activeCamera, worldPos.xyz, aabb, instanceIdx)\n\t\t\t\tlet normal = -1 * hit.rayDirection\n\n\t\t\t\tif (hit.isHit) {\n\t\t\t\t\tnormal = calculateNormal(hit.pos, aabb, instanceIdx)\n\t\t\t\t}\n\n\t\t\t\t// Appearance runs before the hit branch so it may use derivatives.\n\t\t\t\tconst color = appearance(\n\t\t\t\t\tRaymarchResult({\n\t\t\t\t\t\tisHit: hit.isHit,\n\t\t\t\t\t\tposition: hit.pos,\n\t\t\t\t\t\tnormal,\n\t\t\t\t\t\trayOrigin: activeCamera.position,\n\t\t\t\t\t\trayDirection: hit.rayDirection,\n\t\t\t\t\t\trayDistance: hit.rayDistance,\n\t\t\t\t\t\tstepCount: hit.stepCount,\n\t\t\t\t\t\tprojectedDepth: hit.depth,\n\t\t\t\t\t\tfragmentCoord: $position.xy,\n\t\t\t\t\t\tinstanceIndex: instanceIdx,\n\t\t\t\t\t\tbounds: aabb,\n\t\t\t\t\t}),\n\t\t\t\t)\n\n\t\t\t\tif (hit.isHit) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcolor,\n\t\t\t\t\t\t$fragDepth: hit.depth,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcolor: vec4f(),\n\t\t\t\t\t$fragDepth: 1,\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\t)\n\n\treturn function render({\n\t\tcolorAttachment,\n\t\tdepthStencilAttachment,\n\t\tinstances = 1,\n\t}: RaymarchRenderOptions) {\n\t\tpipeline\n\t\t\t.withColorAttachment({ color: colorAttachment })\n\t\t\t.withDepthStencilAttachment(depthStencilAttachment)\n\t\t\t.draw(cubeVertices.$.length, instances)\n\t}\n}\n\n/**\n * Creates a renderer for a raymarch program. It adds bounds rendering,\n * raymarching, normal calculation, appearance, depth, and draw submission to the\n * surface supplied by the program.\n *\n * Program creation, preparation, and pipeline compilation are repeated when the\n * program version changes, using the updated factory with the same context.\n *\n * @returns A function that draws a requested number of raymarched instances.\n */\nexport function createRaymarchRenderer<TContext = undefined>({\n\troot,\n\tprogram: programDefinition,\n\tcontext = undefined as TContext,\n\trenderTarget,\n\tprepare = (program) => program,\n\tpreparePipeline,\n}: {\n\troot: TgpuRoot\n\n\t/** Program providing pipeline options, a version, and a shader factory. */\n\tprogram: Readonly<RaymarchProgramDefinition<TContext>>\n\n\t/** Render target configuration used to create a compatible pipeline. */\n\trenderTarget?: Readonly<RaymarchRenderTargetOptions>\n\n\t/**\n\t * Optional program transformation applied before pipeline compilation.\n\t */\n\tprepare?: (program: RaymarchProgram) => RaymarchProgram\n\n\t/**\n\t * Optional pipeline transformation applied after pipeline creation and before\n\t * the pipeline is captured by the render function.\n\t */\n\tpreparePipeline?: (\n\t\tpipeline: TgpuRenderPipeline<{ color: Vec4f }>,\n\t) => TgpuRenderPipeline<{ color: Vec4f }>\n} & (undefined extends NoInfer<TContext>\n\t? { context?: NoInfer<TContext> }\n\t: { context: NoInfer<TContext> })) {\n\tfunction createRenderer() {\n\t\tconst { camera, surface, appearance } = prepare(\n\t\t\tprogramDefinition.create(context),\n\t\t)\n\t\tconst renderer = createRaymarchPipeline({\n\t\t\troot,\n\t\t\toptions: programDefinition.options,\n\t\t\tsurface,\n\t\t\tcamera,\n\t\t\tappearance,\n\t\t\tpreparePipeline,\n\t\t\trenderTarget,\n\t\t})\n\n\t\treturn renderer\n\t}\n\n\tlet activeVersion = programDefinition.version\n\tlet activeRenderer = createRenderer()\n\n\treturn function renderRaymarchedInstances(options: RaymarchRenderOptions) {\n\t\tif (activeVersion !== programDefinition.version) {\n\t\t\tconst nextRenderer = createRenderer()\n\n\t\t\tactiveRenderer = nextRenderer\n\t\t\tactiveVersion = programDefinition.version\n\t\t}\n\n\t\tactiveRenderer(options)\n\t}\n}\n"],"mappings":"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"}
|
package/dist/matte.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matte.js","names":[],"sources":["../src/appearances/matte.ts"],"sourcesContent":["import { type v4f, vec3f, vec4f } from 'typegpu/data'\nimport { dot, normalize, saturate } from 'typegpu/std'\nimport type { RaymarchLighting } from '../lighting'\nimport type { RaymarchAppearance, RaymarchResult } from '../program'\n\n/** GPU function sampling unpremultiplied linear RGB with alpha as opacity in [0, 1]. */\nexport type MatteColorSampler = (result: RaymarchResult) => v4f\n\n/**\n * Creates a matte appearance using ambient fill and Lambert diffuse lighting.\n * Surfaces facing a light receive its full contribution, with no shiny highlights.\n * Lighting affects RGB only; the sampled alpha passes through as opacity.\n *\n * Color sampling runs for hits and misses so derivatives remain available.\n * Lighting runs only for hits. Colors and lighting values are linear RGB.\n */\nexport function createMatteAppearance({\n\tcolor,\n\tlighting,\n}: {\n\tcolor: MatteColorSampler\n\tlighting: () => RaymarchLighting\n}): RaymarchAppearance {\n\treturn function matteAppearance(result: RaymarchResult): v4f {\n\t\t'use gpu'\n\t\tconst surfaceColor = color(result)\n\t\tif (!result.isHit) return vec4f(0)\n\n\t\tconst lights = lighting()\n\t\tlet illumination = vec3f(lights.ambient)\n\t\tfor (const light of lights.directionalLights) {\n\t\t\tif (light.intensity === 0) continue\n\n\t\t\tconst lightDirection = -1 * normalize(light.direction)\n\t\t\tconst diffuse = saturate(dot(result.normal, lightDirection))\n\t\t\tillumination += light.color * light.intensity * diffuse\n\t\t}\n\n\t\treturn vec4f(surfaceColor.rgb * illumination, surfaceColor.a)\n\t}\n}\n"],"mappings":";;;AAgBA,
|
|
1
|
+
{"version":3,"file":"matte.js","names":["createMatteAppearance","surfaceColor","color","result","vec4f","lights","lighting","illumination","vec3f","light","lightDirection","normalize","diffuse","saturate","dot","\"params\"","\"type\"","\"name\"","\"body\"","\"color\"","\"vec4f\"","\"lighting\"","\"vec3f\"","\"normalize\"","\"saturate\"","\"dot\"","$"],"sources":["../src/appearances/matte.ts"],"sourcesContent":["import { type v4f, vec3f, vec4f } from 'typegpu/data'\nimport { dot, normalize, saturate } from 'typegpu/std'\nimport type { RaymarchLighting } from '../lighting'\nimport type { RaymarchAppearance, RaymarchResult } from '../program'\n\n/** GPU function sampling unpremultiplied linear RGB with alpha as opacity in [0, 1]. */\nexport type MatteColorSampler = (result: RaymarchResult) => v4f\n\n/**\n * Creates a matte appearance using ambient fill and Lambert diffuse lighting.\n * Surfaces facing a light receive its full contribution, with no shiny highlights.\n * Lighting affects RGB only; the sampled alpha passes through as opacity.\n *\n * Color sampling runs for hits and misses so derivatives remain available.\n * Lighting runs only for hits. Colors and lighting values are linear RGB.\n */\nexport function createMatteAppearance({\n\tcolor,\n\tlighting,\n}: {\n\tcolor: MatteColorSampler\n\tlighting: () => RaymarchLighting\n}): RaymarchAppearance {\n\treturn function matteAppearance(result: RaymarchResult): v4f {\n\t\t'use gpu'\n\t\tconst surfaceColor = color(result)\n\t\tif (!result.isHit) return vec4f(0)\n\n\t\tconst lights = lighting()\n\t\tlet illumination = vec3f(lights.ambient)\n\t\tfor (const light of lights.directionalLights) {\n\t\t\tif (light.intensity === 0) continue\n\n\t\t\tconst lightDirection = -1 * normalize(light.direction)\n\t\t\tconst diffuse = saturate(dot(result.normal, lightDirection))\n\t\t\tillumination += light.color * light.intensity * diffuse\n\t\t}\n\n\t\treturn vec4f(surfaceColor.rgb * illumination, surfaceColor.a)\n\t}\n}\n"],"mappings":";;;AAgBA,SAAgBA,EAAsB,EACrC,UACA,eAIsB;CACtB,OAAO,gBAAA,OAAA,WAAA,qCAAA,IAAA,QAAA,EAAA,CAAA,IAAA,EAAA,KAAA,SAAA,GAAA;EAAA;EAAA,IAAAC,IAAAC,EAAAC,CAAA;EAAA,IAAA,CAAAA,EAAA,OAAA,OAAAC,EAAA,CAAA;EAAA,IAAAC,IAAAC,EAAA,GAAAC,IAAAC,EAAAH,EAAA,OAAA;EAAA,KAAA,IAAAI,KAAAJ,EAAA,mBAAA;GAAA,IAAAI,EAAA,cAAA,GAAA;GAAA,IAAAC,IAAA,aAAA,IAAAC,EAAAF,EAAA,SAAA,CAAA,GAAAG,IAAAC,EAAAC,EAAAX,EAAA,QAAAO,CAAA,CAAA;GAAA,IAAA,aAAAH,GAAA,aAAA,aAAAE,EAAA,OAAAA,EAAA,SAAA,GAAAG,CAAA,CAAA;EAAA;EAAA,OAAAR,EAAA,aAAAH,EAAA,KAAAM,CAAA,GAAAN,EAAA,CAAA;CAAA,IAAA;EAAA,GAAA;EAAA,MAAA;EAAA,KAAA;GAAAc,QAAA,CAAA;IAAAC,MAAA;IAAAC,MAAA;GAAA,CAAA;GAAAC,MAAA,CAAA,GAAA;IAAA;KAAA;KAAA;KAAA;MAAA;MAAA;MAAA,CAAA,QAAA;KAAA;IAAA;IAAA;KAAA;KAAA;MAAA;MAAA;MAAA;OAAA;OAAA;OAAA;MAAA;KAAA;KAAA,CAAA,IAAA;MAAA;MAAA;MAAA,CAAA,CAAA,GAAA,GAAA,CAAA;KAAA,CAAA;IAAA;IAAA;KAAA;KAAA;KAAA;MAAA;MAAA;MAAA,CAAA;KAAA;IAAA;IAAA;KAAA;KAAA;KAAA;MAAA;MAAA;MAAA,CAAA;OAAA;OAAA;OAAA;MAAA,CAAA;KAAA;IAAA;IAAA;KAAA;KAAA,CAAA,IAAA,OAAA;KAAA;MAAA;MAAA;MAAA;KAAA;KAAA,CAAA,GAAA;MAAA;OAAA;OAAA;QAAA;QAAA;SAAA;SAAA;SAAA;QAAA;QAAA;QAAA,CAAA,GAAA,GAAA;OAAA;OAAA,CAAA,EAAA;MAAA;MAAA;OAAA;OAAA;OAAA;QAAA;QAAA;SAAA;SAAA;SAAA,CAAA,GAAA,GAAA;QAAA;QAAA;QAAA;SAAA;SAAA;SAAA,CAAA;UAAA;UAAA;UAAA;SAAA,CAAA;QAAA;OAAA;MAAA;MAAA;OAAA;OAAA;OAAA;QAAA;QAAA;QAAA,CAAA;SAAA;SAAA;SAAA,CAAA;UAAA;UAAA;UAAA;SAAA,GAAA,gBAAA;QAAA,CAAA;OAAA;MAAA;MAAA;OAAA;OAAA;OAAA;OAAA;QAAA;QAAA;SAAA;SAAA;UAAA;UAAA;UAAA;SAAA;SAAA;SAAA;UAAA;UAAA;UAAA;SAAA;QAAA;QAAA;QAAA;OAAA;MAAA;KAAA,CAAA;IAAA;IAAA,CAAA,IAAA;KAAA;KAAA;KAAA,CAAA;MAAA;MAAA;OAAA;OAAA;OAAA;MAAA;MAAA;MAAA;KAAA,GAAA;MAAA;MAAA;MAAA;KAAA,CAAA;IAAA,CAAA;GAAA,CAAA;EAAA;EAAA,WAAA;GAAAC,aAAAjB;GAAAkB,aAAAhB;GAAAiB,gBAAAf;GAAAgB,aAAAd;GAAAe,iBAAAZ;GAAAa,gBAAAX;GAAAY,WAAAX;EAAA;CAAA,CAAA,KAAAY,EAAA,EAAA,CAAA,CAAA,CAAA;AAiBR"}
|
package/dist/pbr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pbr.js","names":[],"sources":["../src/appearances/pbr/material.ts","../src/appearances/pbr/appearance.ts"],"sourcesContent":["import { f32, type Infer, struct, vec3f } from 'typegpu/data'\nimport { mix } from 'typegpu/std'\n\n/**\n * GPU material schema for a surface using metallic/roughness shading and opacity.\n * Colors are linear RGB. Callers must supply finite values within the documented\n * ranges; constructing this struct does not clamp or validate material values.\n */\nexport const PbrMaterial = struct({\n\t/** Diffuse color for nonmetals, specular reflection color for metals. Each channel is in [0, 1]. */\n\tbaseColor: vec3f,\n\n\t/** Nonmetal at 0, metal at 1; intermediate values blend the responses. Not a shininess control. */\n\tmetallic: f32,\n\n\t/**\n\t * Surface roughness in [0, 1]: 0 produces sharp direct highlights, 1 broad ones.\n\t * Direct shading applies a small internal floor at the smooth end for stability.\n\t * Passed to the environment callback; the consumer owns reflection filtering.\n\t */\n\troughness: f32,\n\n\t/**\n\t * Nonnegative outgoing linear RGB added independently of illumination; may exceed 1.\n\t * Does not illuminate other surfaces or disable this material's reflections.\n\t */\n\temission: vec3f,\n\n\t/** Opacity of the entire shaded surface in [0, 1]: 0 is transparent, 1 is opaque. */\n\topacity: f32,\n})\nexport type PbrMaterial = Infer<typeof PbrMaterial>\n\n/** Debug material for visualizing a normalized float That varies over the surface. */\nexport function debugPbrMaterial(luminance: number): PbrMaterial {\n\t'use gpu'\n\treturn PbrMaterial({\n\t\tbaseColor: vec3f(0),\n\t\tmetallic: f32(0),\n\t\troughness: f32(1),\n\t\temission: vec3f(luminance),\n\t\topacity: f32(1),\n\t})\n}\n\nexport function mixPbrMaterials(\n\ta: PbrMaterial,\n\tb: PbrMaterial,\n\tamount: number,\n): PbrMaterial {\n\t'use gpu'\n\treturn PbrMaterial({\n\t\tbaseColor: mix(a.baseColor, b.baseColor, amount),\n\t\tmetallic: mix(a.metallic, b.metallic, amount),\n\t\troughness: mix(a.roughness, b.roughness, amount),\n\t\temission: mix(a.emission, b.emission, amount),\n\t\topacity: mix(a.opacity, b.opacity, amount),\n\t})\n}\n","import {\n\ttype Infer,\n\tstruct,\n\ttype v3f,\n\ttype v4f,\n\tvec3f,\n\tvec4f,\n} from 'typegpu/data'\nimport {\n\tclamp,\n\tdot,\n\tmax,\n\tmix,\n\tnormalize,\n\tpow,\n\treflect,\n\tsqrt,\n} from 'typegpu/std'\nimport type { RaymarchLighting } from '../../lighting'\nimport type { RaymarchAppearance, RaymarchResult } from '../../program'\nimport { PbrMaterial } from './material'\n\n/** Position, normal, and PBR material consumed by the lighting calculation. */\nexport const PbrSurfaceSample = struct({\n\tposition: vec3f,\n\tnormal: vec3f,\n\tmaterial: PbrMaterial,\n})\nexport type PbrSurfaceSample = Infer<typeof PbrSurfaceSample>\n\n/** Schlick Fresnel approximation; cosTheta is the incident angle's cosine in [0, 1]. */\nfunction fresnelSchlick(cosTheta: number, specularF0: v3f): v3f {\n\t'use gpu'\n\treturn specularF0 + (1 - specularF0) * pow(1 - cosTheta, 5)\n}\n\n/**\n * GGX microfacet distribution; normalDotHalf is in [0, 1].\n * alpha is material roughness squared, with a positive floor applied by the caller.\n */\nfunction distributionGGX(normalDotHalf: number, alpha: number): number {\n\t'use gpu'\n\tconst alphaSquared = alpha * alpha\n\tconst denominator = normalDotHalf * normalDotHalf * (alphaSquared - 1) + 1\n\treturn alphaSquared / (Math.PI * denominator * denominator)\n}\n\n/**\n * Height-correlated Smith GGX visibility, including G / (4 NdotL NdotV).\n * Both cosines must be in (0, 1]; alpha uses the same positive floor as GGX.\n */\nfunction visibilitySmithGGX(\n\tnormalDotView: number,\n\tnormalDotLight: number,\n\talpha: number,\n): number {\n\t'use gpu'\n\tconst alphaSquared = alpha * alpha\n\tconst viewTerm =\n\t\tnormalDotLight *\n\t\tsqrt(normalDotView * normalDotView * (1 - alphaSquared) + alphaSquared)\n\tconst lightTerm =\n\t\tnormalDotView *\n\t\tsqrt(normalDotLight * normalDotLight * (1 - alphaSquared) + alphaSquared)\n\treturn 0.5 / (viewTerm + lightTerm)\n}\n\n/** Combines the microfacet distribution, visibility, and Fresnel response. */\nfunction calculateSpecularResponse(\n\tnormalDotView: number,\n\tnormalDotLight: number,\n\tnormalDotHalf: number,\n\talpha: number,\n\tfresnel: v3f,\n): v3f {\n\t'use gpu'\n\tconst distribution = distributionGGX(normalDotHalf, alpha)\n\tconst visibility = visibilitySmithGGX(normalDotView, normalDotLight, alpha)\n\treturn distribution * visibility * fresnel\n}\n\n/** Material response including the surface-facing factor, before light color/intensity. */\nfunction evaluateDirectLightResponse(\n\tnormal: v3f,\n\tviewDirection: v3f,\n\tlightDirection: v3f,\n\tnormalDotView: number,\n\tdiffuseColor: v3f,\n\tspecularF0: v3f,\n\talpha: number,\n): v3f {\n\t'use gpu'\n\tconst normalDotLight = clamp(dot(normal, lightDirection), 0, 1)\n\tif (normalDotView === 0 || normalDotLight === 0) return vec3f(0)\n\n\tconst halfwayDirection = normalize(viewDirection + lightDirection)\n\tconst normalDotHalf = clamp(dot(normal, halfwayDirection), 0, 1)\n\tconst viewDotHalf = clamp(dot(viewDirection, halfwayDirection), 0, 1)\n\tconst fresnel = fresnelSchlick(viewDotHalf, specularF0)\n\tconst specular = calculateSpecularResponse(\n\t\tnormalDotView,\n\t\tnormalDotLight,\n\t\tnormalDotHalf,\n\t\talpha,\n\t\tfresnel,\n\t)\n\n\t// Only the nonmetal response contributes diffuse reflection.\n\tconst dielectricFresnel = fresnelSchlick(viewDotHalf, vec3f(0.04))\n\tconst diffuse = ((1 - dielectricFresnel) * diffuseColor) / Math.PI\n\treturn normalDotLight * (diffuse + specular)\n}\n\n/**\n * Creates a GPU surface shader combining direct lighting, material emission,\n * and environment reflections.\n */\nexport function createPbrShadeSurface({\n\tlighting,\n\tenvironment,\n}: {\n\tlighting: () => RaymarchLighting\n\tenvironment: (direction: v3f, roughness: number) => v3f\n}) {\n\tfunction calculateDirectLighting(\n\t\tviewDirection: v3f,\n\t\tnormal: v3f,\n\t\tmaterial: PbrMaterial,\n\t\tspecularF0: v3f,\n\t): v3f {\n\t\t'use gpu'\n\n\t\tconst diffuseColor = material.baseColor * (1 - material.metallic)\n\t\tlet accumulatedLight = lighting().ambient * diffuseColor\n\t\tconst directionalLights = lighting().directionalLights\n\t\tconst normalDotView = clamp(dot(normal, viewDirection), 0, 1)\n\t\tif (normalDotView === 0) return accumulatedLight\n\n\t\tconst minimumAlpha = 0.001 // Keep the GGX response finite even for material roughness zero.\n\t\tconst alpha = max(material.roughness * material.roughness, minimumAlpha)\n\n\t\tfor (const light of directionalLights) {\n\t\t\tif (light.intensity === 0) continue\n\n\t\t\tconst lightDirection = -1 * normalize(light.direction)\n\t\t\tconst response = evaluateDirectLightResponse(\n\t\t\t\tnormal,\n\t\t\t\tviewDirection,\n\t\t\t\tlightDirection,\n\t\t\t\tnormalDotView,\n\t\t\t\tdiffuseColor,\n\t\t\t\tspecularF0,\n\t\t\t\talpha,\n\t\t\t)\n\t\t\taccumulatedLight += light.color * light.intensity * response\n\t\t}\n\n\t\treturn accumulatedLight\n\t}\n\n\tfunction calculateReflection(\n\t\tviewDirection: v3f,\n\t\tnormal: v3f,\n\t\tspecularF0: v3f,\n\t\troughness: number,\n\t): v3f {\n\t\t'use gpu'\n\n\t\tconst reflectionDirection = reflect(-1 * viewDirection, normal)\n\t\tconst environmentColor = environment(reflectionDirection, roughness)\n\t\tconst facing = max(dot(normal, viewDirection), 0)\n\t\tconst fresnel = fresnelSchlick(facing, specularF0)\n\n\t\treturn environmentColor * fresnel\n\t}\n\n\treturn function shadeSurface(\n\t\tcameraPosition: v3f,\n\t\tsample: PbrSurfaceSample,\n\t): v3f {\n\t\t'use gpu'\n\n\t\tconst material = sample.material\n\t\tconst viewDirection = normalize(cameraPosition - sample.position)\n\n\t\tconst dielectricF0 = vec3f(0.04) // Normal-incidence reflectance for a nonmetal with IOR 1.5.\n\t\tconst specularF0 = mix(dielectricF0, material.baseColor, material.metallic)\n\n\t\tconst directLighting = calculateDirectLighting(\n\t\t\tviewDirection,\n\t\t\tsample.normal,\n\t\t\tmaterial,\n\t\t\tspecularF0,\n\t\t)\n\n\t\tconst reflection = calculateReflection(\n\t\t\tviewDirection,\n\t\t\tsample.normal,\n\t\t\tspecularF0,\n\t\t\tmaterial.roughness,\n\t\t)\n\n\t\treturn directLighting + material.emission + reflection\n\t}\n}\n\n/** GPU function sampling a PBR material from the raymarch result. */\nexport type PbrMaterialSampler = (result: RaymarchResult) => PbrMaterial\n\n/**\n * Creates a metallic/roughness appearance for a raymarch program.\n * Material opacity applies to the entire shaded result during blending.\n *\n * Material sampling runs for hits and misses so derivatives remain available.\n * Lighting runs only for hits. The returned color on a miss is ignored by the\n * renderer.\n */\nexport function createPbrAppearance({\n\tmaterial,\n\tlighting,\n\tenvironment,\n}: {\n\tmaterial: PbrMaterialSampler\n\tlighting: () => RaymarchLighting\n\t/**\n\t * Incoming linear RGB from a normalized reflection direction. Called only on\n\t * hits; texture sampling here should use an explicit level of detail.\n\t */\n\tenvironment: (direction: v3f, roughness: number) => v3f\n}): RaymarchAppearance {\n\tconst shadeSurface = createPbrShadeSurface({ lighting, environment })\n\n\treturn function pbrAppearance(result: RaymarchResult): v4f {\n\t\t'use gpu'\n\t\tconst materialSample = material(result)\n\t\tif (!result.isHit) return vec4f(0)\n\n\t\treturn vec4f(\n\t\t\tshadeSurface(\n\t\t\t\tresult.rayOrigin,\n\t\t\t\tPbrSurfaceSample({\n\t\t\t\t\tposition: result.position,\n\t\t\t\t\tnormal: result.normal,\n\t\t\t\t\tmaterial: materialSample,\n\t\t\t\t}),\n\t\t\t),\n\t\t\tmaterialSample.opacity,\n\t\t)\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pbr.js","names":["mixPbrMaterials","PbrMaterial","mix","a","b","amount","\"params\"","\"type\"","\"name\"","\"body\"","\"baseColor\"","\"metallic\"","\"roughness\"","\"emission\"","\"opacity\"","\"PbrMaterial\"","\"mix\"","$","struct","vec3f","f32","evaluateDirectLightResponse","normalDotLight","clamp","dot","normal","lightDirection","normalDotView","halfwayDirection","normalize","viewDirection","normalDotHalf","viewDotHalf","specular","calculateSpecularResponse","alpha","fresnelSchlick","specularF0","dielectricFresnel","diffuse","diffuseColor","\"clamp\"","\"dot\"","\"vec3f\"","\"normalize\"","\"fresnelSchlick\"","\"calculateSpecularResponse\"","distribution","distributionGGX","visibility","visibilitySmithGGX","fresnel","\"distributionGGX\"","\"visibilitySmithGGX\"","alphaSquared","viewTerm","sqrt","lightTerm","\"sqrt\"","denominator","pow","cosTheta","\"pow\"","PbrSurfaceSample","createPbrShadeSurface","calculateReflection","environmentColor","environment","reflect","roughness","max","\"reflect\"","\"environment\"","\"max\"","calculateDirectLighting","material","accumulatedLight","lighting","directionalLights","light","response","\"lighting\"","\"evaluateDirectLightResponse\"","sample","cameraPosition","dielectricF0","directLighting","reflection","\"calculateDirectLighting\"","\"calculateReflection\"","createPbrAppearance","shadeSurface","materialSample","result","vec4f","\"position\"","\"normal\"","\"material\"","\"vec4f\"","\"shadeSurface\"","\"PbrSurfaceSample\""],"sources":["../src/appearances/pbr/material.ts","../src/appearances/pbr/appearance.ts"],"sourcesContent":["import { f32, type Infer, struct, vec3f } from 'typegpu/data'\nimport { mix } from 'typegpu/std'\n\n/**\n * GPU material schema for a surface using metallic/roughness shading and opacity.\n * Colors are linear RGB. Callers must supply finite values within the documented\n * ranges; constructing this struct does not clamp or validate material values.\n */\nexport const PbrMaterial = struct({\n\t/** Diffuse color for nonmetals, specular reflection color for metals. Each channel is in [0, 1]. */\n\tbaseColor: vec3f,\n\n\t/** Nonmetal at 0, metal at 1; intermediate values blend the responses. Not a shininess control. */\n\tmetallic: f32,\n\n\t/**\n\t * Surface roughness in [0, 1]: 0 produces sharp direct highlights, 1 broad ones.\n\t * Direct shading applies a small internal floor at the smooth end for stability.\n\t * Passed to the environment callback; the consumer owns reflection filtering.\n\t */\n\troughness: f32,\n\n\t/**\n\t * Nonnegative outgoing linear RGB added independently of illumination; may exceed 1.\n\t * Does not illuminate other surfaces or disable this material's reflections.\n\t */\n\temission: vec3f,\n\n\t/** Opacity of the entire shaded surface in [0, 1]: 0 is transparent, 1 is opaque. */\n\topacity: f32,\n})\nexport type PbrMaterial = Infer<typeof PbrMaterial>\n\n/** Debug material for visualizing a normalized float That varies over the surface. */\nexport function debugPbrMaterial(luminance: number): PbrMaterial {\n\t'use gpu'\n\treturn PbrMaterial({\n\t\tbaseColor: vec3f(0),\n\t\tmetallic: f32(0),\n\t\troughness: f32(1),\n\t\temission: vec3f(luminance),\n\t\topacity: f32(1),\n\t})\n}\n\nexport function mixPbrMaterials(\n\ta: PbrMaterial,\n\tb: PbrMaterial,\n\tamount: number,\n): PbrMaterial {\n\t'use gpu'\n\treturn PbrMaterial({\n\t\tbaseColor: mix(a.baseColor, b.baseColor, amount),\n\t\tmetallic: mix(a.metallic, b.metallic, amount),\n\t\troughness: mix(a.roughness, b.roughness, amount),\n\t\temission: mix(a.emission, b.emission, amount),\n\t\topacity: mix(a.opacity, b.opacity, amount),\n\t})\n}\n","import {\n\ttype Infer,\n\tstruct,\n\ttype v3f,\n\ttype v4f,\n\tvec3f,\n\tvec4f,\n} from 'typegpu/data'\nimport {\n\tclamp,\n\tdot,\n\tmax,\n\tmix,\n\tnormalize,\n\tpow,\n\treflect,\n\tsqrt,\n} from 'typegpu/std'\nimport type { RaymarchLighting } from '../../lighting'\nimport type { RaymarchAppearance, RaymarchResult } from '../../program'\nimport { PbrMaterial } from './material'\n\n/** Position, normal, and PBR material consumed by the lighting calculation. */\nexport const PbrSurfaceSample = struct({\n\tposition: vec3f,\n\tnormal: vec3f,\n\tmaterial: PbrMaterial,\n})\nexport type PbrSurfaceSample = Infer<typeof PbrSurfaceSample>\n\n/** Schlick Fresnel approximation; cosTheta is the incident angle's cosine in [0, 1]. */\nfunction fresnelSchlick(cosTheta: number, specularF0: v3f): v3f {\n\t'use gpu'\n\treturn specularF0 + (1 - specularF0) * pow(1 - cosTheta, 5)\n}\n\n/**\n * GGX microfacet distribution; normalDotHalf is in [0, 1].\n * alpha is material roughness squared, with a positive floor applied by the caller.\n */\nfunction distributionGGX(normalDotHalf: number, alpha: number): number {\n\t'use gpu'\n\tconst alphaSquared = alpha * alpha\n\tconst denominator = normalDotHalf * normalDotHalf * (alphaSquared - 1) + 1\n\treturn alphaSquared / (Math.PI * denominator * denominator)\n}\n\n/**\n * Height-correlated Smith GGX visibility, including G / (4 NdotL NdotV).\n * Both cosines must be in (0, 1]; alpha uses the same positive floor as GGX.\n */\nfunction visibilitySmithGGX(\n\tnormalDotView: number,\n\tnormalDotLight: number,\n\talpha: number,\n): number {\n\t'use gpu'\n\tconst alphaSquared = alpha * alpha\n\tconst viewTerm =\n\t\tnormalDotLight *\n\t\tsqrt(normalDotView * normalDotView * (1 - alphaSquared) + alphaSquared)\n\tconst lightTerm =\n\t\tnormalDotView *\n\t\tsqrt(normalDotLight * normalDotLight * (1 - alphaSquared) + alphaSquared)\n\treturn 0.5 / (viewTerm + lightTerm)\n}\n\n/** Combines the microfacet distribution, visibility, and Fresnel response. */\nfunction calculateSpecularResponse(\n\tnormalDotView: number,\n\tnormalDotLight: number,\n\tnormalDotHalf: number,\n\talpha: number,\n\tfresnel: v3f,\n): v3f {\n\t'use gpu'\n\tconst distribution = distributionGGX(normalDotHalf, alpha)\n\tconst visibility = visibilitySmithGGX(normalDotView, normalDotLight, alpha)\n\treturn distribution * visibility * fresnel\n}\n\n/** Material response including the surface-facing factor, before light color/intensity. */\nfunction evaluateDirectLightResponse(\n\tnormal: v3f,\n\tviewDirection: v3f,\n\tlightDirection: v3f,\n\tnormalDotView: number,\n\tdiffuseColor: v3f,\n\tspecularF0: v3f,\n\talpha: number,\n): v3f {\n\t'use gpu'\n\tconst normalDotLight = clamp(dot(normal, lightDirection), 0, 1)\n\tif (normalDotView === 0 || normalDotLight === 0) return vec3f(0)\n\n\tconst halfwayDirection = normalize(viewDirection + lightDirection)\n\tconst normalDotHalf = clamp(dot(normal, halfwayDirection), 0, 1)\n\tconst viewDotHalf = clamp(dot(viewDirection, halfwayDirection), 0, 1)\n\tconst fresnel = fresnelSchlick(viewDotHalf, specularF0)\n\tconst specular = calculateSpecularResponse(\n\t\tnormalDotView,\n\t\tnormalDotLight,\n\t\tnormalDotHalf,\n\t\talpha,\n\t\tfresnel,\n\t)\n\n\t// Only the nonmetal response contributes diffuse reflection.\n\tconst dielectricFresnel = fresnelSchlick(viewDotHalf, vec3f(0.04))\n\tconst diffuse = ((1 - dielectricFresnel) * diffuseColor) / Math.PI\n\treturn normalDotLight * (diffuse + specular)\n}\n\n/**\n * Creates a GPU surface shader combining direct lighting, material emission,\n * and environment reflections.\n */\nexport function createPbrShadeSurface({\n\tlighting,\n\tenvironment,\n}: {\n\tlighting: () => RaymarchLighting\n\tenvironment: (direction: v3f, roughness: number) => v3f\n}) {\n\tfunction calculateDirectLighting(\n\t\tviewDirection: v3f,\n\t\tnormal: v3f,\n\t\tmaterial: PbrMaterial,\n\t\tspecularF0: v3f,\n\t): v3f {\n\t\t'use gpu'\n\n\t\tconst diffuseColor = material.baseColor * (1 - material.metallic)\n\t\tlet accumulatedLight = lighting().ambient * diffuseColor\n\t\tconst directionalLights = lighting().directionalLights\n\t\tconst normalDotView = clamp(dot(normal, viewDirection), 0, 1)\n\t\tif (normalDotView === 0) return accumulatedLight\n\n\t\tconst minimumAlpha = 0.001 // Keep the GGX response finite even for material roughness zero.\n\t\tconst alpha = max(material.roughness * material.roughness, minimumAlpha)\n\n\t\tfor (const light of directionalLights) {\n\t\t\tif (light.intensity === 0) continue\n\n\t\t\tconst lightDirection = -1 * normalize(light.direction)\n\t\t\tconst response = evaluateDirectLightResponse(\n\t\t\t\tnormal,\n\t\t\t\tviewDirection,\n\t\t\t\tlightDirection,\n\t\t\t\tnormalDotView,\n\t\t\t\tdiffuseColor,\n\t\t\t\tspecularF0,\n\t\t\t\talpha,\n\t\t\t)\n\t\t\taccumulatedLight += light.color * light.intensity * response\n\t\t}\n\n\t\treturn accumulatedLight\n\t}\n\n\tfunction calculateReflection(\n\t\tviewDirection: v3f,\n\t\tnormal: v3f,\n\t\tspecularF0: v3f,\n\t\troughness: number,\n\t): v3f {\n\t\t'use gpu'\n\n\t\tconst reflectionDirection = reflect(-1 * viewDirection, normal)\n\t\tconst environmentColor = environment(reflectionDirection, roughness)\n\t\tconst facing = max(dot(normal, viewDirection), 0)\n\t\tconst fresnel = fresnelSchlick(facing, specularF0)\n\n\t\treturn environmentColor * fresnel\n\t}\n\n\treturn function shadeSurface(\n\t\tcameraPosition: v3f,\n\t\tsample: PbrSurfaceSample,\n\t): v3f {\n\t\t'use gpu'\n\n\t\tconst material = sample.material\n\t\tconst viewDirection = normalize(cameraPosition - sample.position)\n\n\t\tconst dielectricF0 = vec3f(0.04) // Normal-incidence reflectance for a nonmetal with IOR 1.5.\n\t\tconst specularF0 = mix(dielectricF0, material.baseColor, material.metallic)\n\n\t\tconst directLighting = calculateDirectLighting(\n\t\t\tviewDirection,\n\t\t\tsample.normal,\n\t\t\tmaterial,\n\t\t\tspecularF0,\n\t\t)\n\n\t\tconst reflection = calculateReflection(\n\t\t\tviewDirection,\n\t\t\tsample.normal,\n\t\t\tspecularF0,\n\t\t\tmaterial.roughness,\n\t\t)\n\n\t\treturn directLighting + material.emission + reflection\n\t}\n}\n\n/** GPU function sampling a PBR material from the raymarch result. */\nexport type PbrMaterialSampler = (result: RaymarchResult) => PbrMaterial\n\n/**\n * Creates a metallic/roughness appearance for a raymarch program.\n * Material opacity applies to the entire shaded result during blending.\n *\n * Material sampling runs for hits and misses so derivatives remain available.\n * Lighting runs only for hits. The returned color on a miss is ignored by the\n * renderer.\n */\nexport function createPbrAppearance({\n\tmaterial,\n\tlighting,\n\tenvironment,\n}: {\n\tmaterial: PbrMaterialSampler\n\tlighting: () => RaymarchLighting\n\t/**\n\t * Incoming linear RGB from a normalized reflection direction. Called only on\n\t * hits; texture sampling here should use an explicit level of detail.\n\t */\n\tenvironment: (direction: v3f, roughness: number) => v3f\n}): RaymarchAppearance {\n\tconst shadeSurface = createPbrShadeSurface({ lighting, environment })\n\n\treturn function pbrAppearance(result: RaymarchResult): v4f {\n\t\t'use gpu'\n\t\tconst materialSample = material(result)\n\t\tif (!result.isHit) return vec4f(0)\n\n\t\treturn vec4f(\n\t\t\tshadeSurface(\n\t\t\t\tresult.rayOrigin,\n\t\t\t\tPbrSurfaceSample({\n\t\t\t\t\tposition: result.position,\n\t\t\t\t\tnormal: result.normal,\n\t\t\t\t\tmaterial: materialSample,\n\t\t\t\t}),\n\t\t\t),\n\t\t\tmaterialSample.opacity,\n\t\t)\n\t}\n}\n"],"mappings":"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"}
|
package/dist/program.d.ts
CHANGED
|
@@ -99,11 +99,11 @@ export interface RaymarchProgram {
|
|
|
99
99
|
/** GPU function returning unpremultiplied linear RGB and opacity for the raymarch result. */
|
|
100
100
|
appearance: RaymarchAppearance;
|
|
101
101
|
}
|
|
102
|
-
/** Versioned program with its pipeline compilation options. */
|
|
103
|
-
export interface RaymarchProgramDefinition {
|
|
102
|
+
/** Versioned program factory with its pipeline compilation options. */
|
|
103
|
+
export interface RaymarchProgramDefinition<TContext = undefined> {
|
|
104
104
|
version: number;
|
|
105
105
|
options: RaymarchProgramOptions;
|
|
106
|
-
|
|
106
|
+
create: (context: TContext) => RaymarchProgram;
|
|
107
107
|
}
|
|
108
108
|
/** Minimal hot-module context used to retain a program across reevaluations. */
|
|
109
109
|
export interface RaymarchHotContext {
|
|
@@ -111,20 +111,23 @@ export interface RaymarchHotContext {
|
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
113
|
* Creates a versioned program definition without allocating GPU resources. It
|
|
114
|
-
*
|
|
114
|
+
* stores a factory for surface, camera, and appearance callbacks,
|
|
115
115
|
* and the options used to compile them into a raymarching pipeline. Callbacks
|
|
116
116
|
* may read changing buffer data without rebuilding the pipeline.
|
|
117
117
|
*
|
|
118
118
|
* ```ts
|
|
119
119
|
* const program = createRaymarchProgram({ ...program, options })
|
|
120
|
+
* const dependentProgram = createRaymarchProgram(options, (context: Context) => ({ ...callbacks }))
|
|
120
121
|
* ```
|
|
121
122
|
*
|
|
122
123
|
* ## Vite Hot Reloading
|
|
123
124
|
*
|
|
124
125
|
* When `hot` is provided, reevaluating the module updates the existing program
|
|
125
126
|
* definition and increments its version. Renderer instances observe that
|
|
126
|
-
* version and
|
|
127
|
-
*
|
|
127
|
+
* version and rerun the factory with each renderer's existing context before
|
|
128
|
+
* rebuilding its pipeline. Factories run during renderer setup and rebuilding,
|
|
129
|
+
* not on every draw. Caller-owned resources should be created outside the factory.
|
|
130
|
+
* The defining module must call `import.meta.hot?.accept()` for this behavior, and
|
|
128
131
|
* may currently define only one HMR-backed raymarch program.
|
|
129
132
|
*
|
|
130
133
|
* ```ts
|
|
@@ -134,11 +137,7 @@ export interface RaymarchHotContext {
|
|
|
134
137
|
*
|
|
135
138
|
* @returns A read-only program definition consumed by raymarch renderer factories.
|
|
136
139
|
*/
|
|
137
|
-
export declare function createRaymarchProgram(
|
|
140
|
+
export declare function createRaymarchProgram(program: RaymarchProgram & {
|
|
138
141
|
options: RaymarchProgramOptions;
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
* Optional hot-module context used to preserve and update the program
|
|
142
|
-
* across module reevaluations.
|
|
143
|
-
*/
|
|
144
|
-
hot?: RaymarchHotContext): Readonly<RaymarchProgramDefinition>;
|
|
142
|
+
}, hot?: RaymarchHotContext): Readonly<RaymarchProgramDefinition>;
|
|
143
|
+
export declare function createRaymarchProgram<TContext = undefined>(options: RaymarchProgramOptions, create: (context: TContext) => RaymarchProgram, hot?: RaymarchHotContext): Readonly<RaymarchProgramDefinition<TContext>>;
|
package/dist/renderer.d.ts
CHANGED
|
@@ -30,15 +30,15 @@ export interface RaymarchRenderOptions {
|
|
|
30
30
|
* raymarching, normal calculation, appearance, depth, and draw submission to the
|
|
31
31
|
* surface supplied by the program.
|
|
32
32
|
*
|
|
33
|
-
* Program preparation and pipeline compilation are repeated when the
|
|
34
|
-
* version changes,
|
|
33
|
+
* Program creation, preparation, and pipeline compilation are repeated when the
|
|
34
|
+
* program version changes, using the updated factory with the same context.
|
|
35
35
|
*
|
|
36
36
|
* @returns A function that draws a requested number of raymarched instances.
|
|
37
37
|
*/
|
|
38
|
-
export declare function createRaymarchRenderer({ root, program: programDefinition, renderTarget, prepare, preparePipeline, }: {
|
|
38
|
+
export declare function createRaymarchRenderer<TContext = undefined>({ root, program: programDefinition, context, renderTarget, prepare, preparePipeline, }: {
|
|
39
39
|
root: TgpuRoot;
|
|
40
|
-
/** Program providing pipeline options, a version, and shader
|
|
41
|
-
program: Readonly<RaymarchProgramDefinition
|
|
40
|
+
/** Program providing pipeline options, a version, and a shader factory. */
|
|
41
|
+
program: Readonly<RaymarchProgramDefinition<TContext>>;
|
|
42
42
|
/** Render target configuration used to create a compatible pipeline. */
|
|
43
43
|
renderTarget?: Readonly<RaymarchRenderTargetOptions>;
|
|
44
44
|
/**
|
|
@@ -54,4 +54,8 @@ export declare function createRaymarchRenderer({ root, program: programDefinitio
|
|
|
54
54
|
}>) => TgpuRenderPipeline<{
|
|
55
55
|
color: Vec4f;
|
|
56
56
|
}>;
|
|
57
|
-
}
|
|
57
|
+
} & (undefined extends NoInfer<TContext> ? {
|
|
58
|
+
context?: NoInfer<TContext>;
|
|
59
|
+
} : {
|
|
60
|
+
context: NoInfer<TContext>;
|
|
61
|
+
})): (options: RaymarchRenderOptions) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "luxscura",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A TypeGPU ray marching renderer",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alex Wayne",
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
"typegpu": "^0.12.6"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@types/bun": "^1.3
|
|
62
|
-
"@webgpu/types": "^0.1.
|
|
63
|
-
"typegpu": "^0.12.
|
|
61
|
+
"@types/bun": "^1.4.3",
|
|
62
|
+
"@webgpu/types": "^0.1.74",
|
|
63
|
+
"typegpu": "^0.12.8",
|
|
64
64
|
"typescript": "npm:tsover@6.0.2",
|
|
65
|
-
"unplugin-typegpu": "^0.12.
|
|
66
|
-
"vite": "^8.
|
|
65
|
+
"unplugin-typegpu": "^0.12.6",
|
|
66
|
+
"vite": "^8.3.4"
|
|
67
67
|
}
|
|
68
68
|
}
|