feat: add color grading 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:
@@ -10,13 +10,13 @@ import {
|
||||
spawnRequestedNode,
|
||||
} from "../static/render-graph/node-spawn.js";
|
||||
|
||||
test("add-node model contains all 13 catalog types in application groups", () => {
|
||||
assert.equal(addNodeItems.length, 13);
|
||||
test("add-node model contains all 17 catalog types in application groups", () => {
|
||||
assert.equal(addNodeItems.length, 17);
|
||||
assert.deepEqual(
|
||||
[...new Set(addNodeItems.map((item) => item.group))],
|
||||
["Source", "Compute", "CPU preparation", "Render / post", "Frame"],
|
||||
);
|
||||
assert.equal(new Set(addNodeItems.map((item) => item.typeId)).size, 13);
|
||||
assert.equal(new Set(addNodeItems.map((item) => item.typeId)).size, 17);
|
||||
assert.deepEqual(
|
||||
searchAddNodeItems("tone render").map((item) => item.typeId),
|
||||
["tone_map"],
|
||||
@@ -40,7 +40,7 @@ test("allocator avoids existing and session-reserved IDs and is bounded", () =>
|
||||
);
|
||||
});
|
||||
|
||||
test("all 13 types spawn with exact position, current version and generated ID", async () => {
|
||||
test("all 17 types spawn with exact position, current version and generated ID", async () => {
|
||||
let revision = 5,
|
||||
expectedType;
|
||||
const request = { compositionRevision: 5, viewPosition: { x: 12.25, y: -4 } };
|
||||
|
||||
@@ -36,8 +36,8 @@ test("production render graph composition passes fxnode's public validator", asy
|
||||
result.ok ? undefined : JSON.stringify(result.issues, null, 2),
|
||||
);
|
||||
assert.equal(fxNodeComposition.schemaVersion, 2);
|
||||
assert.equal(fxNodeComposition.version, 4);
|
||||
assert.equal(Object.keys(fxNodeComposition.nodes).length, 13);
|
||||
assert.equal(fxNodeComposition.version, 5);
|
||||
assert.equal(Object.keys(fxNodeComposition.nodes).length, 17);
|
||||
assert.ok(
|
||||
Object.values(fxNodeComposition.nodes).every(
|
||||
(definition) => definition.migrations.length === 0,
|
||||
|
||||
@@ -111,6 +111,10 @@ test("catalog exhaustively mirrors all current contracts", () => {
|
||||
"pipeline",
|
||||
"fullscreen_copy",
|
||||
"tone_map",
|
||||
"color_balance",
|
||||
"exposure_contrast",
|
||||
"saturation",
|
||||
"channel_mixer",
|
||||
"bloom_extract",
|
||||
"bloom_blur",
|
||||
"bloom_composite",
|
||||
@@ -130,7 +134,7 @@ test("catalog exhaustively mirrors all current contracts", () => {
|
||||
Object.keys(contract.parameters).sort(),
|
||||
key,
|
||||
);
|
||||
assert.equal(CATALOG_VERSION, 4);
|
||||
assert.equal(CATALOG_VERSION, 5);
|
||||
assert.deepEqual(nodeDefinitions.pipeline.parameters, {
|
||||
pipeline: {
|
||||
type: "string",
|
||||
@@ -175,6 +179,26 @@ test("catalog exhaustively mirrors all current contracts", () => {
|
||||
value: true,
|
||||
});
|
||||
assert.equal(nodeDefinitions.mesh_query.sockets.isVisible.showValue, true);
|
||||
|
||||
assert.deepEqual(nodeDefinitions.color_balance.ui.slice(0, 4), [
|
||||
{ kind: "parameter", parameter: "mode" },
|
||||
{ kind: "widget", widget: "grading-wheels", bindings: [
|
||||
{ title: "Lift", scalar: "lift", color: "liftColor" },
|
||||
{ title: "Gamma", scalar: "gamma", color: "gammaColor" },
|
||||
{ title: "Gain", scalar: "gain", color: "gainColor" },
|
||||
], visibleWhen: { parameter: "mode", equals: "lift_gamma_gain" } },
|
||||
{ kind: "widget", widget: "grading-wheels", bindings: [
|
||||
{ title: "Offset", scalar: "offset", color: "offsetColor" },
|
||||
{ title: "Power", scalar: "power", color: "powerColor" },
|
||||
{ title: "Slope", scalar: "slope", color: "slopeColor" },
|
||||
], visibleWhen: { parameter: "mode", equals: "offset_power_slope" } },
|
||||
{ kind: "parameter", parameter: "factor" },
|
||||
]);
|
||||
for (const name of ["liftColor", "gammaColor", "gainColor", "offsetColor", "powerColor", "slopeColor"])
|
||||
assert.deepEqual(nodeDefinitions.color_balance.parameters[name].default, { kind: "color", value: [1, 1, 1, 1] });
|
||||
assert.deepEqual(nodeDefinitions.channel_mixer.parameters.redOutput, {
|
||||
type: "vector", default: { kind: "vector", value: [1, 0, 0] }, minimum: -2, maximum: 2,
|
||||
});
|
||||
});
|
||||
|
||||
test("adapter validates and exactly lowers canonical pipeline controls and blur direction", () => {
|
||||
|
||||
@@ -9,6 +9,7 @@ const order = [
|
||||
"hdr",
|
||||
"culling",
|
||||
"tone",
|
||||
"grading",
|
||||
"edges",
|
||||
"bloom",
|
||||
"combined",
|
||||
@@ -72,6 +73,12 @@ const sequences = {
|
||||
["tone", "tone_map"],
|
||||
["frame_out", "frame_out"],
|
||||
],
|
||||
grading: [
|
||||
["balance_hdr", "texture"], ["exposure_hdr", "texture"], ["saturation_hdr", "texture"], ["mixer_hdr", "texture"], ["ldr", "texture"],
|
||||
["hdr", "texture"], ["depth", "texture"], ["mesh", "mesh"], ["query", "mesh_query"], ["registry", "pipeline_registry"],
|
||||
["ground", "pipeline"], ["pbr", "pipeline"], ["pbr_double", "pipeline"], ["balance", "color_balance"], ["exposure", "exposure_contrast"],
|
||||
["saturation", "saturation"], ["mixer", "channel_mixer"], ["tone", "tone_map"], ["frame_out", "frame_out"],
|
||||
],
|
||||
edges: [
|
||||
["ldr", "texture"],
|
||||
["edge_hdr", "texture"],
|
||||
@@ -143,6 +150,7 @@ test("presets have the exact canonical pipeline identities, schemas, and node se
|
||||
"preset_hdr_fullscreen",
|
||||
"preset_gpu_culling",
|
||||
"preset_tone",
|
||||
"preset_grading",
|
||||
"preset_edges",
|
||||
"preset_bloom",
|
||||
"preset_combined",
|
||||
@@ -175,6 +183,16 @@ test("presets have the exact canonical pipeline identities, schemas, and node se
|
||||
),
|
||||
);
|
||||
}
|
||||
const grading = presets.grading;
|
||||
assert.deepEqual(grading.nodes.find((n) => n.id === "balance").parameters, {
|
||||
mode: "lift_gamma_gain", factor: 1, lift: 0, liftColor: [1,1,1,1],
|
||||
gamma: 1, gammaColor: [1,1,1,1], gain: 1, gainColor: [1,1,1,1],
|
||||
offset: 0, offsetColor: [1,1,1,1], power: 1, powerColor: [1,1,1,1],
|
||||
slope: 1, slopeColor: [1,1,1,1],
|
||||
});
|
||||
assert.deepEqual(grading.nodes.find((n) => n.id === "exposure").parameters, { exposureStops: 0, contrast: 1, pivot: .18, factor: 1 });
|
||||
assert.deepEqual(grading.nodes.find((n) => n.id === "saturation").parameters, { saturation: 1, factor: 1 });
|
||||
assert.deepEqual(grading.nodes.find((n) => n.id === "mixer").parameters, { redOutput: [1,0,0], greenOutput: [0,1,0], blueOutput: [0,0,1], factor: 1 });
|
||||
});
|
||||
|
||||
test("presets preserve common mesh, texture, query, pipeline, culling and post wiring", () => {
|
||||
@@ -264,12 +282,13 @@ test("presets preserve common mesh, texture, query, pipeline, culling and post w
|
||||
node: "cull",
|
||||
socket: "isFrustumCulled",
|
||||
});
|
||||
for (const name of ["tone", "edges", "bloom", "combined"])
|
||||
for (const name of ["tone", "grading", "edges", "bloom", "combined"])
|
||||
assert.ok(!presets[name].nodes.some((node) => node.id === "copy"));
|
||||
const finalSource = {
|
||||
hdr: "pbr_double",
|
||||
culling: "pbr_double",
|
||||
tone: "tone",
|
||||
grading: "tone",
|
||||
edges: "tone",
|
||||
bloom: "tone",
|
||||
combined: "tone",
|
||||
|
||||
Reference in New Issue
Block a user