auto-git:
[change] src/geometry/terrain-brush.ts
This commit is contained in:
@@ -30,6 +30,8 @@ export interface TerrainBrushDirtySampleBounds {
|
|||||||
export interface TerrainBrushStampMutationResult {
|
export interface TerrainBrushStampMutationResult {
|
||||||
changed: boolean;
|
changed: boolean;
|
||||||
dirtyBounds: TerrainBrushDirtySampleBounds | null;
|
dirtyBounds: TerrainBrushDirtySampleBounds | null;
|
||||||
|
heightSampleIndices: number[];
|
||||||
|
paintWeightIndices: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TerrainSmoothHeightSource {
|
interface TerrainSmoothHeightSource {
|
||||||
@@ -243,11 +245,27 @@ function setTerrainSamplePaintWeights(
|
|||||||
sampleX: number,
|
sampleX: number,
|
||||||
sampleZ: number,
|
sampleZ: number,
|
||||||
weights: readonly [number, number, number, number]
|
weights: readonly [number, number, number, number]
|
||||||
) {
|
): number[] {
|
||||||
const offset = getTerrainPaintWeightSampleOffset(terrain, sampleX, sampleZ);
|
const offset = getTerrainPaintWeightSampleOffset(terrain, sampleX, sampleZ);
|
||||||
paintWeights[offset] = weights[1];
|
const changedIndices: number[] = [];
|
||||||
paintWeights[offset + 1] = weights[2];
|
|
||||||
paintWeights[offset + 2] = weights[3];
|
for (
|
||||||
|
let layerOffset = 0;
|
||||||
|
layerOffset < TERRAIN_LAYER_COUNT - 1;
|
||||||
|
layerOffset += 1
|
||||||
|
) {
|
||||||
|
const paintWeightIndex = offset + layerOffset;
|
||||||
|
const nextWeight = weights[layerOffset + 1] ?? 0;
|
||||||
|
|
||||||
|
if ((paintWeights[paintWeightIndex] ?? 0) === nextWeight) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
paintWeights[paintWeightIndex] = nextWeight;
|
||||||
|
changedIndices.push(paintWeightIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changedIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyTerrainBrushStamp(options: {
|
export function applyTerrainBrushStamp(options: {
|
||||||
@@ -304,7 +322,9 @@ export function applyTerrainBrushStampInPlace(options: {
|
|||||||
if (minSampleX > maxSampleX || minSampleZ > maxSampleZ) {
|
if (minSampleX > maxSampleX || minSampleZ > maxSampleZ) {
|
||||||
return {
|
return {
|
||||||
changed: false,
|
changed: false,
|
||||||
dirtyBounds: null
|
dirtyBounds: null,
|
||||||
|
heightSampleIndices: [],
|
||||||
|
paintWeightIndices: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,6 +340,8 @@ export function applyTerrainBrushStampInPlace(options: {
|
|||||||
: null;
|
: null;
|
||||||
const smoothingStrength = clamp01(strength);
|
const smoothingStrength = clamp01(strength);
|
||||||
let dirtyBounds: TerrainBrushDirtySampleBounds | null = null;
|
let dirtyBounds: TerrainBrushDirtySampleBounds | null = null;
|
||||||
|
const heightSampleIndices: number[] = [];
|
||||||
|
const paintWeightIndices: number[] = [];
|
||||||
|
|
||||||
const markDirty = (sampleX: number, sampleZ: number) => {
|
const markDirty = (sampleX: number, sampleZ: number) => {
|
||||||
if (dirtyBounds === null) {
|
if (dirtyBounds === null) {
|
||||||
@@ -411,21 +433,26 @@ export function applyTerrainBrushStampInPlace(options: {
|
|||||||
nextWeights[2] !== currentWeights[2] ||
|
nextWeights[2] !== currentWeights[2] ||
|
||||||
nextWeights[3] !== currentWeights[3]
|
nextWeights[3] !== currentWeights[3]
|
||||||
) {
|
) {
|
||||||
setTerrainSamplePaintWeights(
|
const changedPaintWeightIndices = setTerrainSamplePaintWeights(
|
||||||
terrain.paintWeights,
|
terrain.paintWeights,
|
||||||
terrain,
|
terrain,
|
||||||
sampleX,
|
sampleX,
|
||||||
sampleZ,
|
sampleZ,
|
||||||
nextWeights
|
nextWeights
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (changedPaintWeightIndices.length > 0) {
|
||||||
|
paintWeightIndices.push(...changedPaintWeightIndices);
|
||||||
markDirty(sampleX, sampleZ);
|
markDirty(sampleX, sampleZ);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextHeight !== currentHeight) {
|
if (nextHeight !== currentHeight) {
|
||||||
terrain.heights[sampleIndex] = nextHeight;
|
terrain.heights[sampleIndex] = nextHeight;
|
||||||
|
heightSampleIndices.push(sampleIndex);
|
||||||
markDirty(sampleX, sampleZ);
|
markDirty(sampleX, sampleZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,16 +460,19 @@ export function applyTerrainBrushStampInPlace(options: {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
changed: dirtyBounds !== null,
|
changed: dirtyBounds !== null,
|
||||||
dirtyBounds
|
dirtyBounds,
|
||||||
|
heightSampleIndices,
|
||||||
|
paintWeightIndices
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTerrainBrushPatchFromTerrains(options: {
|
export function createTerrainBrushPatchFromTerrains(options: {
|
||||||
before: Terrain;
|
before: Terrain;
|
||||||
after: Terrain;
|
after: Terrain;
|
||||||
dirtyBounds: TerrainBrushDirtySampleBounds;
|
heightSampleIndices: Iterable<number>;
|
||||||
|
paintWeightIndices: Iterable<number>;
|
||||||
}): TerrainBrushPatch {
|
}): TerrainBrushPatch {
|
||||||
const { before, after, dirtyBounds } = options;
|
const { before, after } = options;
|
||||||
|
|
||||||
if (before.id !== after.id) {
|
if (before.id !== after.id) {
|
||||||
throw new Error("Terrain brush patches require matching terrain ids.");
|
throw new Error("Terrain brush patches require matching terrain ids.");
|
||||||
@@ -461,34 +491,36 @@ export function createTerrainBrushPatchFromTerrains(options: {
|
|||||||
|
|
||||||
const heightSamples: TerrainBrushPatch["heightSamples"] = [];
|
const heightSamples: TerrainBrushPatch["heightSamples"] = [];
|
||||||
const paintWeights: TerrainBrushPatch["paintWeights"] = [];
|
const paintWeights: TerrainBrushPatch["paintWeights"] = [];
|
||||||
const minSampleX = clamp(
|
const normalizeIndices = (
|
||||||
Math.floor(dirtyBounds.minSampleX),
|
indices: Iterable<number>,
|
||||||
0,
|
length: number,
|
||||||
before.sampleCountX - 1
|
label: string
|
||||||
);
|
): number[] => {
|
||||||
const maxSampleX = clamp(
|
const uniqueIndices = new Set<number>();
|
||||||
Math.ceil(dirtyBounds.maxSampleX),
|
|
||||||
0,
|
|
||||||
before.sampleCountX - 1
|
|
||||||
);
|
|
||||||
const minSampleZ = clamp(
|
|
||||||
Math.floor(dirtyBounds.minSampleZ),
|
|
||||||
0,
|
|
||||||
before.sampleCountZ - 1
|
|
||||||
);
|
|
||||||
const maxSampleZ = clamp(
|
|
||||||
Math.ceil(dirtyBounds.maxSampleZ),
|
|
||||||
0,
|
|
||||||
before.sampleCountZ - 1
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let sampleZ = minSampleZ; sampleZ <= maxSampleZ; sampleZ += 1) {
|
for (const index of indices) {
|
||||||
for (let sampleX = minSampleX; sampleX <= maxSampleX; sampleX += 1) {
|
if (!Number.isInteger(index) || index < 0 || index >= length) {
|
||||||
const sampleIndex = getTerrainSampleIndex(before, sampleX, sampleZ);
|
throw new Error(`${label} patch index ${index} is out of range.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueIndices.add(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...uniqueIndices].sort((left, right) => left - right);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const sampleIndex of normalizeIndices(
|
||||||
|
options.heightSampleIndices,
|
||||||
|
before.heights.length,
|
||||||
|
"Terrain height"
|
||||||
|
)) {
|
||||||
const beforeHeight = before.heights[sampleIndex] ?? 0;
|
const beforeHeight = before.heights[sampleIndex] ?? 0;
|
||||||
const afterHeight = after.heights[sampleIndex] ?? 0;
|
const afterHeight = after.heights[sampleIndex] ?? 0;
|
||||||
|
|
||||||
if (beforeHeight !== afterHeight) {
|
if (beforeHeight === afterHeight) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
heightSamples.push({
|
heightSamples.push({
|
||||||
index: sampleIndex,
|
index: sampleIndex,
|
||||||
before: beforeHeight,
|
before: beforeHeight,
|
||||||
@@ -496,18 +528,11 @@ export function createTerrainBrushPatchFromTerrains(options: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const paintOffset = getTerrainPaintWeightSampleOffset(
|
for (const paintWeightIndex of normalizeIndices(
|
||||||
before,
|
options.paintWeightIndices,
|
||||||
sampleX,
|
before.paintWeights.length,
|
||||||
sampleZ
|
"Terrain paint weight"
|
||||||
);
|
)) {
|
||||||
|
|
||||||
for (
|
|
||||||
let layerOffset = 0;
|
|
||||||
layerOffset < TERRAIN_LAYER_COUNT - 1;
|
|
||||||
layerOffset += 1
|
|
||||||
) {
|
|
||||||
const paintWeightIndex = paintOffset + layerOffset;
|
|
||||||
const beforeWeight = before.paintWeights[paintWeightIndex] ?? 0;
|
const beforeWeight = before.paintWeights[paintWeightIndex] ?? 0;
|
||||||
const afterWeight = after.paintWeights[paintWeightIndex] ?? 0;
|
const afterWeight = after.paintWeights[paintWeightIndex] ?? 0;
|
||||||
|
|
||||||
@@ -521,8 +546,6 @@ export function createTerrainBrushPatchFromTerrains(options: {
|
|||||||
after: afterWeight
|
after: afterWeight
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
terrainId: before.id,
|
terrainId: before.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user