Add ellipsoid placement rotation

This commit is contained in:
DBotThePony 2025-03-30 15:13:56 +07:00
parent 9cfbab6c3c
commit ac1c9a1ad4
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 73 additions and 1 deletions

View File

@ -208,6 +208,7 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
xLength = UniformFloat.of(30f, 70f),
yLength = UniformFloat.of(40f, 90f),
zLength = UniformFloat.of(30f, 70f),
rotateXZ = BooleanProvider.AlwaysTrue,
),
ore.placement()
)

View File

@ -8,9 +8,11 @@ import net.minecraft.core.Direction
import net.minecraft.core.Vec3i
import net.minecraft.world.level.ChunkPos
import net.minecraft.world.phys.Vec3
import org.joml.AxisAngle4d
import org.joml.AxisAngle4f
import org.joml.Matrix3f
import org.joml.Matrix4f
import org.joml.Quaterniond
import org.joml.Quaternionf
import org.joml.Vector3f
import ru.dbotthepony.mc.otm.core.collect.filter
@ -25,10 +27,14 @@ typealias Vector = Vec3
val VECTOR_UP = Vector(0.0, 1.0, 0.0)
val VECTOR_FORWARD = Vector(1.0, 0.0, 0.0)
val VECTOR_POSITIVE_X = VECTOR_FORWARD
val VECTOR_BACKWARD = Vector(-1.0, 0.0, 0.0)
val VECTOR_NEGATIVE_X = VECTOR_BACKWARD
val VECTOR_DOWN = Vector(0.0, -1.0, 0.0)
val VECTOR_RIGHT = Vector(0.0, 0.0, 1.0)
val VECTOR_POSITIVE_Z = VECTOR_RIGHT
val VECTOR_LEFT = Vector(0.0, 0.0, -1.0)
val VECTOR_NEGATIVE_Z = VECTOR_LEFT
private const val DEGREES_TO_RADIANS = 0.017453292f
@ -36,6 +42,10 @@ fun toRadians(angle: Float): Float {
return angle * DEGREES_TO_RADIANS
}
fun toRadians(angle: Double): Double {
return Math.toRadians(angle)
}
fun Vector.asAngle(): Angle {
val norm = normalize()
return Angle(asin(norm.y), atan2(norm.x, norm.z))
@ -173,16 +183,36 @@ fun Vector.rotate(q: Quaternionf): Vector {
return Vector(quaternion.x.toDouble(), quaternion.y.toDouble(), quaternion.z.toDouble())
}
fun Vector.rotate(q: Quaterniond): Vector {
// TODO: 1.19.3
val quaternion = Quaterniond(q)
quaternion.mul(rotateAroundThisDouble())
val quaternion1 = Quaterniond(q)
quaternion1.conjugate()
quaternion.mul(quaternion1)
return Vector(quaternion.x, quaternion.y, quaternion.z)
}
fun Vector.rotateAroundThis(rotation: Float, isDegrees: Boolean = false): Quaternionf {
// TODO: 1.19.3
return Quaternionf(AxisAngle4f(if (isDegrees) toRadians(rotation) else rotation, x.toFloat(), y.toFloat(), z.toFloat()))
}
fun Vector.rotateAroundThis(rotation: Double, isDegrees: Boolean = false): Quaterniond {
// TODO: 1.19.3
return Quaterniond(AxisAngle4d(if (isDegrees) toRadians(rotation) else rotation, x, y, z))
}
fun Vector.rotateAroundThis(): Quaternionf {
// TODO: 1.19.3
return Quaternionf(AxisAngle4f(0f, x.toFloat(), y.toFloat(), z.toFloat()))
}
fun Vector.rotateAroundThisDouble(): Quaterniond {
// TODO: 1.19.3
return Quaterniond(AxisAngle4d(0.0, x, y, z))
}
fun Vector.asMatrix(): Matrix3f {
return Matrix3f().also {
it[0, 0] = x.toFloat()

View File

@ -4,17 +4,29 @@ import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.BlockPos
import net.minecraft.util.RandomSource
import net.minecraft.util.valueproviders.ConstantFloat
import net.minecraft.util.valueproviders.FloatProvider
import net.minecraft.util.valueproviders.IntProvider
import net.minecraft.util.valueproviders.UniformFloat
import net.minecraft.world.level.levelgen.placement.PlacementContext
import net.minecraft.world.level.levelgen.placement.PlacementModifier
import net.minecraft.world.level.levelgen.placement.PlacementModifierType
import ru.dbotthepony.mc.otm.core.collect.Vec3iHashStrategy
import ru.dbotthepony.mc.otm.core.math.VECTOR_POSITIVE_X
import ru.dbotthepony.mc.otm.core.math.VECTOR_POSITIVE_Z
import ru.dbotthepony.mc.otm.core.math.VECTOR_RIGHT
import ru.dbotthepony.mc.otm.core.math.VECTOR_UP
import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.math.rotate
import ru.dbotthepony.mc.otm.core.math.rotateAroundThis
import ru.dbotthepony.mc.otm.core.nextDouble
import ru.dbotthepony.mc.otm.data.world.BooleanProvider
import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
import ru.dbotthepony.mc.otm.worldgen.PlacementPos
import java.util.*
import java.util.stream.Stream
import kotlin.math.PI
/**
* Ellipsoid ("cloud") placement
@ -54,6 +66,10 @@ data class EllipsoidPlacement(
* Ellipsoid size sampler on Y axis
*/
val yLength: FloatProvider,
val rotateXZ: BooleanProvider = BooleanProvider.AlwaysFalse,
val rotateXY: FloatProvider = ConstantFloat.ZERO,
val rotateZY: FloatProvider = ConstantFloat.ZERO,
) : PlacementModifier(), EnhancedPlacement {
init {
require(xLength.minValue >= 1f) { "Bad ellipsoid x minimal size: $xLength" }
@ -79,6 +95,22 @@ data class EllipsoidPlacement(
var iterations = 0
val maxIterations = count * 10
val rotateXZ = rotateXZ.instance().sample(random)
val rotateXY = rotateXY.sample(random)
val rotateZY = rotateZY.sample(random)
val rotationXZ: Double
if (rotateXZ) {
rotationXZ = random.nextDouble(-PI, PI)
} else {
rotationXZ = 0.0
}
val qXZ = VECTOR_UP.rotateAroundThis(rotationXZ)
val qXY = VECTOR_POSITIVE_Z.rotateAroundThis(rotateXY)
val qZY = VECTOR_POSITIVE_X.rotateAroundThis(rotateZY)
while (results.size < count && ++iterations < maxIterations) {
val x = this.x.sample(random) * xLength
val y = this.y.sample(random) * yLength
@ -89,7 +121,13 @@ data class EllipsoidPlacement(
(z * z) / zPow <= 1.0f
if (isValidPoint) {
results.add(BlockPos(x.toInt() + position.x, y.toInt() + position.y, z.toInt() + position.z))
var point = Vector(x.toDouble(), y.toDouble(), z.toDouble())
point = point.rotate(qXZ)
point = point.rotate(qXY)
point = point.rotate(qZY)
results.add(BlockPos(point.x.toInt() + position.x, point.y.toInt() + position.y, point.z.toInt() + position.z))
}
}
@ -130,6 +168,9 @@ data class EllipsoidPlacement(
FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("x_size").forGetter(EllipsoidPlacement::xLength),
FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("z_size").forGetter(EllipsoidPlacement::zLength),
FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("y_size").forGetter(EllipsoidPlacement::yLength),
BooleanProvider.CODEC.optionalFieldOf("rotateXZ", BooleanProvider.AlwaysFalse).forGetter(EllipsoidPlacement::rotateXZ),
FloatProvider.CODEC.optionalFieldOf("rotateXY", ConstantFloat.ZERO).forGetter(EllipsoidPlacement::rotateXY),
FloatProvider.CODEC.optionalFieldOf("rotateZY", ConstantFloat.ZERO).forGetter(EllipsoidPlacement::rotateZY),
).apply(it, ::EllipsoidPlacement)
}
}