mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 18:34:56 -04:00
improve particle, physics performance
This commit is contained in:
parent
8fe880caec
commit
357d40af4c
@ -14,13 +14,16 @@
|
||||
package de.bixilon.minosoft.data.physics
|
||||
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.player.LocalPlayerEntity
|
||||
import de.bixilon.minosoft.data.registries.AABB
|
||||
import de.bixilon.minosoft.data.registries.VoxelShape
|
||||
import de.bixilon.minosoft.data.world.Chunk
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import glm_.vec2.Vec2i
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3bool
|
||||
import glm_.vec3.Vec3d
|
||||
@ -30,26 +33,32 @@ class CollisionDetector(val connection: PlayConnection) {
|
||||
|
||||
private fun getCollisionsToCheck(deltaPosition: Vec3d, aabb: AABB, ignoreUnloadedChunks: Boolean = true): VoxelShape {
|
||||
// also look at blocks further down to also cover blocks with a higher than normal hitbox (for example fences)
|
||||
val blockPositions = ((aabb extend deltaPosition).grow(1.0 + COLLISION_BOX_MARGIN)).blockPositions.toMutableList()
|
||||
val blockPositions = aabb.offset(deltaPosition).grow(COLLISION_BOX_MARGIN).extend(Directions.DOWN).blockPositions
|
||||
|
||||
val aabbBlockPositions = aabb.shrink().blockPositions
|
||||
|
||||
val result = VoxelShape()
|
||||
var chunk: Chunk? = null
|
||||
var lastChunkPosition: Vec2i? = null
|
||||
for (blockPosition in blockPositions) {
|
||||
val chunk = connection.world[blockPosition.chunkPosition]
|
||||
if ((chunk == null || !chunk.isFullyLoaded) && !ignoreUnloadedChunks) {
|
||||
val chunkPosition = blockPosition.chunkPosition
|
||||
if (lastChunkPosition != chunkPosition) {
|
||||
lastChunkPosition = chunkPosition
|
||||
chunk = connection.world[blockPosition.chunkPosition]
|
||||
}
|
||||
if (chunk == null || !chunk.isFullyLoaded) {
|
||||
// chunk is not loaded
|
||||
result.add(VoxelShape.FULL + blockPosition)
|
||||
if (!ignoreUnloadedChunks) {
|
||||
result += AABB.BLOCK + blockPosition
|
||||
}
|
||||
continue
|
||||
}
|
||||
val blockState = chunk?.get(blockPosition.inChunkPosition) ?: continue
|
||||
val blockState = chunk[blockPosition.inChunkPosition] ?: continue
|
||||
val blockShape = blockState.collisionShape + blockPosition
|
||||
|
||||
// remove position if not already in it and not colliding with it
|
||||
if (blockPosition in aabbBlockPositions) {
|
||||
if (blockShape.intersect(aabb)) {
|
||||
continue
|
||||
}
|
||||
if (blockPosition in aabbBlockPositions && blockShape.intersect(aabb)) {
|
||||
continue
|
||||
}
|
||||
result.add(blockShape)
|
||||
}
|
||||
@ -112,7 +121,7 @@ class CollisionDetector(val connection: PlayConnection) {
|
||||
|
||||
if (stepping && onGround && (blocked.x || blocked.z)) {
|
||||
var stepMovement = adjustMovementForCollisions(Vec3d(movement.x, PhysicsConstants.STEP_HEIGHT, movement.z), aabb)
|
||||
val verticalStepMovement = adjustMovementForCollisions(Vec3d(0.0, PhysicsConstants.STEP_HEIGHT, 0.0), aabb extend Vec3d(movement.x, 0.0, movement.z))
|
||||
val verticalStepMovement = adjustMovementForCollisions(Vec3d(0.0, PhysicsConstants.STEP_HEIGHT, 0.0), aabb.extend(Vec3d(movement.x, 0.0, movement.z)))
|
||||
|
||||
if (verticalStepMovement.y < PhysicsConstants.STEP_HEIGHT) {
|
||||
val horizontalStepMovement = adjustMovementForCollisions(Vec3d(movement.x, 0.0, movement.z), aabb + verticalStepMovement) + verticalStepMovement
|
||||
@ -124,8 +133,8 @@ class CollisionDetector(val connection: PlayConnection) {
|
||||
if (stepMovement.length() > collisionMovement.length()) {
|
||||
returnMovement = stepMovement + adjustMovementForCollisions(Vec3d(0.0, -stepMovement.y + movement.y, 0.0), aabb + stepMovement)
|
||||
}
|
||||
checkBlocked()
|
||||
}
|
||||
checkBlocked()
|
||||
physicsEntity?.let {
|
||||
if (blocked.x) {
|
||||
it.velocity.x = 0.0
|
||||
|
@ -29,12 +29,9 @@ import glm_.vec3.Vec3i
|
||||
import glm_.vec3.Vec3t
|
||||
|
||||
|
||||
class AABB(
|
||||
min: Vec3d,
|
||||
max: Vec3d,
|
||||
) {
|
||||
val min = Vec3d(glm.min(min.x, max.x), glm.min(min.y, max.y), glm.min(min.z, max.z))
|
||||
val max = Vec3d(glm.max(min.x, max.x), glm.max(min.y, max.y), glm.max(min.z, max.z))
|
||||
class AABB {
|
||||
val min: Vec3d
|
||||
val max: Vec3d
|
||||
|
||||
constructor(jsonData: JsonObject) : this(jsonData["from"].toVec3(Vec3.EMPTY), jsonData["to"].toVec3(Vec3.ONE))
|
||||
|
||||
@ -44,19 +41,30 @@ class AABB(
|
||||
|
||||
constructor(min: Vec3, max: Vec3) : this(Vec3d(min), Vec3d(max))
|
||||
|
||||
constructor(min: Vec3d, max: Vec3d) {
|
||||
this.min = Vec3d(glm.min(min.x, max.x), glm.min(min.y, max.y), glm.min(min.z, max.z))
|
||||
this.max = Vec3d(glm.max(min.x, max.x), glm.max(min.y, max.y), glm.max(min.z, max.z))
|
||||
}
|
||||
|
||||
private constructor(unsafe: Boolean, min: Vec3d, max: Vec3d) {
|
||||
this.min = min
|
||||
this.max = max
|
||||
}
|
||||
|
||||
fun intersect(other: AABB): Boolean {
|
||||
return (min.x < other.max.x && max.x > other.min.x) && (min.y < other.max.y && max.y > other.min.y) && (min.z < other.max.z && max.z > other.min.z)
|
||||
}
|
||||
|
||||
operator fun plus(other: Vec3t<out Number>): AABB {
|
||||
return AABB(min + other, max + other)
|
||||
operator fun plus(other: Vec3t<out Number>): AABB = offset(other)
|
||||
|
||||
fun offset(other: Vec3t<out Number>): AABB {
|
||||
return AABB(true, min + other, max + other)
|
||||
}
|
||||
|
||||
operator fun plus(other: AABB): AABB {
|
||||
val newMin = Vec3(glm.min(min.x, other.min.x), glm.min(min.y, other.min.y), glm.min(min.z, other.min.z))
|
||||
val newMax = Vec3(glm.max(max.x, other.max.x), glm.max(max.y, other.max.y), glm.max(max.z, other.max.z))
|
||||
return AABB(newMin, newMax)
|
||||
val newMin = Vec3d(glm.min(min.x, other.min.x), glm.min(min.y, other.min.y), glm.min(min.z, other.min.z))
|
||||
val newMax = Vec3d(glm.max(max.x, other.max.x), glm.max(max.y, other.max.y), glm.max(max.z, other.max.z))
|
||||
return AABB(true, newMin, newMax)
|
||||
}
|
||||
|
||||
val blockPositions: List<Vec3i>
|
||||
@ -84,7 +92,8 @@ class AABB(
|
||||
return axis.choose(max)
|
||||
}
|
||||
|
||||
infix fun extend(vec3: Vec3d): AABB {
|
||||
|
||||
fun extend(vec3: Vec3d): AABB {
|
||||
val newMin = Vec3d(min)
|
||||
val newMax = Vec3d(max)
|
||||
|
||||
@ -106,22 +115,22 @@ class AABB(
|
||||
newMax.z += vec3.z
|
||||
}
|
||||
|
||||
return AABB(newMin, newMax)
|
||||
return AABB(true, newMin, newMax)
|
||||
}
|
||||
|
||||
infix fun extend(vec3i: Vec3i): AABB {
|
||||
return this extend Vec3d(vec3i)
|
||||
fun extend(vec3i: Vec3i): AABB {
|
||||
return this.extend(Vec3d(vec3i))
|
||||
}
|
||||
|
||||
infix fun extend(direction: Directions): AABB {
|
||||
return this extend direction.vector
|
||||
fun extend(direction: Directions): AABB {
|
||||
return this.extend(direction.vectord)
|
||||
}
|
||||
|
||||
fun grow(size: Double = 1.0E-7): AABB {
|
||||
return AABB(min - size, max + size)
|
||||
}
|
||||
|
||||
infix fun grow(size: Float): AABB {
|
||||
fun grow(size: Float): AABB {
|
||||
return AABB(min - size, max + size)
|
||||
}
|
||||
|
||||
@ -230,8 +239,8 @@ class AABB(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val EMPTY: AABB
|
||||
get() = AABB(Vec3.EMPTY, Vec3.EMPTY)
|
||||
val BLOCK: AABB = AABB(Vec3.EMPTY, Vec3.ONE)
|
||||
val EMPTY: AABB = AABB(Vec3.EMPTY, Vec3.EMPTY)
|
||||
|
||||
private fun getRange(min: Double, max: Double): IntRange {
|
||||
return IntRange(min.floor, max.ceil - 1)
|
||||
|
@ -17,11 +17,8 @@ import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonPrimitive
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.ONE
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.getMinDistanceDirection
|
||||
import de.bixilon.minosoft.util.KUtil.toInt
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3d
|
||||
import glm_.vec3.Vec3t
|
||||
|
||||
@ -88,6 +85,12 @@ class VoxelShape(private val aabbs: MutableList<AABB> = mutableListOf()) : Itera
|
||||
}
|
||||
}
|
||||
|
||||
operator fun plusAssign(voxelShape: VoxelShape) = add(voxelShape)
|
||||
|
||||
operator fun plusAssign(aabb: AABB) {
|
||||
aabbs += aabb
|
||||
}
|
||||
|
||||
fun remove(voxelShape: VoxelShape) {
|
||||
for (newAABB in voxelShape.aabbs) {
|
||||
aabbs.remove(newAABB)
|
||||
@ -122,7 +125,7 @@ class VoxelShape(private val aabbs: MutableList<AABB> = mutableListOf()) : Itera
|
||||
|
||||
companion object {
|
||||
val EMPTY = VoxelShape()
|
||||
val FULL = VoxelShape(mutableListOf(AABB(Vec3.EMPTY, Vec3.ONE)))
|
||||
val FULL = VoxelShape(mutableListOf(AABB.BLOCK))
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<AABB> {
|
||||
|
@ -24,7 +24,7 @@ import glm_.vec2.Vec2
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3d
|
||||
|
||||
class ParticleMesh(renderWindow: RenderWindow) : Mesh(renderWindow, ParticleMeshStruct, PrimitiveTypes.POINT) {
|
||||
class ParticleMesh(renderWindow: RenderWindow, initialCacheSize: Int) : Mesh(renderWindow, ParticleMeshStruct, PrimitiveTypes.POINT, initialCacheSize) {
|
||||
|
||||
fun addVertex(position: Vec3d, scale: Float, texture: AbstractTexture, tintColor: RGBColor, uvMin: Vec2 = Vec2(0.0f, 0.0f), uvMax: Vec2 = Vec2(1.0f, 1.0f)) {
|
||||
val textureLayer = if (RenderConstants.FORCE_DEBUG_TEXTURE) {
|
||||
|
@ -24,8 +24,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
|
||||
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
|
||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedSet
|
||||
import glm_.mat4x4.Mat4
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
@ -35,13 +33,14 @@ class ParticleRenderer(
|
||||
val renderWindow: RenderWindow,
|
||||
) : Renderer {
|
||||
private val particleShader: Shader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"))
|
||||
private var particleMesh = ParticleMesh(renderWindow)
|
||||
private var transparentParticleMesh = ParticleMesh(renderWindow)
|
||||
private var particleMesh = ParticleMesh(renderWindow, 0)
|
||||
private var transparentParticleMesh = ParticleMesh(renderWindow, 0)
|
||||
|
||||
private var particles: MutableSet<Particle> = synchronizedSetOf()
|
||||
private var particles: MutableSet<Particle> = mutableSetOf()
|
||||
private var particleQueue: MutableSet<Particle> = mutableSetOf()
|
||||
|
||||
val size: Int
|
||||
get() = particles.size
|
||||
get() = particles.size + particleQueue.size
|
||||
|
||||
override fun init() {
|
||||
connection.registerEvent(CallbackEventInvoker.of<CameraMatrixChangeEvent> {
|
||||
@ -71,8 +70,11 @@ class ParticleRenderer(
|
||||
}
|
||||
|
||||
fun add(particle: Particle) {
|
||||
check(particles.size < RenderConstants.MAXIMUM_PARTICLE_AMOUNT) { "Can not add particle: Limit reached (${particles.size} > ${RenderConstants.MAXIMUM_PARTICLE_AMOUNT}" }
|
||||
particles += particle
|
||||
val particleCount = particles.size + particleQueue.size
|
||||
check(particleCount < RenderConstants.MAXIMUM_PARTICLE_AMOUNT) { "Can not add particle: Limit reached (${particleCount} > ${RenderConstants.MAXIMUM_PARTICLE_AMOUNT}" }
|
||||
synchronized(particleQueue) {
|
||||
particleQueue += particle
|
||||
}
|
||||
}
|
||||
|
||||
operator fun plusAssign(particle: Particle) {
|
||||
@ -82,18 +84,26 @@ class ParticleRenderer(
|
||||
override fun update() {
|
||||
particleMesh.unload()
|
||||
transparentParticleMesh.unload()
|
||||
particleMesh = ParticleMesh(renderWindow)
|
||||
transparentParticleMesh = ParticleMesh(renderWindow)
|
||||
particleMesh = ParticleMesh(renderWindow, particles.size)
|
||||
transparentParticleMesh = ParticleMesh(renderWindow, 500)
|
||||
|
||||
val toRemove: MutableSet<Particle> = mutableSetOf()
|
||||
|
||||
|
||||
for (particle in particles.toSynchronizedSet()) {
|
||||
synchronized(particleQueue) {
|
||||
particles += particleQueue
|
||||
particleQueue.clear()
|
||||
}
|
||||
|
||||
for (particle in particles) {
|
||||
particle.tryTick()
|
||||
if (particle.dead) {
|
||||
this.particles -= particle
|
||||
toRemove += particle
|
||||
continue
|
||||
}
|
||||
particle.addVertex(transparentParticleMesh, particleMesh)
|
||||
}
|
||||
particles -= toRemove
|
||||
|
||||
particleMesh.load()
|
||||
transparentParticleMesh.load()
|
||||
|
Loading…
x
Reference in New Issue
Block a user