Remove alpha from deposit layer
Some checks failed
Check & deploy / build (push) Failing after 1m18s
Some checks failed
Check & deploy / build (push) Failing after 1m18s
This commit is contained in:
parent
22587529f4
commit
e00b394bc3
10 changed files with 45 additions and 73 deletions
|
|
@ -35,10 +35,8 @@ export const defaultSettings: GardenDefaultSettings = {
|
|||
randomTimeScale: 0.34816,
|
||||
|
||||
diffusionRateTrails: 0.22,
|
||||
decayRateBrush: 18,
|
||||
diffusionDecayRateDivisor: 1000,
|
||||
diffusionNeighborDivisor: 8,
|
||||
brushDecayAlphaOffset: 1.001,
|
||||
brushEffectDuration: 8,
|
||||
|
||||
brushCurveResolution: 12,
|
||||
|
|
@ -48,7 +46,6 @@ export const defaultSettings: GardenDefaultSettings = {
|
|||
brushCurveSegmentBrushRadiusRatio: 0.65,
|
||||
brushSmoothingMinSampleDistance: 0.5,
|
||||
|
||||
brushAlpha: 1,
|
||||
brushDiscardThreshold: 0.02,
|
||||
brushGrainNoiseScale: 22,
|
||||
brushGrainNoiseOffsetX: 0.31,
|
||||
|
|
@ -56,12 +53,12 @@ export const defaultSettings: GardenDefaultSettings = {
|
|||
brushGrainMinStrength: 0.45,
|
||||
brushGrainMaxStrength: 1,
|
||||
|
||||
eraserClearAlpha: 0,
|
||||
eraserClearBlue: 0,
|
||||
eraserClearGreen: 0,
|
||||
eraserClearRed: 0,
|
||||
eraserLineDistanceEpsilon: 0.0001,
|
||||
eraserMaskAlphaThreshold: 0.5,
|
||||
eraserMaskErasedValue: 0,
|
||||
|
||||
adaptiveCapInitial: 1_000_000,
|
||||
adaptiveCapMin: 50_000,
|
||||
|
|
|
|||
|
|
@ -28,12 +28,12 @@ export type GardenRuntimeSettings = {
|
|||
brushCurveSegmentBrushRadiusRatio: number;
|
||||
brushEffectDuration: number;
|
||||
brushSmoothingMinSampleDistance: number;
|
||||
eraserClearAlpha: number;
|
||||
eraserClearBlue: number;
|
||||
eraserClearGreen: number;
|
||||
eraserClearRed: number;
|
||||
eraserLineDistanceEpsilon: number;
|
||||
eraserMaskAlphaThreshold: number;
|
||||
eraserMaskErasedValue: number;
|
||||
eraserSize: number;
|
||||
internalRenderAreaMegapixels: number;
|
||||
mirrorSegmentCount: number;
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ export class GameLoopResources {
|
|||
eraserClearRed: runtimeSettings.eraserClearRed,
|
||||
eraserClearGreen: runtimeSettings.eraserClearGreen,
|
||||
eraserClearBlue: runtimeSettings.eraserClearBlue,
|
||||
eraserClearAlpha: runtimeSettings.eraserClearAlpha,
|
||||
eraserMaskErasedValue: runtimeSettings.eraserMaskErasedValue,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -215,7 +215,8 @@ fn agent_finalize(
|
|||
// Writes only this agent's last-writer-wins deposit into a per-frame-cleared
|
||||
// depositMap. Storage textures do not blend concurrent compute writes, so
|
||||
// overlapping agents intentionally collapse to whichever write wins. The
|
||||
// diffusion pass then sums trailMap + depositMap at tile-load time.
|
||||
// diffusion pass then sums trailMap + depositMap at tile-load time. The
|
||||
// rgba8unorm alpha lane is unused, so deposits leave it at zero.
|
||||
textureStore(
|
||||
trailMapOut,
|
||||
vec2<i32>(nextPosition),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import shader from './brush.wgsl?raw';
|
|||
|
||||
export interface BrushSettings {
|
||||
brushSize: number;
|
||||
brushAlpha: number;
|
||||
brushDiscardThreshold: number;
|
||||
brushGrainNoiseScale: number;
|
||||
brushGrainNoiseOffsetX: number;
|
||||
|
|
@ -45,7 +44,6 @@ const setBrushUniformValues = (
|
|||
target: Float32Array,
|
||||
{
|
||||
brushSize,
|
||||
brushAlpha,
|
||||
brushDiscardThreshold,
|
||||
brushGrainNoiseScale,
|
||||
brushGrainNoiseOffsetX,
|
||||
|
|
@ -65,17 +63,16 @@ const setBrushUniformValues = (
|
|||
|
||||
target[0] = brushRadius;
|
||||
target[1] = brushRadius * brushRadius;
|
||||
// target[2], target[3] are WGSL alignment padding for brushValue:vec4 — never read by the shader.
|
||||
// target[2], target[3] are WGSL alignment padding for brushColor:vec3 — never read by the shader.
|
||||
target[4] = selectedColorIndex === 0 ? 1 : 0;
|
||||
target[5] = selectedColorIndex === 1 ? 1 : 0;
|
||||
target[6] = selectedColorIndex === 2 ? 1 : 0;
|
||||
target[7] = brushAlpha;
|
||||
target[8] = 1 / Math.max(Number.EPSILON, brushGrainNoiseScale * safePixelRatio);
|
||||
target[9] = brushGrainNoiseOffsetX;
|
||||
target[10] = brushGrainNoiseOffsetY;
|
||||
target[11] = brushDiscardThreshold;
|
||||
target[12] = brushGrainMinStrength;
|
||||
target[13] = brushGrainMaxStrength;
|
||||
target[7] = 1 / Math.max(Number.EPSILON, brushGrainNoiseScale * safePixelRatio);
|
||||
target[8] = brushGrainNoiseOffsetX;
|
||||
target[9] = brushGrainNoiseOffsetY;
|
||||
target[10] = brushDiscardThreshold;
|
||||
target[11] = brushGrainMinStrength;
|
||||
target[12] = brushGrainMaxStrength;
|
||||
};
|
||||
|
||||
export class BrushPipeline {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ const SEGMENT_LENGTH_EPSILON: f32 = 0.0001;
|
|||
struct Settings {
|
||||
brushRadius: f32,
|
||||
brushRadiusSquared: f32,
|
||||
// padding to 16-byte alignment for the following vec4
|
||||
// padding to 16-byte alignment for the following vec3
|
||||
_pad0: f32,
|
||||
_pad1: f32,
|
||||
brushValue: vec4<f32>,
|
||||
brushColor: vec3<f32>,
|
||||
brushGrainNoiseScale: f32,
|
||||
brushGrainNoiseOffsetX: f32,
|
||||
brushGrainNoiseOffsetY: f32,
|
||||
|
|
@ -115,5 +115,7 @@ fn brushStrength(
|
|||
}
|
||||
|
||||
fn brushOutput(strength: f32) -> vec4<f32> {
|
||||
return vec4(settings.brushValue.rgb * strength, settings.brushValue.a * strength);
|
||||
// The rgba8unorm source map needs a vec4; its alpha lane is unused, so the
|
||||
// brush leaves it at zero.
|
||||
return vec4(settings.brushColor * strength, 0.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,7 @@ struct Settings {
|
|||
inverseDiffusionRateTrails: f32,
|
||||
decayRateTrails: f32,
|
||||
diffusionNeighborScale: f32,
|
||||
brushDecayAlphaMultiplier: f32,
|
||||
brushDecayAlphaSubtract: f32,
|
||||
padding0: f32,
|
||||
padding1: f32,
|
||||
padding2: f32,
|
||||
};
|
||||
|
||||
const WORKGROUP_SIZE_X = __WORKGROUP_SIZE__u;
|
||||
|
|
@ -32,7 +28,9 @@ const HASH_TO_UNIT_FLOAT: f32 = 2.3283064365386963e-10;
|
|||
// in the same frame.
|
||||
@group(0) @binding(3) var depositMap: texture_2d<f32>;
|
||||
|
||||
var<workgroup> tile: array<vec4<f32>, TILE_TEXEL_COUNT>;
|
||||
// Only the color channels take part in the simulation; the alpha lane of the
|
||||
// rgba8unorm trail and source maps is unused and always stored as zero.
|
||||
var<workgroup> tile: array<vec3<f32>, TILE_TEXEL_COUNT>;
|
||||
var<workgroup> tileTrailStrength: array<f32, TILE_TEXEL_COUNT>;
|
||||
|
||||
@compute @workgroup_size(__WORKGROUP_SIZE__, __WORKGROUP_SIZE__)
|
||||
|
|
@ -53,10 +51,10 @@ fn main(
|
|||
vec2<i32>(0, 0),
|
||||
textureBound
|
||||
);
|
||||
let texel = textureLoad(trailMap, sourcePixel, 0)
|
||||
+ textureLoad(depositMap, sourcePixel, 0);
|
||||
let texel = textureLoad(trailMap, sourcePixel, 0).rgb
|
||||
+ textureLoad(depositMap, sourcePixel, 0).rgb;
|
||||
tile[tileIndex] = texel;
|
||||
tileTrailStrength[tileIndex] = length(texel.rgb);
|
||||
tileTrailStrength[tileIndex] = length(texel);
|
||||
}
|
||||
|
||||
workgroupBarrier();
|
||||
|
|
@ -106,25 +104,23 @@ fn main(
|
|||
+ propagate_value(nBR, sBR, current, trailWeight);
|
||||
|
||||
let updated = current + propagated * settings.diffusionNeighborScale;
|
||||
let decayed = clamp(vec4(
|
||||
updated.rgb * settings.decayRateTrails - vec3(TRAIL_RGB_DECAY_SUBTRACT),
|
||||
updated.a * settings.brushDecayAlphaMultiplier - settings.brushDecayAlphaSubtract
|
||||
), vec4(0), vec4(1));
|
||||
let decayed = clamp(
|
||||
updated * settings.decayRateTrails - vec3(TRAIL_RGB_DECAY_SUBTRACT),
|
||||
vec3(0),
|
||||
vec3(1)
|
||||
);
|
||||
|
||||
textureStore(trailMapOut, pixel, decayed);
|
||||
textureStore(trailMapOut, pixel, vec4(decayed, 0.0));
|
||||
}
|
||||
|
||||
fn propagate_value(
|
||||
neighbour: vec4<f32>,
|
||||
neighbour: vec3<f32>,
|
||||
neighbourStrength: f32,
|
||||
current: vec4<f32>,
|
||||
current: vec3<f32>,
|
||||
trailWeight: f32
|
||||
) -> vec4<f32> {
|
||||
let difference = clamp(neighbour - current, vec4(0), vec4(1));
|
||||
return vec4(
|
||||
vec3(neighbourStrength * trailWeight),
|
||||
neighbour.a * trailWeight
|
||||
) * difference;
|
||||
) -> vec3<f32> {
|
||||
let difference = clamp(neighbour - current, vec3(0), vec3(1));
|
||||
return vec3(neighbourStrength * trailWeight) * difference;
|
||||
}
|
||||
|
||||
fn random_from_pixel(pixel: vec2<i32>) -> f32 {
|
||||
|
|
|
|||
|
|
@ -12,22 +12,10 @@ import shader from './diffuse.wgsl?raw';
|
|||
export interface DiffusionSettings {
|
||||
diffusionRateTrails: number;
|
||||
decayRateTrails: number;
|
||||
decayRateBrush: number;
|
||||
diffusionDecayRateDivisor: number;
|
||||
diffusionNeighborDivisor: number;
|
||||
brushDecayAlphaOffset: number;
|
||||
}
|
||||
|
||||
type DiffusionUniformSettings = Pick<
|
||||
DiffusionSettings,
|
||||
| 'diffusionRateTrails'
|
||||
| 'decayRateTrails'
|
||||
| 'decayRateBrush'
|
||||
| 'diffusionDecayRateDivisor'
|
||||
| 'diffusionNeighborDivisor'
|
||||
| 'brushDecayAlphaOffset'
|
||||
>;
|
||||
|
||||
const MIN_DIFFUSION_RATE = 0.000001;
|
||||
|
||||
const getSafeInverseDiffusionRate = (diffusionRate: number): number =>
|
||||
|
|
@ -41,30 +29,23 @@ const setDiffusionUniformValues = (
|
|||
{
|
||||
diffusionRateTrails,
|
||||
decayRateTrails,
|
||||
decayRateBrush,
|
||||
diffusionDecayRateDivisor,
|
||||
diffusionNeighborDivisor,
|
||||
brushDecayAlphaOffset,
|
||||
}: DiffusionUniformSettings
|
||||
}: DiffusionSettings
|
||||
): void => {
|
||||
const decayDivisor = Math.max(Number.EPSILON, diffusionDecayRateDivisor);
|
||||
const brushDecayRate = decayRateBrush / decayDivisor;
|
||||
const neighborDivisor = Number.isFinite(diffusionNeighborDivisor)
|
||||
? Math.max(1, diffusionNeighborDivisor)
|
||||
: 1;
|
||||
target[0] = getSafeInverseDiffusionRate(diffusionRateTrails);
|
||||
target[1] = decayRateTrails / decayDivisor;
|
||||
target[2] = 1 / neighborDivisor;
|
||||
target[3] = 1 + brushDecayRate;
|
||||
target[4] = brushDecayAlphaOffset * brushDecayRate;
|
||||
target[5] = 0;
|
||||
target[6] = 0;
|
||||
target[7] = 0;
|
||||
// target[3] is WGSL 16-byte alignment padding — never read by the shader.
|
||||
};
|
||||
|
||||
export class DiffusionPipeline {
|
||||
private static readonly WORKGROUP_SIZE = 16;
|
||||
private static readonly UNIFORM_COUNT = 8;
|
||||
private static readonly UNIFORM_COUNT = 4;
|
||||
|
||||
private readonly bindGroupLayout: GPUBindGroupLayout;
|
||||
private readonly pipeline: GPUComputePipeline;
|
||||
|
|
@ -136,18 +117,14 @@ export class DiffusionPipeline {
|
|||
public setParameters({
|
||||
diffusionRateTrails,
|
||||
decayRateTrails,
|
||||
decayRateBrush,
|
||||
diffusionDecayRateDivisor,
|
||||
diffusionNeighborDivisor,
|
||||
brushDecayAlphaOffset,
|
||||
}: DiffusionSettings) {
|
||||
setDiffusionUniformValues(this.uniformValues, {
|
||||
diffusionRateTrails,
|
||||
decayRateTrails,
|
||||
decayRateBrush,
|
||||
diffusionDecayRateDivisor,
|
||||
diffusionNeighborDivisor,
|
||||
brushDecayAlphaOffset,
|
||||
});
|
||||
writeBufferIfChanged(
|
||||
this.device,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ interface EraserTextureParameters {
|
|||
eraserClearRed: number;
|
||||
eraserClearGreen: number;
|
||||
eraserClearBlue: number;
|
||||
eraserClearAlpha: number;
|
||||
eraserMaskErasedValue: number;
|
||||
}
|
||||
|
||||
const UNIFORM_COUNT = 8;
|
||||
|
|
@ -110,7 +110,7 @@ export class EraserTexturePipeline {
|
|||
eraserClearRed,
|
||||
eraserClearGreen,
|
||||
eraserClearBlue,
|
||||
eraserClearAlpha,
|
||||
eraserMaskErasedValue,
|
||||
}: EraserTextureParameters): void {
|
||||
const eraserRadius = eraserSize / 2;
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ export class EraserTexturePipeline {
|
|||
this.uniformValues[2] = eraserClearRed;
|
||||
this.uniformValues[3] = eraserClearGreen;
|
||||
this.uniformValues[4] = eraserClearBlue;
|
||||
this.uniformValues[5] = eraserClearAlpha;
|
||||
this.uniformValues[5] = eraserMaskErasedValue;
|
||||
this.uniformValues[6] = eraserRadius;
|
||||
writeBufferIfChanged(
|
||||
this.device,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ struct Settings {
|
|||
clearRed: f32,
|
||||
clearGreen: f32,
|
||||
clearBlue: f32,
|
||||
clearAlpha: f32,
|
||||
erasedMaskValue: f32,
|
||||
eraserRadius: f32,
|
||||
};
|
||||
|
||||
|
|
@ -66,14 +66,16 @@ fn fragmentCombined(
|
|||
}
|
||||
|
||||
fn getEraserMaskValue() -> vec4<f32> {
|
||||
return vec4<f32>(settings.clearAlpha, 0.0, 0.0, 1.0);
|
||||
return vec4<f32>(settings.erasedMaskValue, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
fn getEraserClearValue() -> vec4<f32> {
|
||||
// The rgba8unorm trail and source maps need a vec4; their alpha lane is
|
||||
// unused, so erased texels keep it at zero.
|
||||
return vec4<f32>(
|
||||
settings.clearRed,
|
||||
settings.clearGreen,
|
||||
settings.clearBlue,
|
||||
settings.clearAlpha
|
||||
0.0
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue