refactor: redesign render graph nodes

Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab

Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-07-28 13:00:29 +00:00
co-authored by heaust
parent fc8c16daec
commit edc7c8ef29
23 changed files with 5229 additions and 1810 deletions
+56 -258
View File
@@ -1,278 +1,76 @@
const input = (node, socket) => ({ node, socket });
const node = (id, key, parameters = {}, inputs = {}) => ({
id,
state: "enabled",
executor: { key, version: 1 },
parameters,
inputs,
id, state: "enabled", executor: { key, version: 1 }, parameters, inputs,
});
const texture = (format) => ({
const texture = (format, scale = 1) => ({
texture: {
dimension: "d2",
format,
extent: {
kind: "surface_relative",
width: { numerator: 1, denominator: 1 },
height: { numerator: 1, denominator: 1 },
depthOrArrayLayers: 1,
},
mipLevelCount: 1,
sampleCount: 1,
viewFormats: [],
dimension: "d2", format,
extent: { kind: "surface_relative", width: { numerator: 1, denominator: scale }, height: { numerator: 1, denominator: scale }, depthOrArrayLayers: 1 },
mipLevelCount: 1, sampleCount: 1, viewFormats: [],
},
residency: "transient",
});
const direct = (graphId, clearColor) => Object.freeze({
schemaVersion: 2,
graphId,
revision: 1,
nodes: [
node("surface", "surface_target"),
node("depth", "texture_spec", texture("depth32_float")),
node("scene", "scene_table"),
node("visible", "visibility_flags", {}, { scene: input("scene", "scene") }),
node("query", "mesh_query", {
filters: [
{ flag: "isVisible", predicate: "required_true" },
{ flag: "isFrustumCulled", predicate: "any" },
],
}, { scene: input("scene", "scene"), isVisible: input("visible", "flags") }),
node("depth_config", "depth_stencil_config", {
depthCompare: "less_equal",
depthWriteEnabled: true,
clearDepth: 1,
}),
node("forward", "legacy_forward", { clearColor }, {
scene: input("scene", "scene"),
draws: input("query", "draws"),
colorTarget: input("surface", "surface"),
depthTarget: input("depth", "spec"),
depthStencil: input("depth_config", "config"),
}),
node("present", "present", {}, { surface: input("forward", "color") }),
],
});
const scene = (colorTarget, clearColor = [0.015, 0.02, 0.03, 1]) => [
node("hdr", "texture", texture("rgba16_float")),
node("depth", "texture", texture("depth32_float")),
node("mesh", "mesh"),
node("query", "mesh_query", { visiblePredicate: "required_true", visibleDefault: true, frustumCulledPredicate: "any", frustumCulledDefault: false }, { mesh: input("mesh", "mesh"), isVisible: input("mesh", "isVisible") }),
node("registry", "pipeline_registry", {}, { pipelineIndices: input("mesh", "pipelineIndices") }),
node("ground", "pipeline", { pipeline: "ground_plane", depthCompare: "less_equal", depthWriteEnabled: true, clearDepth: 1, clearColor }, { mesh: input("mesh", "mesh"), draws: input("query", "draws"), activation: input("registry", "activation"), colorTarget: input(colorTarget, "texture"), depthTarget: input("depth", "texture") }),
node("pbr", "pipeline", { pipeline: "gltf_standard", depthCompare: "less_equal", depthWriteEnabled: true, clearDepth: 1, clearColor }, { mesh: input("mesh", "mesh"), draws: input("query", "draws"), activation: input("registry", "activation"), colorTarget: input("ground", "color"), depthTarget: input("ground", "depth") }),
node("pbr_double", "pipeline", { pipeline: "gltf_standard_double_sided", depthCompare: "less_equal", depthWriteEnabled: true, clearDepth: 1, clearColor }, { mesh: input("mesh", "mesh"), draws: input("query", "draws"), activation: input("registry", "activation"), colorTarget: input("pbr", "color"), depthTarget: input("pbr", "depth") }),
];
const graph = (graphId, nodes) => Object.freeze({ schemaVersion: 2, graphId, revision: 1, nodes });
const direct = (graphId, clearColor) => graph(graphId, [
node("ldr", "texture", texture("rgba8_unorm")),
...scene("ldr", clearColor).filter((item) => item.id !== "hdr"),
node("frame_out", "frame_out", {}, { color: input("pbr_double", "color") }),
]);
export const midnight = direct("preset_midnight", [0.015, 0.06, 0.18, 1]);
export const ember = direct("preset_ember", [0.18, 0.035, 0.012, 1]);
export const hdr = Object.freeze({
schemaVersion: 2,
graphId: "preset_hdr_fullscreen",
revision: 1,
nodes: [
node("surface", "surface_target"),
node("hdr", "texture_spec", texture("rgba16_float")),
node("depth", "texture_spec", texture("depth32_float")),
node("scene", "scene_table"),
node("visible", "visibility_flags", {}, { scene: input("scene", "scene") }),
node(
"query",
"mesh_query",
{
filters: [
{ flag: "isVisible", predicate: "required_true" },
{ flag: "isFrustumCulled", predicate: "any" },
],
},
{ scene: input("scene", "scene"), isVisible: input("visible", "flags") },
),
node("depth_config", "depth_stencil_config", {
depthCompare: "less_equal",
depthWriteEnabled: true,
clearDepth: 1,
}),
node(
"forward",
"legacy_forward",
{ clearColor: [0.015, 0.02, 0.03, 1] },
{
scene: input("scene", "scene"),
draws: input("query", "draws"),
colorTarget: input("hdr", "spec"),
depthTarget: input("depth", "spec"),
depthStencil: input("depth_config", "config"),
},
),
node(
"copy",
"fullscreen_copy",
{},
{
source: input("forward", "color"),
colorTarget: input("surface", "surface"),
},
),
node("present", "present", {}, { surface: input("copy", "color") }),
],
});
export const culling = Object.freeze((() => {
const graph = structuredClone(hdr);
graph.graphId = "preset_gpu_culling";
graph.nodes.splice(
5,
0,
node("aabbs", "local_aabb_buffer", {}, { scene: input("scene", "scene") }),
node("frustum", "camera_frustum"),
node("cull", "frustum_cull", {}, {
scene: input("scene", "scene"),
localAabbs: input("aabbs", "localAabbs"),
frustum: input("frustum", "frustum"),
}),
);
const query = graph.nodes.find((x) => x.id === "query");
query.parameters.filters[1].predicate = "required_false";
query.inputs.isFrustumCulled = input("cull", "flags");
return graph;
export const hdr = graph("preset_hdr_fullscreen", [
...scene("hdr"),
node("frame_out", "frame_out", {}, { color: input("pbr_double", "color") }),
]);
export const culling = graph("preset_gpu_culling", (() => {
const nodes = structuredClone(hdr.nodes);
nodes.splice(3, 0, node("cull", "frustum_cull", { camera: "active" }, { mesh: input("mesh", "mesh"), localAabbs: input("mesh", "localAabbs") }));
const query = nodes.find((item) => item.id === "query");
query.parameters.frustumCulledPredicate = "required_false";
query.inputs.isFrustumCulled = input("cull", "isFrustumCulled");
return nodes;
})());
const postPreset = (graphId, kind) => {
const nodes = hdr.nodes.slice(0, 8).map((x) => structuredClone(x));
if (kind === "tone")
nodes.push(
node(
"tone",
"tone_map",
{ exposure: 1 },
{
source: input("forward", "color"),
colorTarget: input("surface", "surface"),
},
),
);
const nodes = [node("ldr", "texture", texture("rgba8_unorm")), ...scene("hdr")];
let source = "pbr_double";
if (kind === "edges") {
nodes.splice(1, 0, node("edge_hdr", "texture_spec", texture("rgba16_float")));
nodes.push(
node(
"edges",
"luminance_edge",
{ strength: 2 },
{
source: input("forward", "color"),
colorTarget: input("edge_hdr", "spec"),
},
),
);
nodes.push(
node(
"tone",
"tone_map",
{ exposure: 1 },
{
source: input("edges", "color"),
colorTarget: input("surface", "surface"),
},
),
);
nodes.splice(1, 0, node("edge_hdr", "texture", texture("rgba16_float")));
nodes.push(node("edges", "luminance_edge", { strength: 2 }, { source: input(source, "color"), colorTarget: input("edge_hdr", "texture") }));
source = "edges";
}
if (kind === "bloom" || kind === "combined") {
const half = {
texture: {
...texture("rgba16_float").texture,
extent: {
kind: "surface_relative",
width: { numerator: 1, denominator: 2 },
height: { numerator: 1, denominator: 2 },
depthOrArrayLayers: 1,
},
},
residency: "transient",
};
nodes.splice(
1,
0,
node("half_a", "texture_spec", structuredClone(half)),
node("half_b", "texture_spec", structuredClone(half)),
node("half_c", "texture_spec", structuredClone(half)),
node("composite_hdr", "texture_spec", texture("rgba16_float")),
);
nodes.splice(1, 0,
node("half_a", "texture", texture("rgba16_float", 2)), node("half_b", "texture", texture("rgba16_float", 2)),
node("half_c", "texture", texture("rgba16_float", 2)), node("composite_hdr", "texture", texture("rgba16_float")));
nodes.push(
node(
"extract",
"bloom_extract",
{ threshold: 1, knee: 0.5 },
{
source: input("forward", "color"),
colorTarget: input("half_a", "spec"),
},
),
node("extract", "bloom_extract", { threshold: 1, knee: 0.5 }, { source: input("pbr_double", "color"), colorTarget: input("half_a", "texture") }),
node("blur_h", "bloom_blur", { direction: [1, 0], radius: 1 }, { source: input("extract", "color"), colorTarget: input("half_b", "texture") }),
node("blur_v", "bloom_blur", { direction: [0, 1], radius: 1 }, { source: input("blur_h", "color"), colorTarget: input("half_c", "texture") }),
node("composite", "bloom_composite", { intensity: 0.8 }, { source: input("pbr_double", "color"), bloom: input("blur_v", "color"), colorTarget: input("composite_hdr", "texture") }),
);
nodes.push(
node(
"blur_h",
"bloom_blur",
{ direction: [1, 0], radius: 1 },
{
source: input("extract", "color"),
colorTarget: input("half_b", "spec"),
},
),
);
nodes.push(
node(
"blur_v",
"bloom_blur",
{ direction: [0, 1], radius: 1 },
{
source: input("blur_h", "color"),
colorTarget: input("half_c", "spec"),
},
),
);
nodes.push(
node(
"composite",
"bloom_composite",
{ intensity: 0.8 },
{
source: input("forward", "color"),
bloom: input("blur_v", "color"),
colorTarget: input("composite_hdr", "spec"),
},
),
);
let toneSource = "composite";
source = "composite";
if (kind === "combined") {
nodes.splice(1, 0, node("edge_hdr", "texture_spec", texture("rgba16_float")));
nodes.push(
node(
"edges",
"luminance_edge",
{ strength: 2 },
{
source: input("composite", "color"),
colorTarget: input("edge_hdr", "spec"),
},
),
);
toneSource = "edges";
nodes.splice(1, 0, node("edge_hdr", "texture", texture("rgba16_float")));
nodes.push(node("edges", "luminance_edge", { strength: 2 }, { source: input(source, "color"), colorTarget: input("edge_hdr", "texture") }));
source = "edges";
}
nodes.push(
node(
"tone",
"tone_map",
{ exposure: 1 },
{
source: input(toneSource, "color"),
colorTarget: input("surface", "surface"),
},
),
);
}
const last = nodes.at(-1);
nodes.push(
node("present", "present", {}, { surface: input(last.id, "color") }),
);
return Object.freeze({ schemaVersion: 2, graphId, revision: 1, nodes });
nodes.push(node("tone", "tone_map", { exposure: 1 }, { source: input(source, "color"), colorTarget: input("ldr", "texture") }));
nodes.push(node("frame_out", "frame_out", {}, { color: input("tone", "color") }));
return graph(graphId, nodes);
};
export const tone = postPreset("preset_tone", "tone"),
edges = postPreset("preset_edges", "edges"),
bloom = postPreset("preset_bloom", "bloom"),
combined = postPreset("preset_combined", "combined");
export const renderGraphPresets = Object.freeze({
midnight,
ember,
hdr,
culling,
tone,
edges,
bloom,
combined,
});
export const tone = postPreset("preset_tone", "tone");
export const edges = postPreset("preset_edges", "edges");
export const bloom = postPreset("preset_bloom", "bloom");
export const combined = postPreset("preset_combined", "combined");
export const renderGraphPresets = Object.freeze({ midnight, ember, hdr, culling, tone, edges, bloom, combined });