@plasius/gpu-renderer 0.1.7 → 0.1.8

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/src/index.js CHANGED
@@ -3,6 +3,106 @@ const DEFAULT_CANVAS_SELECTOR = "canvas[data-plasius-gpu-renderer]";
3
3
  export const rendererDebugOwner = "renderer";
4
4
  export const rendererWorkerQueueClass = "render";
5
5
  export const defaultRendererWorkerProfile = "realtime";
6
+ export const rendererRepresentationBands = Object.freeze([
7
+ "near",
8
+ "mid",
9
+ "far",
10
+ "horizon",
11
+ ]);
12
+ export const rendererAccelerationStructureUpdateClasses = Object.freeze([
13
+ "static",
14
+ "rigid-dynamic",
15
+ "deforming",
16
+ "proxy",
17
+ ]);
18
+ export const rendererRayTracingStageOrder = Object.freeze([
19
+ "primaryVisibility",
20
+ "shadowAssist",
21
+ "opaqueFoundation",
22
+ "rtDirectLighting",
23
+ "rtReflections",
24
+ "rtGlobalIllumination",
25
+ "denoiseTemporal",
26
+ "transparents",
27
+ "composition",
28
+ "present",
29
+ ]);
30
+
31
+ const rendererRayTracingStageDefinitions = Object.freeze(
32
+ rendererRayTracingStageOrder.map((key, index) =>
33
+ Object.freeze({
34
+ key,
35
+ order: index + 1,
36
+ required: true,
37
+ description:
38
+ {
39
+ primaryVisibility: "Primary visibility and depth preparation.",
40
+ shadowAssist: "Shadow assist passes and regional shadow preparation.",
41
+ opaqueFoundation: "Main opaque foundation for shading and tracing inputs.",
42
+ rtDirectLighting: "Ray-traced direct lighting and premium shadows.",
43
+ rtReflections: "Ray-traced reflections for important surfaces.",
44
+ rtGlobalIllumination: "Selective ray-traced indirect lighting and GI.",
45
+ denoiseTemporal: "Required denoise and temporal accumulation stage.",
46
+ transparents: "Transparents, particles, and volumetrics composition.",
47
+ composition: "Final world composition and color resolve.",
48
+ present: "Presentation to the active surface.",
49
+ }[key],
50
+ })
51
+ )
52
+ );
53
+
54
+ const rendererRepresentationBandPolicies = Object.freeze({
55
+ near: Object.freeze({
56
+ band: "near",
57
+ rasterMode: "full-live",
58
+ rtParticipation: "premium",
59
+ shadowSource: "ray-traced-primary",
60
+ temporalReuse: "balanced",
61
+ updateCadenceDivisor: 1,
62
+ }),
63
+ mid: Object.freeze({
64
+ band: "mid",
65
+ rasterMode: "simplified-live",
66
+ rtParticipation: "selective",
67
+ shadowSource: "regional-raster-and-proxy",
68
+ temporalReuse: "aggressive",
69
+ updateCadenceDivisor: 2,
70
+ }),
71
+ far: Object.freeze({
72
+ band: "far",
73
+ rasterMode: "proxy-or-cached",
74
+ rtParticipation: "proxy",
75
+ shadowSource: "merged-proxy-casters",
76
+ temporalReuse: "high",
77
+ updateCadenceDivisor: 8,
78
+ }),
79
+ horizon: Object.freeze({
80
+ band: "horizon",
81
+ rasterMode: "horizon-shell",
82
+ rtParticipation: "disabled",
83
+ shadowSource: "baked-impression",
84
+ temporalReuse: "cached",
85
+ updateCadenceDivisor: 60,
86
+ }),
87
+ });
88
+
89
+ const rendererAccelerationStructurePolicies = Object.freeze(
90
+ rendererAccelerationStructureUpdateClasses.map((updateClass) =>
91
+ Object.freeze({
92
+ updateClass,
93
+ description:
94
+ {
95
+ static: "Stable static world geometry with infrequent rebuilds.",
96
+ "rigid-dynamic":
97
+ "Rigid transforms that can be refit or relinked without full deformation updates.",
98
+ deforming:
99
+ "Skinned or vertex-deforming content treated as a managed RT cost center.",
100
+ proxy:
101
+ "Low-cost RT proxy or distant representation updates.",
102
+ }[updateClass],
103
+ })
104
+ )
105
+ );
6
106
 
7
107
  function buildRendererWorkerBudgetLevels(jobType, queueClass, levels) {
8
108
  return Object.freeze(
@@ -362,6 +462,75 @@ const rendererWorkerProfileSpecs = {
362
462
  },
363
463
  };
364
464
 
465
+ function buildRendererInputBoundary(profile) {
466
+ return Object.freeze({
467
+ type: "stable-visual-snapshot",
468
+ owner: rendererDebugOwner,
469
+ profile,
470
+ authority: "visual",
471
+ source: "scene-preparation",
472
+ stable: true,
473
+ });
474
+ }
475
+
476
+ function buildRendererRenderStages(profile) {
477
+ return Object.freeze(
478
+ rendererRayTracingStageDefinitions.map((stage) =>
479
+ Object.freeze({
480
+ ...stage,
481
+ profile,
482
+ workerJobKeys:
483
+ profile === "xr" && stage.key === "primaryVisibility"
484
+ ? Object.freeze(["lateLatch", "visibility"])
485
+ : stage.key === "present"
486
+ ? Object.freeze(["submit"])
487
+ : stage.key === "denoiseTemporal" ||
488
+ stage.key === "transparents" ||
489
+ stage.key === "composition"
490
+ ? Object.freeze(["postProcess"])
491
+ : stage.key === "primaryVisibility"
492
+ ? Object.freeze(["visibility"])
493
+ : stage.key === "shadowAssist" ||
494
+ stage.key === "opaqueFoundation" ||
495
+ stage.key === "rtDirectLighting" ||
496
+ stage.key === "rtReflections" ||
497
+ stage.key === "rtGlobalIllumination"
498
+ ? Object.freeze(["mainEncode"])
499
+ : Object.freeze(["mainEncode"]),
500
+ })
501
+ )
502
+ );
503
+ }
504
+
505
+ function buildRendererRepresentationBands(profile) {
506
+ return Object.freeze(
507
+ rendererRepresentationBands.map((band) =>
508
+ Object.freeze({
509
+ ...rendererRepresentationBandPolicies[band],
510
+ profile,
511
+ })
512
+ )
513
+ );
514
+ }
515
+
516
+ function buildRendererAccelerationStructureUpdates(profile) {
517
+ return Object.freeze(
518
+ rendererAccelerationStructurePolicies.map((policy) =>
519
+ Object.freeze({
520
+ ...policy,
521
+ profile,
522
+ })
523
+ )
524
+ );
525
+ }
526
+
527
+ function assertRendererIdentifier(name, value) {
528
+ if (typeof value !== "string" || value.trim().length === 0) {
529
+ throw new Error(`${name} must be a non-empty string.`);
530
+ }
531
+ return value.trim();
532
+ }
533
+
365
534
  function buildRendererWorkerProfile(name, spec) {
366
535
  return Object.freeze({
367
536
  name,
@@ -415,6 +584,10 @@ function buildRendererWorkerManifest(name, spec) {
415
584
  description: spec.description,
416
585
  queueClass: rendererWorkerQueueClass,
417
586
  schedulerMode: "dag",
587
+ inputBoundary: buildRendererInputBoundary(name),
588
+ renderStages: buildRendererRenderStages(name),
589
+ representationBands: buildRendererRepresentationBands(name),
590
+ accelerationStructureUpdates: buildRendererAccelerationStructureUpdates(name),
418
591
  suggestedAllocationIds: Object.freeze([...spec.suggestedAllocationIds]),
419
592
  jobs: Object.freeze(
420
593
  Object.entries(spec.jobs).map(([jobName, jobSpec]) =>
@@ -464,6 +637,51 @@ export function getRendererWorkerManifest(name = defaultRendererWorkerProfile) {
464
637
  return manifest;
465
638
  }
466
639
 
640
+ export function createRayTracingRenderPlan(options = {}) {
641
+ const profile = options.profile ?? defaultRendererWorkerProfile;
642
+ const snapshotId = assertRendererIdentifier(
643
+ "snapshotId",
644
+ options.snapshotId
645
+ );
646
+ const workerManifest = getRendererWorkerManifest(profile);
647
+ const representations = Array.isArray(options.representations)
648
+ ? Object.freeze(
649
+ options.representations.map((representation, index) => {
650
+ if (!representation || typeof representation !== "object") {
651
+ throw new Error(`representations[${index}] must be an object.`);
652
+ }
653
+ const band = assertRendererIdentifier(
654
+ `representations[${index}].band`,
655
+ representation.band
656
+ );
657
+ if (!rendererRepresentationBands.includes(band)) {
658
+ throw new Error(
659
+ `representations[${index}].band must be one of: ${rendererRepresentationBands.join(", ")}.`
660
+ );
661
+ }
662
+ return Object.freeze({
663
+ ...representation,
664
+ band,
665
+ });
666
+ })
667
+ )
668
+ : workerManifest.representationBands;
669
+
670
+ return Object.freeze({
671
+ schemaVersion: 1,
672
+ owner: rendererDebugOwner,
673
+ profile,
674
+ inputBoundary: Object.freeze({
675
+ ...workerManifest.inputBoundary,
676
+ snapshotId,
677
+ }),
678
+ renderStages: workerManifest.renderStages,
679
+ representationBands: representations,
680
+ accelerationStructureUpdates: workerManifest.accelerationStructureUpdates,
681
+ workerManifest,
682
+ });
683
+ }
684
+
467
685
  function clamp01(value) {
468
686
  return Math.min(1, Math.max(0, value));
469
687
  }