@plasius/gpu-renderer 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +4 -1
- package/dist/index.cjs +187 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/index.d.ts +96 -0
- package/src/index.js +193 -0
package/src/index.d.ts
CHANGED
|
@@ -151,6 +151,19 @@ export type RendererAccelerationStructureUpdateClass =
|
|
|
151
151
|
| "rigid-dynamic"
|
|
152
152
|
| "deforming"
|
|
153
153
|
| "proxy";
|
|
154
|
+
export type RendererWavefrontHitType =
|
|
155
|
+
| "surface"
|
|
156
|
+
| "emissive"
|
|
157
|
+
| "environment"
|
|
158
|
+
| "transparent"
|
|
159
|
+
| "miss";
|
|
160
|
+
export type RendererWavefrontPassKey =
|
|
161
|
+
| "generatePrimaryRays"
|
|
162
|
+
| "intersectActiveQueue"
|
|
163
|
+
| "resolveSurfaceRecords"
|
|
164
|
+
| "accumulateTerminalRadiance"
|
|
165
|
+
| "scatterContinuations"
|
|
166
|
+
| "compactAndSwapQueues";
|
|
154
167
|
|
|
155
168
|
export interface RendererInputBoundary {
|
|
156
169
|
readonly type: "stable-visual-snapshot";
|
|
@@ -288,9 +301,75 @@ export interface RayTracingRenderPlan {
|
|
|
288
301
|
}
|
|
289
302
|
)[];
|
|
290
303
|
readonly accelerationStructureUpdates: readonly RendererAccelerationStructureUpdatePolicy[];
|
|
304
|
+
readonly wavefront: RendererWavefrontPathTracingPlan;
|
|
291
305
|
readonly workerManifest: RendererWorkerManifest;
|
|
292
306
|
}
|
|
293
307
|
|
|
308
|
+
export interface RendererWavefrontFieldContract {
|
|
309
|
+
readonly name: string;
|
|
310
|
+
readonly type: string;
|
|
311
|
+
readonly description: string;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export interface RendererWavefrontRecordContract {
|
|
315
|
+
readonly schemaVersion: typeof rendererWavefrontBufferSchemaVersion;
|
|
316
|
+
readonly recordName: string;
|
|
317
|
+
readonly fields: readonly RendererWavefrontFieldContract[];
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export interface RendererWavefrontQueueDescriptor {
|
|
321
|
+
readonly name: "active" | "next";
|
|
322
|
+
readonly role: "current-bounce" | "next-bounce";
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export interface RendererWavefrontBounceStep {
|
|
326
|
+
readonly bounce: number;
|
|
327
|
+
readonly readQueue: "active" | "next";
|
|
328
|
+
readonly writeQueue: "active" | "next";
|
|
329
|
+
readonly passOrder: readonly RendererWavefrontPassKey[];
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export interface RendererWavefrontTerminationPolicy {
|
|
333
|
+
readonly terminalHitTypes: readonly RendererWavefrontHitType[];
|
|
334
|
+
readonly continuationHitTypes: readonly RendererWavefrontHitType[];
|
|
335
|
+
readonly emissive: Readonly<{
|
|
336
|
+
action: "accumulate-and-stop";
|
|
337
|
+
contributesRadiance: true;
|
|
338
|
+
}>;
|
|
339
|
+
readonly environment: Readonly<{
|
|
340
|
+
action: "accumulate-and-stop";
|
|
341
|
+
contributesRadiance: true;
|
|
342
|
+
}>;
|
|
343
|
+
readonly miss: Readonly<{
|
|
344
|
+
action: "accumulate-environment-or-dark-stop";
|
|
345
|
+
contributesRadiance: true;
|
|
346
|
+
}>;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export interface RendererWavefrontPathTracingPlan {
|
|
350
|
+
readonly schemaVersion: typeof rendererWavefrontBufferSchemaVersion;
|
|
351
|
+
readonly owner: typeof rendererDebugOwner;
|
|
352
|
+
readonly maxDepth: number;
|
|
353
|
+
readonly queueCapacity: number;
|
|
354
|
+
readonly explicitLightSampling: boolean;
|
|
355
|
+
readonly accumulationResetEpoch: number;
|
|
356
|
+
readonly queueLayout: Readonly<{
|
|
357
|
+
strategy: typeof rendererWavefrontQueuePairStrategy;
|
|
358
|
+
compactAfterScatter: true;
|
|
359
|
+
queues: readonly RendererWavefrontQueueDescriptor[];
|
|
360
|
+
}>;
|
|
361
|
+
readonly bufferContracts: Readonly<{
|
|
362
|
+
ray: RendererWavefrontRecordContract;
|
|
363
|
+
hit: RendererWavefrontRecordContract;
|
|
364
|
+
surface: RendererWavefrontRecordContract;
|
|
365
|
+
materialReference: RendererWavefrontRecordContract;
|
|
366
|
+
mediumReference: RendererWavefrontRecordContract;
|
|
367
|
+
accumulation: RendererWavefrontRecordContract;
|
|
368
|
+
}>;
|
|
369
|
+
readonly bounceSchedule: readonly RendererWavefrontBounceStep[];
|
|
370
|
+
readonly terminationPolicy: RendererWavefrontTerminationPolicy;
|
|
371
|
+
}
|
|
372
|
+
|
|
294
373
|
export function getRendererWorkerProfile(
|
|
295
374
|
name?: RendererWorkerProfileName
|
|
296
375
|
): RendererWorkerProfile;
|
|
@@ -309,11 +388,28 @@ export function createRayTracingRenderPlan(options: {
|
|
|
309
388
|
readonly [key: string]: unknown;
|
|
310
389
|
}
|
|
311
390
|
)[];
|
|
391
|
+
wavefront?: {
|
|
392
|
+
maxDepth?: number;
|
|
393
|
+
queueCapacity?: number;
|
|
394
|
+
explicitLightSampling?: boolean;
|
|
395
|
+
accumulationResetEpoch?: number;
|
|
396
|
+
};
|
|
312
397
|
}): RayTracingRenderPlan;
|
|
313
398
|
|
|
399
|
+
export function createWavefrontPathTracingPlan(options?: {
|
|
400
|
+
maxDepth?: number;
|
|
401
|
+
queueCapacity?: number;
|
|
402
|
+
explicitLightSampling?: boolean;
|
|
403
|
+
accumulationResetEpoch?: number;
|
|
404
|
+
}): RendererWavefrontPathTracingPlan;
|
|
405
|
+
|
|
314
406
|
export const rendererRepresentationBands: readonly RendererRepresentationBand[];
|
|
315
407
|
export const rendererAccelerationStructureUpdateClasses: readonly RendererAccelerationStructureUpdateClass[];
|
|
316
408
|
export const rendererRayTracingStageOrder: readonly RendererRenderStage["key"][];
|
|
409
|
+
export const rendererWavefrontBufferSchemaVersion: 1;
|
|
410
|
+
export const rendererWavefrontQueuePairStrategy: "ping-pong-active-next";
|
|
411
|
+
export const rendererWavefrontHitTypes: readonly RendererWavefrontHitType[];
|
|
412
|
+
export const rendererWavefrontPassOrder: readonly RendererWavefrontPassKey[];
|
|
317
413
|
|
|
318
414
|
export const defaultRendererClearColor: readonly [number, number, number, number];
|
|
319
415
|
export const rendererDebugOwner: "renderer";
|
package/src/index.js
CHANGED
|
@@ -27,6 +27,23 @@ export const rendererRayTracingStageOrder = Object.freeze([
|
|
|
27
27
|
"composition",
|
|
28
28
|
"present",
|
|
29
29
|
]);
|
|
30
|
+
export const rendererWavefrontBufferSchemaVersion = 1;
|
|
31
|
+
export const rendererWavefrontQueuePairStrategy = "ping-pong-active-next";
|
|
32
|
+
export const rendererWavefrontHitTypes = Object.freeze([
|
|
33
|
+
"surface",
|
|
34
|
+
"emissive",
|
|
35
|
+
"environment",
|
|
36
|
+
"transparent",
|
|
37
|
+
"miss",
|
|
38
|
+
]);
|
|
39
|
+
export const rendererWavefrontPassOrder = Object.freeze([
|
|
40
|
+
"generatePrimaryRays",
|
|
41
|
+
"intersectActiveQueue",
|
|
42
|
+
"resolveSurfaceRecords",
|
|
43
|
+
"accumulateTerminalRadiance",
|
|
44
|
+
"scatterContinuations",
|
|
45
|
+
"compactAndSwapQueues",
|
|
46
|
+
]);
|
|
30
47
|
|
|
31
48
|
const rendererRayTracingStageDefinitions = Object.freeze(
|
|
32
49
|
rendererRayTracingStageOrder.map((key, index) =>
|
|
@@ -104,6 +121,167 @@ const rendererAccelerationStructurePolicies = Object.freeze(
|
|
|
104
121
|
)
|
|
105
122
|
);
|
|
106
123
|
|
|
124
|
+
function createWavefrontField(name, type, description) {
|
|
125
|
+
return Object.freeze({
|
|
126
|
+
name,
|
|
127
|
+
type,
|
|
128
|
+
description,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const rendererWavefrontBufferContracts = Object.freeze({
|
|
133
|
+
ray: Object.freeze({
|
|
134
|
+
schemaVersion: rendererWavefrontBufferSchemaVersion,
|
|
135
|
+
recordName: "RayRecord",
|
|
136
|
+
fields: Object.freeze([
|
|
137
|
+
createWavefrontField("rayId", "u32", "Stable ray identifier for correlation and debugging."),
|
|
138
|
+
createWavefrontField("parentRayId", "u32", "Parent ray identifier for continuation lineage."),
|
|
139
|
+
createWavefrontField("sourcePixelId", "u32", "Screen pixel or texel that owns the sample."),
|
|
140
|
+
createWavefrontField("sampleId", "u32", "Per-pixel sample slot for accumulation."),
|
|
141
|
+
createWavefrontField("bounce", "u32", "Breadth-first bounce depth for the queue entry."),
|
|
142
|
+
createWavefrontField("origin", "vec3<f32>", "Ray origin in renderer world space."),
|
|
143
|
+
createWavefrontField("direction", "vec3<f32>", "Normalized ray direction in renderer world space."),
|
|
144
|
+
createWavefrontField("throughput", "vec3<f32>", "Current path throughput before the next event."),
|
|
145
|
+
createWavefrontField("mediumRefId", "u32", "Active medium reference identifier for the ray."),
|
|
146
|
+
createWavefrontField("flags", "u32", "Bit flags for front-face state, debug, and quality toggles."),
|
|
147
|
+
]),
|
|
148
|
+
}),
|
|
149
|
+
hit: Object.freeze({
|
|
150
|
+
schemaVersion: rendererWavefrontBufferSchemaVersion,
|
|
151
|
+
recordName: "HitRecord",
|
|
152
|
+
fields: Object.freeze([
|
|
153
|
+
createWavefrontField("rayId", "u32", "Ray identifier copied from the active queue."),
|
|
154
|
+
createWavefrontField("sourcePixelId", "u32", "Pixel/texel owner for the ray sample."),
|
|
155
|
+
createWavefrontField("hitType", rendererWavefrontHitTypes.join(" | "), "Resolved hit classification for termination or continuation."),
|
|
156
|
+
createWavefrontField("distance", "f32", "Nearest-hit distance or miss sentinel."),
|
|
157
|
+
createWavefrontField("entityId", "u32", "Stable scene entity identifier."),
|
|
158
|
+
createWavefrontField("instanceId", "u32", "Renderer instance identifier."),
|
|
159
|
+
createWavefrontField("primitiveId", "u32", "Primitive or triangle identifier."),
|
|
160
|
+
createWavefrontField("materialId", "u32", "Surface material identifier."),
|
|
161
|
+
createWavefrontField("barycentrics", "vec3<f32>", "Triangle barycentric coordinates for interpolation."),
|
|
162
|
+
createWavefrontField("uv", "vec2<f32>", "Resolved surface UV when available."),
|
|
163
|
+
createWavefrontField("geometricNormal", "vec3<f32>", "True geometric face normal."),
|
|
164
|
+
createWavefrontField("shadingNormal", "vec3<f32>", "Interpolated or repaired shading normal."),
|
|
165
|
+
createWavefrontField("frontFace", "bool", "Front-face classification for shading and medium transitions."),
|
|
166
|
+
]),
|
|
167
|
+
}),
|
|
168
|
+
surface: Object.freeze({
|
|
169
|
+
schemaVersion: rendererWavefrontBufferSchemaVersion,
|
|
170
|
+
recordName: "SurfaceRecord",
|
|
171
|
+
fields: Object.freeze([
|
|
172
|
+
createWavefrontField("rayId", "u32", "Ray identifier matched to the resolved hit."),
|
|
173
|
+
createWavefrontField("entityId", "u32", "Stable scene entity identifier."),
|
|
174
|
+
createWavefrontField("materialRefId", "u32", "Material-reference indirection for shading lookup tables."),
|
|
175
|
+
createWavefrontField("mediumRefId", "u32", "Resolved medium transition/reference identifier."),
|
|
176
|
+
createWavefrontField("geometricNormal", "vec3<f32>", "Preserved geometric normal for hemisphere checks."),
|
|
177
|
+
createWavefrontField("shadingNormal", "vec3<f32>", "Normal used for BSDF/BTDF evaluation."),
|
|
178
|
+
createWavefrontField("uv", "vec2<f32>", "Resolved texture coordinate."),
|
|
179
|
+
createWavefrontField("tangentFrame", "mat3x3<f32>", "Optional tangent basis for normal-map transforms."),
|
|
180
|
+
]),
|
|
181
|
+
}),
|
|
182
|
+
materialReference: Object.freeze({
|
|
183
|
+
schemaVersion: rendererWavefrontBufferSchemaVersion,
|
|
184
|
+
recordName: "MaterialReferenceRecord",
|
|
185
|
+
fields: Object.freeze([
|
|
186
|
+
createWavefrontField("materialRefId", "u32", "Stable material lookup identifier."),
|
|
187
|
+
createWavefrontField("materialId", "u32", "Authoritative material id from scene submission."),
|
|
188
|
+
createWavefrontField("shadingModel", "u32", "Renderer-owned shading model enum."),
|
|
189
|
+
createWavefrontField("textureSetId", "u32", "Texture indirection set for the material."),
|
|
190
|
+
createWavefrontField("flags", "u32", "Alpha, emissive, transmission, and debug flags."),
|
|
191
|
+
]),
|
|
192
|
+
}),
|
|
193
|
+
mediumReference: Object.freeze({
|
|
194
|
+
schemaVersion: rendererWavefrontBufferSchemaVersion,
|
|
195
|
+
recordName: "MediumReferenceRecord",
|
|
196
|
+
fields: Object.freeze([
|
|
197
|
+
createWavefrontField("mediumRefId", "u32", "Stable medium lookup identifier."),
|
|
198
|
+
createWavefrontField("mediumId", "u32", "Authoritative medium or fluid descriptor id."),
|
|
199
|
+
createWavefrontField("phaseModel", "u32", "Medium phase-function selector."),
|
|
200
|
+
createWavefrontField("absorption", "vec3<f32>", "Absorption coefficients for the active medium."),
|
|
201
|
+
createWavefrontField("scattering", "vec3<f32>", "Scattering coefficients for the active medium."),
|
|
202
|
+
]),
|
|
203
|
+
}),
|
|
204
|
+
accumulation: Object.freeze({
|
|
205
|
+
schemaVersion: rendererWavefrontBufferSchemaVersion,
|
|
206
|
+
recordName: "AccumulationRecord",
|
|
207
|
+
fields: Object.freeze([
|
|
208
|
+
createWavefrontField("sourcePixelId", "u32", "Screen pixel or texel accumulator owner."),
|
|
209
|
+
createWavefrontField("sampleCount", "u32", "Committed sample count for the pixel."),
|
|
210
|
+
createWavefrontField("radiance", "vec3<f32>", "Accumulated radiance before tone-map/output resolve."),
|
|
211
|
+
createWavefrontField("throughput", "vec3<f32>", "Last surviving throughput for debug and variance tracking."),
|
|
212
|
+
createWavefrontField("resetEpoch", "u32", "Accumulation reset generation for history invalidation."),
|
|
213
|
+
]),
|
|
214
|
+
}),
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
function buildWavefrontTerminationPolicy() {
|
|
218
|
+
return Object.freeze({
|
|
219
|
+
terminalHitTypes: Object.freeze(["emissive", "environment", "miss"]),
|
|
220
|
+
continuationHitTypes: Object.freeze(["surface", "transparent"]),
|
|
221
|
+
emissive: Object.freeze({
|
|
222
|
+
action: "accumulate-and-stop",
|
|
223
|
+
contributesRadiance: true,
|
|
224
|
+
}),
|
|
225
|
+
environment: Object.freeze({
|
|
226
|
+
action: "accumulate-and-stop",
|
|
227
|
+
contributesRadiance: true,
|
|
228
|
+
}),
|
|
229
|
+
miss: Object.freeze({
|
|
230
|
+
action: "accumulate-environment-or-dark-stop",
|
|
231
|
+
contributesRadiance: true,
|
|
232
|
+
}),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function buildWavefrontBounceSchedule(maxDepth) {
|
|
237
|
+
return Object.freeze(
|
|
238
|
+
Array.from({ length: maxDepth }, (_, index) =>
|
|
239
|
+
Object.freeze({
|
|
240
|
+
bounce: index,
|
|
241
|
+
readQueue: index % 2 === 0 ? "active" : "next",
|
|
242
|
+
writeQueue: index % 2 === 0 ? "next" : "active",
|
|
243
|
+
passOrder: rendererWavefrontPassOrder,
|
|
244
|
+
})
|
|
245
|
+
)
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function createWavefrontPathTracingPlan(options = {}) {
|
|
250
|
+
const maxDepth =
|
|
251
|
+
options.maxDepth === undefined
|
|
252
|
+
? 6
|
|
253
|
+
: readPositiveInteger("maxDepth", options.maxDepth);
|
|
254
|
+
const queueCapacity =
|
|
255
|
+
options.queueCapacity === undefined
|
|
256
|
+
? 8192
|
|
257
|
+
: readPositiveInteger("queueCapacity", options.queueCapacity);
|
|
258
|
+
const accumulationResetEpoch =
|
|
259
|
+
options.accumulationResetEpoch === undefined
|
|
260
|
+
? 0
|
|
261
|
+
: readNonNegativeInteger("accumulationResetEpoch", options.accumulationResetEpoch);
|
|
262
|
+
const explicitLightSampling = options.explicitLightSampling === true;
|
|
263
|
+
|
|
264
|
+
return Object.freeze({
|
|
265
|
+
schemaVersion: rendererWavefrontBufferSchemaVersion,
|
|
266
|
+
owner: rendererDebugOwner,
|
|
267
|
+
maxDepth,
|
|
268
|
+
queueCapacity,
|
|
269
|
+
explicitLightSampling,
|
|
270
|
+
accumulationResetEpoch,
|
|
271
|
+
queueLayout: Object.freeze({
|
|
272
|
+
strategy: rendererWavefrontQueuePairStrategy,
|
|
273
|
+
compactAfterScatter: true,
|
|
274
|
+
queues: Object.freeze([
|
|
275
|
+
Object.freeze({ name: "active", role: "current-bounce" }),
|
|
276
|
+
Object.freeze({ name: "next", role: "next-bounce" }),
|
|
277
|
+
]),
|
|
278
|
+
}),
|
|
279
|
+
bufferContracts: rendererWavefrontBufferContracts,
|
|
280
|
+
bounceSchedule: buildWavefrontBounceSchedule(maxDepth),
|
|
281
|
+
terminationPolicy: buildWavefrontTerminationPolicy(),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
107
285
|
function buildRendererWorkerBudgetLevels(jobType, queueClass, levels) {
|
|
108
286
|
return Object.freeze(
|
|
109
287
|
levels.map((level) =>
|
|
@@ -678,6 +856,7 @@ export function createRayTracingRenderPlan(options = {}) {
|
|
|
678
856
|
renderStages: workerManifest.renderStages,
|
|
679
857
|
representationBands: representations,
|
|
680
858
|
accelerationStructureUpdates: workerManifest.accelerationStructureUpdates,
|
|
859
|
+
wavefront: createWavefrontPathTracingPlan(options.wavefront),
|
|
681
860
|
workerManifest,
|
|
682
861
|
});
|
|
683
862
|
}
|
|
@@ -732,6 +911,20 @@ function readPositiveNumber(name, value) {
|
|
|
732
911
|
return value;
|
|
733
912
|
}
|
|
734
913
|
|
|
914
|
+
function readPositiveInteger(name, value) {
|
|
915
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
916
|
+
throw new Error(`${name} must be a positive integer.`);
|
|
917
|
+
}
|
|
918
|
+
return value;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function readNonNegativeInteger(name, value) {
|
|
922
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
923
|
+
throw new Error(`${name} must be a non-negative integer.`);
|
|
924
|
+
}
|
|
925
|
+
return value;
|
|
926
|
+
}
|
|
927
|
+
|
|
735
928
|
function now() {
|
|
736
929
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
737
930
|
return performance.now();
|