mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 06:20:02 +00:00
Fixing a handfull of issues!
This commit is contained in:
1 parent
1132242c58
commit
c3359e0a16
30 files changed
+1324
-282
No files matched your search
@@ -316,6 +316,11 @@ public class IrisCaveCarver3D {
|
||||
for (int lz = 0; lz < 16; lz++) {
|
||||
int z = z0 + lz;
|
||||
int index = PowerOfTwoCoordinates.packLocal16(lx, lz);
|
||||
clampedWeights[index] = clampColumnWeight(columnWeights[index]);
|
||||
if (clampedWeights[index] <= resolvedMinWeight) {
|
||||
columnMaxY[index] = minY - 1;
|
||||
continue;
|
||||
}
|
||||
int columnSurfaceY;
|
||||
if (precomputedSurfaceHeights != null && precomputedSurfaceHeights.length > index) {
|
||||
columnSurfaceY = precomputedSurfaceHeights[index];
|
||||
@@ -340,7 +345,6 @@ public class IrisCaveCarver3D {
|
||||
columnThreshold[index] = (thresholdDensity == null
|
||||
? constantThreshold
|
||||
: thresholdDensity.fitDouble(thresholdMin, thresholdMax, x, z)) - thresholdBias;
|
||||
clampedWeights[index] = clampColumnWeight(columnWeights[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
private static final int FIELD_SIZE = CHUNK_SIZE + (BLEND_RADIUS * 2);
|
||||
private static final double MIN_WEIGHT = 0.08D;
|
||||
private static final double THRESHOLD_PENALTY = 0.24D;
|
||||
private static final int MAX_BLENDED_PROFILE_PASSES = 2;
|
||||
private static final int MAX_POOLED_WEIGHT_BUFFERS = 64;
|
||||
/** Lattice columns kept for neighbouring chunks: about 3 KB each on land, roughly 50 MB when full. */
|
||||
private static final int DENSITY_GRID_COLUMNS = 16_384;
|
||||
@@ -348,9 +347,9 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
columnWeightedProfiles.add(new WeightedProfile(profile, weights, averageWeight, null, columnWeightedProfiles.size()));
|
||||
}
|
||||
|
||||
List<WeightedProfile> blendedProfiles = limitAndMergeBlendedProfiles(columnWeightedProfiles, MAX_BLENDED_PROFILE_PASSES, CHUNK_AREA);
|
||||
columnWeightedProfiles.sort(MantleCarvingComponent::compareByCarveOrder);
|
||||
List<WeightedProfile> resolvedProfiles = resolveDimensionCarvingProfiles(chunkX, chunkZ, resolverState, blendScratch);
|
||||
resolvedProfiles.addAll(blendedProfiles);
|
||||
resolvedProfiles.addAll(columnWeightedProfiles);
|
||||
return resolvedProfiles;
|
||||
}
|
||||
|
||||
@@ -619,67 +618,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
return surfaceHeights;
|
||||
}
|
||||
|
||||
private static List<WeightedProfile> limitAndMergeBlendedProfiles(List<WeightedProfile> blendedProfiles, int maxProfiles) {
|
||||
return limitAndMergeBlendedProfiles(blendedProfiles, maxProfiles, CHUNK_AREA);
|
||||
}
|
||||
|
||||
private static List<WeightedProfile> limitAndMergeBlendedProfiles(List<WeightedProfile> blendedProfiles, int maxProfiles, int areaSize) {
|
||||
if (blendedProfiles == null || blendedProfiles.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
int clampedLimit = Math.max(1, maxProfiles);
|
||||
List<WeightedProfile> rankedProfiles = new ArrayList<>(blendedProfiles);
|
||||
rankedProfiles.sort(MantleCarvingComponent::compareBySelectionRank);
|
||||
List<WeightedProfile> keptProfiles = new ArrayList<>();
|
||||
int keptCount = Math.min(clampedLimit, rankedProfiles.size());
|
||||
for (int index = 0; index < keptCount; index++) {
|
||||
keptProfiles.add(rankedProfiles.get(index));
|
||||
}
|
||||
|
||||
if (rankedProfiles.size() > keptCount) {
|
||||
for (int columnIndex = 0; columnIndex < areaSize; columnIndex++) {
|
||||
int dominantIndex = 0;
|
||||
double dominantWeight = Double.NEGATIVE_INFINITY;
|
||||
for (int keptIndex = 0; keptIndex < keptProfiles.size(); keptIndex++) {
|
||||
double keptWeight = keptProfiles.get(keptIndex).columnWeights[columnIndex];
|
||||
if (keptWeight > dominantWeight) {
|
||||
dominantWeight = keptWeight;
|
||||
dominantIndex = keptIndex;
|
||||
}
|
||||
}
|
||||
|
||||
double droppedWeight = 0D;
|
||||
for (int droppedIndex = keptCount; droppedIndex < rankedProfiles.size(); droppedIndex++) {
|
||||
droppedWeight += rankedProfiles.get(droppedIndex).columnWeights[columnIndex];
|
||||
}
|
||||
if (droppedWeight <= 0D) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WeightedProfile dominantProfile = keptProfiles.get(dominantIndex);
|
||||
double mergedWeight = dominantProfile.columnWeights[columnIndex] + droppedWeight;
|
||||
dominantProfile.columnWeights[columnIndex] = clampWeight(mergedWeight);
|
||||
}
|
||||
}
|
||||
|
||||
List<WeightedProfile> mergedProfiles = new ArrayList<>();
|
||||
for (WeightedProfile keptProfile : keptProfiles) {
|
||||
double averageWeight = computeAverageWeight(keptProfile.columnWeights, areaSize);
|
||||
mergedProfiles.add(new WeightedProfile(keptProfile.profile, keptProfile.columnWeights, averageWeight, keptProfile.worldYRange, keptProfile.sequence));
|
||||
}
|
||||
mergedProfiles.sort(MantleCarvingComponent::compareByCarveOrder);
|
||||
return mergedProfiles;
|
||||
}
|
||||
|
||||
private static int compareBySelectionRank(WeightedProfile a, WeightedProfile b) {
|
||||
int weightOrder = Double.compare(b.averageWeight, a.averageWeight);
|
||||
if (weightOrder != 0) {
|
||||
return weightOrder;
|
||||
}
|
||||
return Integer.compare(a.sequence, b.sequence);
|
||||
}
|
||||
|
||||
private static int compareByCarveOrder(WeightedProfile a, WeightedProfile b) {
|
||||
int weightOrder = Double.compare(a.averageWeight, b.averageWeight);
|
||||
if (weightOrder != 0) {
|
||||
@@ -689,10 +627,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
}
|
||||
|
||||
private static double computeAverageWeight(double[] weights) {
|
||||
return computeAverageWeight(weights, CHUNK_AREA);
|
||||
}
|
||||
|
||||
private static double computeAverageWeight(double[] weights, int areaSize) {
|
||||
if (weights == null || weights.length == 0) {
|
||||
return 0D;
|
||||
}
|
||||
@@ -700,7 +634,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
for (double weight : weights) {
|
||||
sum += weight;
|
||||
}
|
||||
return sum / Math.max(1, areaSize);
|
||||
return sum / CHUNK_AREA;
|
||||
}
|
||||
|
||||
private static double clampWeight(double value) {
|
||||
@@ -730,10 +664,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
this.worldYRange = worldYRange;
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
private double averageWeight() {
|
||||
return averageWeight;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BlendScratch {
|
||||
|
||||
@@ -930,7 +930,7 @@ public class IrisEngine implements Engine {
|
||||
queryMaximumX,
|
||||
queryMaximumZ);
|
||||
for (NativeStructureVolume volume : resolved) {
|
||||
if (!volume.intersectsRect(minimumX, minimumZ, maximumX, maximumZ)) {
|
||||
if (!volume.intersectsInfluenceRect(minimumX, minimumZ, maximumX, maximumZ)) {
|
||||
continue;
|
||||
}
|
||||
if (matches == null) {
|
||||
|
||||
+2
-2
@@ -115,7 +115,7 @@ public final class NativeStructureVolumeIndex {
|
||||
for (int chunkX = fromChunkX; chunkX <= toChunkX; chunkX++) {
|
||||
for (int chunkZ = fromChunkZ; chunkZ <= toChunkZ; chunkZ++) {
|
||||
for (NativeStructureVolume volume : chunkVolumes(engine, runtimeId, chunkX, chunkZ)) {
|
||||
if (!volume.intersectsRect(minX, minZ, maxX, maxZ)) {
|
||||
if (!volume.intersectsInfluenceRect(minX, minZ, maxX, maxZ)) {
|
||||
continue;
|
||||
}
|
||||
if (matches == null) {
|
||||
@@ -150,7 +150,7 @@ public final class NativeStructureVolumeIndex {
|
||||
for (int originX = chunkX - ORIGIN_REACH_CHUNKS; originX <= chunkX + ORIGIN_REACH_CHUNKS; originX++) {
|
||||
for (int originZ = chunkZ - ORIGIN_REACH_CHUNKS; originZ <= chunkZ + ORIGIN_REACH_CHUNKS; originZ++) {
|
||||
for (NativeStructureVolume volume : scopedOriginVolumes(engine, originX, originZ, pinnedRuntimeId)) {
|
||||
if (!volume.intersectsRect(minX, minZ, maxX, maxZ)) {
|
||||
if (!volume.intersectsInfluenceRect(minX, minZ, maxX, maxZ)) {
|
||||
continue;
|
||||
}
|
||||
if (volumes == null) {
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ public final class NativeStructureVolumeMemo {
|
||||
for (int chunkX = fromChunkX; chunkX <= toChunkX; chunkX++) {
|
||||
for (int chunkZ = fromChunkZ; chunkZ <= toChunkZ; chunkZ++) {
|
||||
for (NativeStructureVolume volume : chunkVolumes(engine, hooks, chunkX, chunkZ)) {
|
||||
if (!volume.intersectsRect(minX, minZ, maxX, maxZ)) {
|
||||
if (!volume.intersectsInfluenceRect(minX, minZ, maxX, maxZ)) {
|
||||
continue;
|
||||
}
|
||||
if (matches == null) {
|
||||
|
||||
@@ -49,6 +49,7 @@ import art.arcane.volmlib.util.math.BlockPosition;
|
||||
import art.arcane.volmlib.util.math.Position2;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.matter.MatterMarker;
|
||||
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
@@ -1135,10 +1136,14 @@ final class IrisObjectPlacementRunner {
|
||||
int envelopeMinY = projection != null ? Integer.MIN_VALUE : worldY + bounds.minY() - warpMargin;
|
||||
int envelopeMaxY = projection != null ? Integer.MAX_VALUE : worldY + bounds.maxY() + warpMargin;
|
||||
boolean envelopeMeetsPiece = false;
|
||||
boolean includesSurfaceCuts = false;
|
||||
for (NativeStructureVolume volume : volumes) {
|
||||
if (volume.intersects(minX, envelopeMinY, minZ, maxX, envelopeMaxY, maxZ)) {
|
||||
envelopeMeetsPiece = true;
|
||||
break;
|
||||
}
|
||||
if (volume.surfaceAdjustment() != null && volume.intersectsInfluenceRect(minX, minZ, maxX, maxZ)) {
|
||||
envelopeMeetsPiece = true;
|
||||
includesSurfaceCuts = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1148,6 +1153,7 @@ final class IrisObjectPlacementRunner {
|
||||
|
||||
self.readLock.lock();
|
||||
try {
|
||||
Long2LongOpenHashMap surfaceCuts = null;
|
||||
VectorMap<NativeBlockState>.Cursor cursor = self.blocks.cursor();
|
||||
while (cursor.next()) {
|
||||
NativeBlockState state = cursor.value();
|
||||
@@ -1187,6 +1193,28 @@ final class IrisObjectPlacementRunner {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!includesSurfaceCuts) {
|
||||
continue;
|
||||
}
|
||||
if (surfaceCuts == null) {
|
||||
surfaceCuts = new Long2LongOpenHashMap();
|
||||
surfaceCuts.defaultReturnValue(Long.MIN_VALUE);
|
||||
}
|
||||
long column = ((long) xx << 32) ^ (zz & 0xffffffffL);
|
||||
long cut = surfaceCuts.get(column);
|
||||
if (cut == Long.MIN_VALUE) {
|
||||
int surfaceY = Engine.hostHeight(engine, xx, zz, true) + engine.getMinHeight();
|
||||
int targetY = NativeStructureVolume.surfaceCutY(volumes, xx, zz, surfaceY);
|
||||
cut = ((long) surfaceY << 32) ^ (targetY & 0xffffffffL);
|
||||
surfaceCuts.put(column, cut);
|
||||
}
|
||||
int surfaceY = (int) (cut >> 32);
|
||||
int targetY = (int) cut;
|
||||
int margin = projection == null ? warpMargin : 0;
|
||||
if (targetY < surfaceY && worldBlockY > (long) targetY - margin
|
||||
&& worldBlockY <= (long) surfaceY + 1 + margin) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
self.readLock.unlock();
|
||||
|
||||
@@ -124,6 +124,7 @@ final class IrisObjectTransforms {
|
||||
interpolation = IrisObjectPlacementScaleInterpolator.NONE;
|
||||
}
|
||||
boolean savedOrigin = origin == ScaleOrigin.SAVED;
|
||||
boolean fractional = scale != Math.rint(scale);
|
||||
List<ScaledVoxel> voxels;
|
||||
IrisObject output;
|
||||
TreeGrounding grounding;
|
||||
@@ -148,26 +149,33 @@ final class IrisObjectTransforms {
|
||||
sourcePosition.getBlockZ() + sourceCenter.getZ());
|
||||
IrisBlockVector minimum = scaledMinimum(position, scale);
|
||||
IrisBlockVector maximum = scaledMaximum(position, scale);
|
||||
IrisVector corner = fractional ? new IrisVector(position.getX() * scale,
|
||||
position.getY() * scale, position.getZ() * scale) : minimum;
|
||||
if (!savedOrigin) {
|
||||
minimum.subtract(targetCenter);
|
||||
maximum.subtract(targetCenter);
|
||||
if (fractional) {
|
||||
corner.subtract(targetCenter);
|
||||
}
|
||||
}
|
||||
TileData tile = self.states.get(sourcePosition);
|
||||
voxels.add(new ScaledVoxel(sourcePosition.clone(), minimum, maximum, entry.getValue(),
|
||||
voxels.add(new ScaledVoxel(sourcePosition.clone(), minimum, maximum, corner, entry.getValue(),
|
||||
tile == null ? null : tile.clone(), grounding != null && grounding.isCanopy(
|
||||
sourcePosition.getBlockX(), sourcePosition.getBlockY(), sourcePosition.getBlockZ())));
|
||||
}
|
||||
} finally {
|
||||
self.readLock.unlock();
|
||||
}
|
||||
if (scale != Math.rint(scale)) {
|
||||
Set<TreeBlockCanvas.Vec> canopy = grounding == null ? null : new HashSet<>();
|
||||
if (fractional) {
|
||||
voxels.sort(Comparator.comparingInt((ScaledVoxel voxel) -> voxel.source().getBlockX())
|
||||
.thenComparingInt(voxel -> voxel.source().getBlockY())
|
||||
.thenComparingInt(voxel -> voxel.source().getBlockZ()));
|
||||
}
|
||||
Set<TreeBlockCanvas.Vec> canopy = grounding == null ? null : new HashSet<>();
|
||||
for (ScaledVoxel voxel : voxels) {
|
||||
writeScaledVoxel(output, voxel, canopy);
|
||||
writeResampledVoxels(output, voxels, scale, canopy);
|
||||
} else {
|
||||
for (ScaledVoxel voxel : voxels) {
|
||||
writeScaledVoxel(output, voxel, canopy);
|
||||
}
|
||||
}
|
||||
|
||||
VectorMap<NativeBlockState> scaledBlocks = output.blocks;
|
||||
@@ -206,7 +214,7 @@ final class IrisObjectTransforms {
|
||||
for (int x = minimum.getBlockX(); x <= maximum.getBlockX(); x++) {
|
||||
for (int z = minimum.getBlockZ(); z <= maximum.getBlockZ(); z++) {
|
||||
NativeBlockState state = output.blocks.get(new IrisBlockVector(x, y, z));
|
||||
if (state != null) {
|
||||
if (state != null && !canopy.contains(new TreeBlockCanvas.Vec(x, y, z))) {
|
||||
roots.add(new TreeGrounding.Root(x, y, z, state));
|
||||
}
|
||||
}
|
||||
@@ -225,23 +233,53 @@ final class IrisObjectTransforms {
|
||||
position.setZ(z);
|
||||
for (int y = minimum.getBlockY(); y <= maximum.getBlockY(); y++) {
|
||||
position.setY(y);
|
||||
output.blocks.put(position, voxel.block());
|
||||
if (canopy != null) {
|
||||
TreeBlockCanvas.Vec cell = new TreeBlockCanvas.Vec(x, y, z);
|
||||
if (voxel.canopy()) {
|
||||
canopy.add(cell);
|
||||
} else {
|
||||
canopy.remove(cell);
|
||||
writeScaledBlock(output, position, voxel, canopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeResampledVoxels(IrisObject output, List<ScaledVoxel> voxels, double scale,
|
||||
Set<TreeBlockCanvas.Vec> canopy) {
|
||||
VectorMap<ScaledVoxel> samples = new VectorMap<>();
|
||||
IrisBlockVector position = new IrisBlockVector();
|
||||
for (ScaledVoxel voxel : voxels) {
|
||||
for (int x = voxel.minimum().getBlockX(); x <= voxel.maximum().getBlockX(); x++) {
|
||||
position.setX(x);
|
||||
for (int z = voxel.minimum().getBlockZ(); z <= voxel.maximum().getBlockZ(); z++) {
|
||||
position.setZ(z);
|
||||
for (int y = voxel.minimum().getBlockY(); y <= voxel.maximum().getBlockY(); y++) {
|
||||
position.setY(y);
|
||||
ScaledVoxel previous = samples.get(position);
|
||||
if (previous == null || voxel.overlap(position, scale) >= previous.overlap(position, scale)) {
|
||||
samples.put(position, voxel);
|
||||
}
|
||||
}
|
||||
if (voxel.tile() == null) {
|
||||
output.states.remove(position);
|
||||
} else {
|
||||
output.states.put(position, voxel.tile().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Map.Entry<IrisBlockVector, ScaledVoxel> entry : samples) {
|
||||
writeScaledBlock(output, entry.getKey(), entry.getValue(), canopy);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeScaledBlock(IrisObject output, IrisBlockVector position, ScaledVoxel voxel,
|
||||
Set<TreeBlockCanvas.Vec> canopy) {
|
||||
output.blocks.put(position, voxel.block());
|
||||
if (canopy != null) {
|
||||
TreeBlockCanvas.Vec cell = new TreeBlockCanvas.Vec(position.getBlockX(),
|
||||
position.getBlockY(), position.getBlockZ());
|
||||
if (voxel.canopy()) {
|
||||
canopy.add(cell);
|
||||
} else {
|
||||
canopy.remove(cell);
|
||||
}
|
||||
}
|
||||
if (voxel.tile() == null) {
|
||||
output.states.remove(position);
|
||||
} else {
|
||||
output.states.put(position, voxel.tile().clone());
|
||||
}
|
||||
}
|
||||
|
||||
private static IrisObject createCenteredScaledObject(IrisObject source, double scale) {
|
||||
@@ -541,7 +579,16 @@ final class IrisObjectTransforms {
|
||||
}
|
||||
|
||||
private record ScaledVoxel(IrisBlockVector source, IrisBlockVector minimum, IrisBlockVector maximum,
|
||||
NativeBlockState block, TileData tile, boolean canopy) {
|
||||
IrisVector corner, NativeBlockState block, TileData tile, boolean canopy) {
|
||||
private double overlap(IrisBlockVector position, double scale) {
|
||||
return overlap(corner.getX(), position.getX(), scale)
|
||||
* overlap(corner.getY(), position.getY(), scale)
|
||||
* overlap(corner.getZ(), position.getZ(), scale);
|
||||
}
|
||||
|
||||
private static double overlap(double source, double target, double scale) {
|
||||
return Math.max(0D, Math.min(source + scale, target + 1D) - Math.max(source, target));
|
||||
}
|
||||
}
|
||||
|
||||
private enum ScaleOrigin {
|
||||
|
||||
Reference in new issue
Block a user