Opaque/mask draws sharing a pipeline and bind set become rows of one persistent `draws.<id>` indirect array (32-byte indexed commands, geometric capacity, inactive tail zeroed) drawn by a single graph pass, so the graph holds one pass per bucket instead of one per mesh. Transmission and blend draws stay direct and ordered after the buckets. Scene requires the indirect-first-instance feature. Compiles re-assert the bundle block when they start, since an earlier switch in the queue clears the one set at enqueue time. Amp-Thread-ID: https://ampcode.com/threads/T-01a0b2dd-db32-712d-99ce-12ce4a86d979 Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
82 lines
2.3 KiB
TypeScript
82 lines
2.3 KiB
TypeScript
import { Mesh } from "../src/Mesh";
|
|
import { Scene } from "../src/Scene";
|
|
import type { PBRMaterial } from "../src/materials/PBRMaterial";
|
|
import type { YawnCore } from "./core-mock";
|
|
|
|
export const triangle = {
|
|
positions: [-1, -1, 0, 1, -1, 0, 0, 1, 0],
|
|
normals: [0, 0, 1, 0, 0, 1, 0, 0, 1],
|
|
tangents: [1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1],
|
|
uvs: [0, 0, 1, 0, 0.5, 1],
|
|
uvs2: [0.1, 0.1, 0.9, 0.1, 0.5, 0.9],
|
|
colors: [1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1],
|
|
indices: [0, 1, 2],
|
|
};
|
|
|
|
export async function createScene(
|
|
options: ConstructorParameters<typeof Scene>[1] = {},
|
|
) {
|
|
const scene = new Scene({} as HTMLCanvasElement, options);
|
|
await scene.ready;
|
|
return scene;
|
|
}
|
|
|
|
export function testCore(scene: Scene) {
|
|
return scene.core as unknown as YawnCore;
|
|
}
|
|
|
|
export function latestGraph(scene: Scene): any {
|
|
return testCore(scene).graphs.at(-1);
|
|
}
|
|
|
|
export function renderPipeline(graph: any, id: string) {
|
|
return graph.pipelines.render.find((pipeline: any) => pipeline.id === id);
|
|
}
|
|
|
|
export function pbrPipelines(graph: any) {
|
|
return graph.pipelines.render.filter((pipeline: any) =>
|
|
pipeline.id.startsWith("forward-pbr-"),
|
|
);
|
|
}
|
|
|
|
export function forwardPasses(graph: any) {
|
|
return graph.passes.filter(
|
|
(pass: any) =>
|
|
pass.type === "render" && pass.pipeline.startsWith("forward-"),
|
|
);
|
|
}
|
|
|
|
export function detailedMesh(
|
|
scene: Scene,
|
|
material: PBRMaterial,
|
|
vertexData: Record<string, ArrayLike<number>> = triangle,
|
|
) {
|
|
return new Mesh(scene, { material, vertexData });
|
|
}
|
|
|
|
/** Decodes the active indirect rows of every forward bucket pass, in pass order. */
|
|
export function bucketDraws(scene: Scene, graph: any) {
|
|
return forwardPasses(graph)
|
|
.filter((pass: any) => pass.indirect)
|
|
.flatMap((pass: any) => {
|
|
const buffer = graph.resources.buffers.find(
|
|
(buffer: any) => buffer.id === pass.indirect.resource,
|
|
);
|
|
const view = scene.core.array(buffer.array).view;
|
|
const draws = [];
|
|
for (let row = 0; row * 8 < view.length; row++) {
|
|
const [indices, instances, firstIndex, baseVertex, firstInstance] =
|
|
view.subarray(row * 8, row * 8 + 5);
|
|
if (instances)
|
|
draws.push({
|
|
pass: pass.id,
|
|
indices,
|
|
firstIndex,
|
|
baseVertex,
|
|
firstInstance,
|
|
});
|
|
}
|
|
return draws;
|
|
});
|
|
}
|