improve raycasting block outline

This commit is contained in:
Bixilon 2021-05-16 13:59:06 +02:00
parent f1e3051f4e
commit 4311eaabaa
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 67 additions and 41 deletions

View File

@ -115,7 +115,7 @@ class World : BiomeAccessor {
return blocks.toMap()
}
data class RayCastHit(
data class RaycastHit(
val position: Vec3,
val distance: Float,
val blockState: BlockState,
@ -124,7 +124,7 @@ class World : BiomeAccessor {
val blockPosition = position.floor
}
fun raycast(origin: Vec3, direction: Vec3): RayCastHit? {
fun raycast(origin: Vec3, direction: Vec3): RaycastHit? {
val currentPosition = Vec3(origin)
fun getTotalDistance(): Float {
@ -140,7 +140,7 @@ class World : BiomeAccessor {
} ?: -1.0f
if (distance >= 0.0f && blockState != null) {
return RayCastHit(
return RaycastHit(
currentPosition + direction * distance,
getTotalDistance() + distance,
blockState = blockState,

View File

@ -303,7 +303,7 @@ class Camera(
cameraPosition = getAbsoluteCameraPosition()
}
fun getTargetBlock(): World.RayCastHit? {
fun getTargetBlock(): World.RaycastHit? {
return connection.world.raycast(cameraPosition, cameraFront)
}

View File

@ -76,4 +76,6 @@ object RenderConstants {
const val DOUBLE_PRESS_KEY_PRESS_MAX_DELAY = 200
const val DOUBLE_PRESS_DELAY_BETWEEN_PRESSED = 500
const val MAX_BLOCK_OUTLINE_RAYCAST_DISTANCE = 5.0f
}

View File

@ -111,7 +111,7 @@ class WorldRenderer(
}
}
if (meshCollection.transparentSectionArrayMesh!!.trianglesCount == 0) {
if (meshCollection.transparentSectionArrayMesh!!.primitiveCount == 0) {
meshCollection.transparentSectionArrayMesh = null
}
@ -321,24 +321,24 @@ class WorldRenderer(
sectionMap[index]?.let {
it.opaqueSectionArrayMesh.unload()
meshes--
triangles -= it.opaqueSectionArrayMesh.trianglesCount
triangles -= it.opaqueSectionArrayMesh.primitiveCount
it.transparentSectionArrayMesh?.let {
it.unload()
meshes--
triangles -= it.trianglesCount
triangles -= it.primitiveCount
}
}
meshCollection.opaqueSectionArrayMesh.let {
it.load()
meshes++
triangles += it.trianglesCount
triangles += it.primitiveCount
}
meshCollection.transparentSectionArrayMesh?.let {
it.load()
meshes++
triangles += it.trianglesCount
triangles += it.primitiveCount
}
@ -390,12 +390,12 @@ class WorldRenderer(
meshCollection.opaqueSectionArrayMesh.let {
it.unload()
this.meshes--
triangles -= it.trianglesCount
triangles -= it.primitiveCount
}
meshCollection.transparentSectionArrayMesh?.let {
it.unload()
this.meshes--
triangles -= it.trianglesCount
triangles -= it.primitiveCount
}
}
}

View File

@ -20,6 +20,7 @@ import org.lwjgl.opengl.GL20.glEnableVertexAttribArray
import org.lwjgl.opengl.GL20.glVertexAttribPointer
class BlockOutlineMesh : Mesh() {
fun addVertex(position: Vec3) {
data.addAll(floatArrayOf(
position.x,
@ -37,6 +38,7 @@ class BlockOutlineMesh : Mesh() {
super.unbind()
}
companion object {
private const val FLOATS_PER_VERTEX = 3
}

View File

@ -13,9 +13,11 @@
package de.bixilon.minosoft.gui.rendering.chunk.block.outline
import de.bixilon.minosoft.data.Gamemodes
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
@ -26,7 +28,7 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL11.*
class BlockOutlineRenderer(
val connection: PlayConnection,
@ -61,17 +63,19 @@ class BlockOutlineRenderer(
for (aabb in shape) {
val min = blockPosition + aabb.min
val max = blockPosition + aabb.max
fun drawSideQuad(x: Float) {
drawLine(Vec3(x, min.y, min.z), Vec3(x, max.y, min.z), mesh)
drawLine(Vec3(x, min.y, min.z), Vec3(x, min.y, max.z), mesh)
drawLine(Vec3(x, max.y, min.z), Vec3(x, max.y, max.z), mesh)
drawLine(Vec3(x, min.y, max.z), Vec3(x, max.y, max.z), mesh)
}
// left quad
drawLine(Vec3(min.x, min.y, min.z), Vec3(min.x, max.y, min.z), mesh)
drawLine(Vec3(min.x, min.y, min.z), Vec3(min.x, min.y, max.z), mesh)
drawLine(Vec3(min.x, max.y, min.z), Vec3(min.x, max.y, max.z), mesh)
drawLine(Vec3(min.x, min.y, max.z), Vec3(min.x, max.y, max.z), mesh)
drawSideQuad(min.x)
// right quad
drawLine(Vec3(max.x, min.y, min.z), Vec3(max.x, max.y, min.z), mesh)
drawLine(Vec3(max.x, min.y, min.z), Vec3(max.x, min.y, max.z), mesh)
drawLine(Vec3(max.x, max.y, min.z), Vec3(max.x, max.y, max.z), mesh)
drawLine(Vec3(max.x, min.y, max.z), Vec3(max.x, max.y, max.z), mesh)
drawSideQuad(max.x)
// connections between 2 quads
drawLine(Vec3(min.x, min.y, min.z), Vec3(max.x, min.y, min.z), mesh)
@ -82,28 +86,45 @@ class BlockOutlineRenderer(
}
private fun draw(mesh: BlockOutlineMesh) {
GL11.glDisable(GL11.GL_CULL_FACE)
glDisable(GL_CULL_FACE)
outlineShader.use()
mesh.draw()
GL11.glEnable(GL11.GL_CULL_FACE)
glEnable(GL_CULL_FACE)
}
private fun unload() {
outlineMesh ?: return
outlineMesh?.unload()
this.outlineMesh = null
this.currentOutlinePosition = null
this.currentOutlineBlockState = null
}
override fun draw() {
val rayCastHit = renderWindow.inputHandler.camera.getTargetBlock()
val raycastHit = renderWindow.inputHandler.camera.getTargetBlock()
var outlineMesh = outlineMesh
if (rayCastHit == null) {
outlineMesh ?: return
outlineMesh.unload()
this.outlineMesh = null
this.currentOutlinePosition = null
this.currentOutlineBlockState = null
if (raycastHit == null) {
unload()
return
}
if (rayCastHit.blockPosition == currentOutlinePosition && rayCastHit.blockState == currentOutlineBlockState) {
if (raycastHit.distance >= RenderConstants.MAX_BLOCK_OUTLINE_RAYCAST_DISTANCE) {
unload()
return
}
if (connection.player.entity.gamemode == Gamemodes.ADVENTURE || connection.player.entity.gamemode == Gamemodes.SPECTATOR) {
if (connection.mapping.blockEntityRegistry.get(raycastHit.blockState.block.resourceLocation) == null) {
unload()
return
}
}
if (raycastHit.blockPosition == currentOutlinePosition && raycastHit.blockState == currentOutlineBlockState) {
draw(outlineMesh!!)
return
}
@ -111,11 +132,11 @@ class BlockOutlineRenderer(
outlineMesh?.unload()
outlineMesh = BlockOutlineMesh()
drawVoxelShape(rayCastHit.blockState.outlineShape, rayCastHit.blockPosition.getWorldOffset(rayCastHit.blockState.block).plus(rayCastHit.blockPosition), outlineMesh)
drawVoxelShape(raycastHit.blockState.outlineShape, raycastHit.blockPosition.getWorldOffset(raycastHit.blockState.block).plus(raycastHit.blockPosition), outlineMesh)
outlineMesh.load()
this.currentOutlinePosition = rayCastHit.blockPosition
this.currentOutlineBlockState = rayCastHit.blockState
this.currentOutlinePosition = raycastHit.blockPosition
this.currentOutlineBlockState = raycastHit.blockState
this.outlineMesh = outlineMesh
draw(outlineMesh)
}
@ -123,7 +144,7 @@ class BlockOutlineRenderer(
companion object : RendererBuilder<BlockOutlineRenderer> {
override val RESOURCE_LOCATION = ResourceLocation("minosoft:block_outline")
private const val LINE_WIDTH = 1.0f / 16.0f
private const val LINE_WIDTH = 1.0f / 64.0f
private const val HALF_LINE_WIDTH = LINE_WIDTH / 2.0f
override fun build(connection: PlayConnection, renderWindow: RenderWindow): BlockOutlineRenderer {

View File

@ -87,10 +87,10 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer
allocatedMemoryText.sText = "Allocated: ${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}"
val rayCastHit = hudRenderer.renderWindow.inputHandler.camera.getTargetBlock()
if (rayCastHit == null) {
targetPosition.sText = "No blocks in reach!"
targetPosition.sText = ""
targetBlockState.sText = ""
} else {
targetPosition.sText = "looking at ${rayCastHit.blockPosition}"
targetPosition.sText = "Target block: ${rayCastHit.blockPosition}"
targetBlockState.sText = rayCastHit.blockState.toString()
}

View File

@ -28,9 +28,10 @@ abstract class Mesh(
_data = value
}
private var vao: Int = -1
protected var vao: Int = -1
private set
private var vbo: Int = -1
var trianglesCount: Int = -1
var primitiveCount: Int = -1
private set
var state = MeshStates.PREPARING
@ -42,7 +43,7 @@ abstract class Mesh(
protected fun initializeBuffers(floatsPerVertex: Int) {
check(state == MeshStates.PREPARING) { "Mesh already loaded: $state" }
trianglesCount = data.size / floatsPerVertex
primitiveCount = data.size / floatsPerVertex
vao = glGenVertexArrays()
vbo = glGenBuffers()
glBindVertexArray(vao)
@ -58,10 +59,10 @@ abstract class Mesh(
glBindBuffer(GL_ARRAY_BUFFER, 0)
}
fun draw() {
open fun draw() {
// check(state == MeshStates.LOADED) { "Mesh not loaded: $state" }
glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES, 0, trianglesCount)
glDrawArrays(GL_TRIANGLES, 0, primitiveCount)
}
fun unload(checkLoaded: Boolean = true) {