mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 02:45:13 -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
|
package de.bixilon.minosoft.data.physics
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.Axes
|
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.player.LocalPlayerEntity
|
||||||
import de.bixilon.minosoft.data.registries.AABB
|
import de.bixilon.minosoft.data.registries.AABB
|
||||||
import de.bixilon.minosoft.data.registries.VoxelShape
|
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.EMPTY
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
|
import glm_.vec2.Vec2i
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import glm_.vec3.Vec3bool
|
import glm_.vec3.Vec3bool
|
||||||
import glm_.vec3.Vec3d
|
import glm_.vec3.Vec3d
|
||||||
@ -30,26 +33,32 @@ class CollisionDetector(val connection: PlayConnection) {
|
|||||||
|
|
||||||
private fun getCollisionsToCheck(deltaPosition: Vec3d, aabb: AABB, ignoreUnloadedChunks: Boolean = true): VoxelShape {
|
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)
|
// 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 aabbBlockPositions = aabb.shrink().blockPositions
|
||||||
|
|
||||||
val result = VoxelShape()
|
val result = VoxelShape()
|
||||||
|
var chunk: Chunk? = null
|
||||||
|
var lastChunkPosition: Vec2i? = null
|
||||||
for (blockPosition in blockPositions) {
|
for (blockPosition in blockPositions) {
|
||||||
val chunk = connection.world[blockPosition.chunkPosition]
|
val chunkPosition = blockPosition.chunkPosition
|
||||||
if ((chunk == null || !chunk.isFullyLoaded) && !ignoreUnloadedChunks) {
|
if (lastChunkPosition != chunkPosition) {
|
||||||
|
lastChunkPosition = chunkPosition
|
||||||
|
chunk = connection.world[blockPosition.chunkPosition]
|
||||||
|
}
|
||||||
|
if (chunk == null || !chunk.isFullyLoaded) {
|
||||||
// chunk is not loaded
|
// chunk is not loaded
|
||||||
result.add(VoxelShape.FULL + blockPosition)
|
if (!ignoreUnloadedChunks) {
|
||||||
|
result += AABB.BLOCK + blockPosition
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val blockState = chunk?.get(blockPosition.inChunkPosition) ?: continue
|
val blockState = chunk[blockPosition.inChunkPosition] ?: continue
|
||||||
val blockShape = blockState.collisionShape + blockPosition
|
val blockShape = blockState.collisionShape + blockPosition
|
||||||
|
|
||||||
// remove position if not already in it and not colliding with it
|
// remove position if not already in it and not colliding with it
|
||||||
if (blockPosition in aabbBlockPositions) {
|
if (blockPosition in aabbBlockPositions && blockShape.intersect(aabb)) {
|
||||||
if (blockShape.intersect(aabb)) {
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result.add(blockShape)
|
result.add(blockShape)
|
||||||
}
|
}
|
||||||
@ -112,7 +121,7 @@ class CollisionDetector(val connection: PlayConnection) {
|
|||||||
|
|
||||||
if (stepping && onGround && (blocked.x || blocked.z)) {
|
if (stepping && onGround && (blocked.x || blocked.z)) {
|
||||||
var stepMovement = adjustMovementForCollisions(Vec3d(movement.x, PhysicsConstants.STEP_HEIGHT, movement.z), aabb)
|
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) {
|
if (verticalStepMovement.y < PhysicsConstants.STEP_HEIGHT) {
|
||||||
val horizontalStepMovement = adjustMovementForCollisions(Vec3d(movement.x, 0.0, movement.z), aabb + verticalStepMovement) + verticalStepMovement
|
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()) {
|
if (stepMovement.length() > collisionMovement.length()) {
|
||||||
returnMovement = stepMovement + adjustMovementForCollisions(Vec3d(0.0, -stepMovement.y + movement.y, 0.0), aabb + stepMovement)
|
returnMovement = stepMovement + adjustMovementForCollisions(Vec3d(0.0, -stepMovement.y + movement.y, 0.0), aabb + stepMovement)
|
||||||
}
|
}
|
||||||
|
checkBlocked()
|
||||||
}
|
}
|
||||||
checkBlocked()
|
|
||||||
physicsEntity?.let {
|
physicsEntity?.let {
|
||||||
if (blocked.x) {
|
if (blocked.x) {
|
||||||
it.velocity.x = 0.0
|
it.velocity.x = 0.0
|
||||||
|
@ -29,12 +29,9 @@ import glm_.vec3.Vec3i
|
|||||||
import glm_.vec3.Vec3t
|
import glm_.vec3.Vec3t
|
||||||
|
|
||||||
|
|
||||||
class AABB(
|
class AABB {
|
||||||
min: Vec3d,
|
val min: Vec3d
|
||||||
max: Vec3d,
|
val 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))
|
|
||||||
|
|
||||||
constructor(jsonData: JsonObject) : this(jsonData["from"].toVec3(Vec3.EMPTY), jsonData["to"].toVec3(Vec3.ONE))
|
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: 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 {
|
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)
|
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 {
|
operator fun plus(other: Vec3t<out Number>): AABB = offset(other)
|
||||||
return AABB(min + other, max + other)
|
|
||||||
|
fun offset(other: Vec3t<out Number>): AABB {
|
||||||
|
return AABB(true, min + other, max + other)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun plus(other: AABB): AABB {
|
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 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 = Vec3(glm.max(max.x, other.max.x), glm.max(max.y, other.max.y), glm.max(max.z, other.max.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(newMin, newMax)
|
return AABB(true, newMin, newMax)
|
||||||
}
|
}
|
||||||
|
|
||||||
val blockPositions: List<Vec3i>
|
val blockPositions: List<Vec3i>
|
||||||
@ -84,7 +92,8 @@ class AABB(
|
|||||||
return axis.choose(max)
|
return axis.choose(max)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun extend(vec3: Vec3d): AABB {
|
|
||||||
|
fun extend(vec3: Vec3d): AABB {
|
||||||
val newMin = Vec3d(min)
|
val newMin = Vec3d(min)
|
||||||
val newMax = Vec3d(max)
|
val newMax = Vec3d(max)
|
||||||
|
|
||||||
@ -106,22 +115,22 @@ class AABB(
|
|||||||
newMax.z += vec3.z
|
newMax.z += vec3.z
|
||||||
}
|
}
|
||||||
|
|
||||||
return AABB(newMin, newMax)
|
return AABB(true, newMin, newMax)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun extend(vec3i: Vec3i): AABB {
|
fun extend(vec3i: Vec3i): AABB {
|
||||||
return this extend Vec3d(vec3i)
|
return this.extend(Vec3d(vec3i))
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun extend(direction: Directions): AABB {
|
fun extend(direction: Directions): AABB {
|
||||||
return this extend direction.vector
|
return this.extend(direction.vectord)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun grow(size: Double = 1.0E-7): AABB {
|
fun grow(size: Double = 1.0E-7): AABB {
|
||||||
return AABB(min - size, max + size)
|
return AABB(min - size, max + size)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun grow(size: Float): AABB {
|
fun grow(size: Float): AABB {
|
||||||
return AABB(min - size, max + size)
|
return AABB(min - size, max + size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,8 +239,8 @@ class AABB(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY: AABB
|
val BLOCK: AABB = AABB(Vec3.EMPTY, Vec3.ONE)
|
||||||
get() = AABB(Vec3.EMPTY, Vec3.EMPTY)
|
val EMPTY: AABB = AABB(Vec3.EMPTY, Vec3.EMPTY)
|
||||||
|
|
||||||
private fun getRange(min: Double, max: Double): IntRange {
|
private fun getRange(min: Double, max: Double): IntRange {
|
||||||
return IntRange(min.floor, max.ceil - 1)
|
return IntRange(min.floor, max.ceil - 1)
|
||||||
|
@ -17,11 +17,8 @@ import com.google.gson.JsonArray
|
|||||||
import com.google.gson.JsonPrimitive
|
import com.google.gson.JsonPrimitive
|
||||||
import de.bixilon.minosoft.data.Axes
|
import de.bixilon.minosoft.data.Axes
|
||||||
import de.bixilon.minosoft.data.direction.Directions
|
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.gui.rendering.util.VecUtil.getMinDistanceDirection
|
||||||
import de.bixilon.minosoft.util.KUtil.toInt
|
import de.bixilon.minosoft.util.KUtil.toInt
|
||||||
import glm_.vec3.Vec3
|
|
||||||
import glm_.vec3.Vec3d
|
import glm_.vec3.Vec3d
|
||||||
import glm_.vec3.Vec3t
|
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) {
|
fun remove(voxelShape: VoxelShape) {
|
||||||
for (newAABB in voxelShape.aabbs) {
|
for (newAABB in voxelShape.aabbs) {
|
||||||
aabbs.remove(newAABB)
|
aabbs.remove(newAABB)
|
||||||
@ -122,7 +125,7 @@ class VoxelShape(private val aabbs: MutableList<AABB> = mutableListOf()) : Itera
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = VoxelShape()
|
val EMPTY = VoxelShape()
|
||||||
val FULL = VoxelShape(mutableListOf(AABB(Vec3.EMPTY, Vec3.ONE)))
|
val FULL = VoxelShape(mutableListOf(AABB.BLOCK))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iterator(): Iterator<AABB> {
|
override fun iterator(): Iterator<AABB> {
|
||||||
|
@ -24,7 +24,7 @@ import glm_.vec2.Vec2
|
|||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import glm_.vec3.Vec3d
|
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)) {
|
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) {
|
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.modding.event.invoker.CallbackEventInvoker
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
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_.mat4x4.Mat4
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
@ -35,13 +33,14 @@ class ParticleRenderer(
|
|||||||
val renderWindow: RenderWindow,
|
val renderWindow: RenderWindow,
|
||||||
) : Renderer {
|
) : Renderer {
|
||||||
private val particleShader: Shader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"))
|
private val particleShader: Shader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"))
|
||||||
private var particleMesh = ParticleMesh(renderWindow)
|
private var particleMesh = ParticleMesh(renderWindow, 0)
|
||||||
private var transparentParticleMesh = ParticleMesh(renderWindow)
|
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
|
val size: Int
|
||||||
get() = particles.size
|
get() = particles.size + particleQueue.size
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
connection.registerEvent(CallbackEventInvoker.of<CameraMatrixChangeEvent> {
|
connection.registerEvent(CallbackEventInvoker.of<CameraMatrixChangeEvent> {
|
||||||
@ -71,8 +70,11 @@ class ParticleRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun add(particle: Particle) {
|
fun add(particle: Particle) {
|
||||||
check(particles.size < RenderConstants.MAXIMUM_PARTICLE_AMOUNT) { "Can not add particle: Limit reached (${particles.size} > ${RenderConstants.MAXIMUM_PARTICLE_AMOUNT}" }
|
val particleCount = particles.size + particleQueue.size
|
||||||
particles += particle
|
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) {
|
operator fun plusAssign(particle: Particle) {
|
||||||
@ -82,18 +84,26 @@ class ParticleRenderer(
|
|||||||
override fun update() {
|
override fun update() {
|
||||||
particleMesh.unload()
|
particleMesh.unload()
|
||||||
transparentParticleMesh.unload()
|
transparentParticleMesh.unload()
|
||||||
particleMesh = ParticleMesh(renderWindow)
|
particleMesh = ParticleMesh(renderWindow, particles.size)
|
||||||
transparentParticleMesh = ParticleMesh(renderWindow)
|
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()
|
particle.tryTick()
|
||||||
if (particle.dead) {
|
if (particle.dead) {
|
||||||
this.particles -= particle
|
toRemove += particle
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
particle.addVertex(transparentParticleMesh, particleMesh)
|
particle.addVertex(transparentParticleMesh, particleMesh)
|
||||||
}
|
}
|
||||||
|
particles -= toRemove
|
||||||
|
|
||||||
particleMesh.load()
|
particleMesh.load()
|
||||||
transparentParticleMesh.load()
|
transparentParticleMesh.load()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user