From 01fa2135bbd027073dea5240c32b09df5f92e8de Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 18 May 2026 22:53:45 +0100 Subject: [PATCH] Sample Huginn particle albedo from artwork --- inspector/src/HuginnFieldCanvas.tsx | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/inspector/src/HuginnFieldCanvas.tsx b/inspector/src/HuginnFieldCanvas.tsx index 58df7a1..3bf559f 100644 --- a/inspector/src/HuginnFieldCanvas.tsx +++ b/inspector/src/HuginnFieldCanvas.tsx @@ -102,6 +102,7 @@ struct SimUniforms { @group(0) @binding(2) var fieldSampler: sampler; @group(0) @binding(3) var fieldTexture: texture_2d; @group(0) @binding(4) var nodeEnvelopes: array; +@group(0) @binding(5) var albedoTexture: texture_2d; fn hash(value: f32) -> f32 { return fract(sin(value * 12.9898) * 43758.5453); @@ -170,6 +171,10 @@ fn samplePacked(uv: vec2f) -> vec4f { return textureSampleLevel(fieldTexture, fieldSampler, clamp(uv, vec2f(0.001), vec2f(0.999)), 0.0); } +fn sampleAlbedo(uv: vec2f) -> vec4f { + return textureSampleLevel(albedoTexture, fieldSampler, clamp(uv, vec2f(0.001), vec2f(0.999)), 0.0); +} + fn channelGradient(uv: vec2f, channel: u32) -> vec2f { let step = vec2f(1.0 / 256.0, 1.0 / 256.0) / max(uniforms.detail, 1.0); let left = samplePacked(uv - vec2f(step.x, 0.0)); @@ -271,10 +276,13 @@ fn updateParticles(@builtin(global_invocation_id) id: vec3u) { let flowAxis = abs(fieldVector.x - fieldVector.y); let heat = clamp(packed.a * 0.78 + packed.b * 0.62 + nodeHeat * 0.38 + fade * 0.18, 0.0, 1.0); let brass = clamp((packed.b - packed.a * 0.32) * 1.35 + flowAxis * 0.18, 0.0, 1.0); + let albedo = sampleAlbedo(uv); let cyan = vec3f(0.08 + heat * 0.28, 0.44 + heat * 0.46, 0.52 + heat * 0.62); let gold = vec3f(0.86, 0.58, 0.22); let deep = vec3f(0.02, 0.10, 0.12); - let rgb = mix(mix(deep, cyan, 0.42 + heat * 0.58), gold, brass * 0.32); + let albedoLift = mix(deep, albedo.rgb, clamp(albedo.a * (0.72 + heat * 0.24), 0.0, 1.0)); + let fieldTint = mix(cyan, gold, brass * 0.26); + let rgb = mix(albedoLift, fieldTint, 0.18 + heat * 0.16); particle.color = vec4f( rgb, uniforms.alpha * (0.0022 + heat * 0.008 + packed.a * 0.005 + nodeHeat * 0.0025) * fade * (0.72 + levelDetail * 0.28) @@ -627,12 +635,23 @@ async function startGpuParticleField(canvas: HTMLCanvasElement, sample: FieldSam format: "rgba8unorm", usage: 1 | 2 | 4, }); + const albedoTexture = device.createTexture({ + size: [sample.width, sample.height, 1], + format: "rgba8unorm", + usage: 1 | 2 | 4, + }); device.queue.writeTexture( { texture: fieldTexture }, sample.fieldRgba, { bytesPerRow: sample.width * 4, rowsPerImage: sample.height }, { width: sample.width, height: sample.height, depthOrArrayLayers: 1 }, ); + device.queue.writeTexture( + { texture: albedoTexture }, + sample.rgba, + { bytesPerRow: sample.width * 4, rowsPerImage: sample.height }, + { width: sample.width, height: sample.height, depthOrArrayLayers: 1 }, + ); const particleBuffer = device.createBuffer({ size: PARTICLE_COUNT * PARTICLE_STRIDE_FLOATS * Float32Array.BYTES_PER_ELEMENT, @@ -686,6 +705,7 @@ async function startGpuParticleField(canvas: HTMLCanvasElement, sample: FieldSam { binding: 2, resource: sampler }, { binding: 3, resource: fieldTexture.createView() }, { binding: 4, resource: { buffer: nodeEnvelopeBuffer } }, + { binding: 5, resource: albedoTexture.createView() }, ], }); const renderBindGroup = device.createBindGroup({ @@ -786,6 +806,7 @@ async function startGpuParticleField(canvas: HTMLCanvasElement, sample: FieldSam uniformBuffer.destroy(); nodeEnvelopeBuffer.destroy(); fieldTexture.destroy(); + albedoTexture.destroy(); }; }