Refactor terrain brush logic to dynamically support variable layer counts

This commit is contained in:
2026-05-13 00:44:16 +02:00
parent eff24127da
commit bbdef545fb

View File

@@ -15,7 +15,7 @@ import {
getTerrainPaintWeightSampleOffset, getTerrainPaintWeightSampleOffset,
getTerrainSampleIndex, getTerrainSampleIndex,
getTerrainSampleLayerWeights, getTerrainSampleLayerWeights,
TERRAIN_LAYER_COUNT, getTerrainStoredPaintWeightCount,
type Terrain type Terrain
} from "../document/terrains"; } from "../document/terrains";
@@ -232,22 +232,20 @@ function getTerrainSmoothTargetHeight(
} }
function createTerrainPaintTargetWeights( function createTerrainPaintTargetWeights(
terrain: Terrain,
layerIndex: number layerIndex: number
): [number, number, number, number] { ): number[] {
if ( if (
!Number.isInteger(layerIndex) || !Number.isInteger(layerIndex) ||
layerIndex < 0 || layerIndex < 0 ||
layerIndex >= TERRAIN_LAYER_COUNT layerIndex >= terrain.layers.length
) { ) {
throw new Error(`Terrain paint layer index ${layerIndex} is out of range.`); throw new Error(`Terrain paint layer index ${layerIndex} is out of range.`);
} }
return [ return terrain.layers.map((_, currentLayerIndex) =>
layerIndex === 0 ? 1 : 0, currentLayerIndex === layerIndex ? 1 : 0
layerIndex === 1 ? 1 : 0, );
layerIndex === 2 ? 1 : 0,
layerIndex === 3 ? 1 : 0
];
} }
function setTerrainSamplePaintWeights( function setTerrainSamplePaintWeights(
@@ -255,16 +253,15 @@ function setTerrainSamplePaintWeights(
terrain: Terrain, terrain: Terrain,
sampleX: number, sampleX: number,
sampleZ: number, sampleZ: number,
weights: readonly [number, number, number, number] weights: readonly number[]
): number[] { ): number[] {
const offset = getTerrainPaintWeightSampleOffset(terrain, sampleX, sampleZ); const offset = getTerrainPaintWeightSampleOffset(terrain, sampleX, sampleZ);
const storedWeightCount = getTerrainStoredPaintWeightCount(
terrain.layers.length
);
const changedIndices: number[] = []; const changedIndices: number[] = [];
for ( for (let layerOffset = 0; layerOffset < storedWeightCount; layerOffset += 1) {
let layerOffset = 0;
layerOffset < TERRAIN_LAYER_COUNT - 1;
layerOffset += 1
) {
const paintWeightIndex = offset + layerOffset; const paintWeightIndex = offset + layerOffset;
const nextWeight = weights[layerOffset + 1] ?? 0; const nextWeight = weights[layerOffset + 1] ?? 0;
@@ -437,20 +434,31 @@ export function applyTerrainBrushStampInPlace(options: {
sampleX, sampleX,
sampleZ sampleZ
); );
const targetWeights = createTerrainPaintTargetWeights(layerIndex); const targetWeights = createTerrainPaintTargetWeights(
terrain,
layerIndex
);
const blend = clamp01(smoothingStrength * weight); const blend = clamp01(smoothingStrength * weight);
const nextWeights: [number, number, number, number] = [ const nextWeights = currentWeights.map((currentWeight, weightIndex) =>
lerp(currentWeights[0], targetWeights[0], blend), lerp(currentWeight, targetWeights[weightIndex] ?? 0, blend)
lerp(currentWeights[1], targetWeights[1], blend), );
lerp(currentWeights[2], targetWeights[2], blend), const storedWeightCount = getTerrainStoredPaintWeightCount(
lerp(currentWeights[3], targetWeights[3], blend) terrain.layers.length
]; );
let storedWeightsChanged = false;
if ( for (
nextWeights[1] !== currentWeights[1] || let layerOffset = 0;
nextWeights[2] !== currentWeights[2] || layerOffset < storedWeightCount;
nextWeights[3] !== currentWeights[3] layerOffset += 1
) { ) {
if (nextWeights[layerOffset + 1] !== currentWeights[layerOffset + 1]) {
storedWeightsChanged = true;
break;
}
}
if (storedWeightsChanged) {
const changedPaintWeightIndices = setTerrainSamplePaintWeights( const changedPaintWeightIndices = setTerrainSamplePaintWeights(
terrain.paintWeights, terrain.paintWeights,
terrain, terrain,