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