mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 09:56:37 -04:00
improve raycasting block outline
This commit is contained in:
parent
f1e3051f4e
commit
4311eaabaa
@ -115,7 +115,7 @@ class World : BiomeAccessor {
|
|||||||
return blocks.toMap()
|
return blocks.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class RayCastHit(
|
data class RaycastHit(
|
||||||
val position: Vec3,
|
val position: Vec3,
|
||||||
val distance: Float,
|
val distance: Float,
|
||||||
val blockState: BlockState,
|
val blockState: BlockState,
|
||||||
@ -124,7 +124,7 @@ class World : BiomeAccessor {
|
|||||||
val blockPosition = position.floor
|
val blockPosition = position.floor
|
||||||
}
|
}
|
||||||
|
|
||||||
fun raycast(origin: Vec3, direction: Vec3): RayCastHit? {
|
fun raycast(origin: Vec3, direction: Vec3): RaycastHit? {
|
||||||
val currentPosition = Vec3(origin)
|
val currentPosition = Vec3(origin)
|
||||||
|
|
||||||
fun getTotalDistance(): Float {
|
fun getTotalDistance(): Float {
|
||||||
@ -140,7 +140,7 @@ class World : BiomeAccessor {
|
|||||||
} ?: -1.0f
|
} ?: -1.0f
|
||||||
|
|
||||||
if (distance >= 0.0f && blockState != null) {
|
if (distance >= 0.0f && blockState != null) {
|
||||||
return RayCastHit(
|
return RaycastHit(
|
||||||
currentPosition + direction * distance,
|
currentPosition + direction * distance,
|
||||||
getTotalDistance() + distance,
|
getTotalDistance() + distance,
|
||||||
blockState = blockState,
|
blockState = blockState,
|
||||||
|
@ -303,7 +303,7 @@ class Camera(
|
|||||||
cameraPosition = getAbsoluteCameraPosition()
|
cameraPosition = getAbsoluteCameraPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTargetBlock(): World.RayCastHit? {
|
fun getTargetBlock(): World.RaycastHit? {
|
||||||
return connection.world.raycast(cameraPosition, cameraFront)
|
return connection.world.raycast(cameraPosition, cameraFront)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,4 +76,6 @@ object RenderConstants {
|
|||||||
|
|
||||||
const val DOUBLE_PRESS_KEY_PRESS_MAX_DELAY = 200
|
const val DOUBLE_PRESS_KEY_PRESS_MAX_DELAY = 200
|
||||||
const val DOUBLE_PRESS_DELAY_BETWEEN_PRESSED = 500
|
const val DOUBLE_PRESS_DELAY_BETWEEN_PRESSED = 500
|
||||||
|
|
||||||
|
const val MAX_BLOCK_OUTLINE_RAYCAST_DISTANCE = 5.0f
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meshCollection.transparentSectionArrayMesh!!.trianglesCount == 0) {
|
if (meshCollection.transparentSectionArrayMesh!!.primitiveCount == 0) {
|
||||||
meshCollection.transparentSectionArrayMesh = null
|
meshCollection.transparentSectionArrayMesh = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,24 +321,24 @@ class WorldRenderer(
|
|||||||
sectionMap[index]?.let {
|
sectionMap[index]?.let {
|
||||||
it.opaqueSectionArrayMesh.unload()
|
it.opaqueSectionArrayMesh.unload()
|
||||||
meshes--
|
meshes--
|
||||||
triangles -= it.opaqueSectionArrayMesh.trianglesCount
|
triangles -= it.opaqueSectionArrayMesh.primitiveCount
|
||||||
|
|
||||||
it.transparentSectionArrayMesh?.let {
|
it.transparentSectionArrayMesh?.let {
|
||||||
it.unload()
|
it.unload()
|
||||||
meshes--
|
meshes--
|
||||||
triangles -= it.trianglesCount
|
triangles -= it.primitiveCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
meshCollection.opaqueSectionArrayMesh.let {
|
meshCollection.opaqueSectionArrayMesh.let {
|
||||||
it.load()
|
it.load()
|
||||||
meshes++
|
meshes++
|
||||||
triangles += it.trianglesCount
|
triangles += it.primitiveCount
|
||||||
}
|
}
|
||||||
meshCollection.transparentSectionArrayMesh?.let {
|
meshCollection.transparentSectionArrayMesh?.let {
|
||||||
it.load()
|
it.load()
|
||||||
meshes++
|
meshes++
|
||||||
triangles += it.trianglesCount
|
triangles += it.primitiveCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -390,12 +390,12 @@ class WorldRenderer(
|
|||||||
meshCollection.opaqueSectionArrayMesh.let {
|
meshCollection.opaqueSectionArrayMesh.let {
|
||||||
it.unload()
|
it.unload()
|
||||||
this.meshes--
|
this.meshes--
|
||||||
triangles -= it.trianglesCount
|
triangles -= it.primitiveCount
|
||||||
}
|
}
|
||||||
meshCollection.transparentSectionArrayMesh?.let {
|
meshCollection.transparentSectionArrayMesh?.let {
|
||||||
it.unload()
|
it.unload()
|
||||||
this.meshes--
|
this.meshes--
|
||||||
triangles -= it.trianglesCount
|
triangles -= it.primitiveCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import org.lwjgl.opengl.GL20.glEnableVertexAttribArray
|
|||||||
import org.lwjgl.opengl.GL20.glVertexAttribPointer
|
import org.lwjgl.opengl.GL20.glVertexAttribPointer
|
||||||
|
|
||||||
class BlockOutlineMesh : Mesh() {
|
class BlockOutlineMesh : Mesh() {
|
||||||
|
|
||||||
fun addVertex(position: Vec3) {
|
fun addVertex(position: Vec3) {
|
||||||
data.addAll(floatArrayOf(
|
data.addAll(floatArrayOf(
|
||||||
position.x,
|
position.x,
|
||||||
@ -37,6 +38,7 @@ class BlockOutlineMesh : Mesh() {
|
|||||||
super.unbind()
|
super.unbind()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val FLOATS_PER_VERTEX = 3
|
private const val FLOATS_PER_VERTEX = 3
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,11 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.gui.rendering.chunk.block.outline
|
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.ResourceLocation
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.BlockState
|
import de.bixilon.minosoft.data.mappings.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.text.ChatColors
|
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.RenderWindow
|
||||||
import de.bixilon.minosoft.gui.rendering.Renderer
|
import de.bixilon.minosoft.gui.rendering.Renderer
|
||||||
import de.bixilon.minosoft.gui.rendering.RendererBuilder
|
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 de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11.*
|
||||||
|
|
||||||
class BlockOutlineRenderer(
|
class BlockOutlineRenderer(
|
||||||
val connection: PlayConnection,
|
val connection: PlayConnection,
|
||||||
@ -61,17 +63,19 @@ class BlockOutlineRenderer(
|
|||||||
for (aabb in shape) {
|
for (aabb in shape) {
|
||||||
val min = blockPosition + aabb.min
|
val min = blockPosition + aabb.min
|
||||||
val max = blockPosition + aabb.max
|
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
|
// left quad
|
||||||
drawLine(Vec3(min.x, min.y, min.z), Vec3(min.x, max.y, min.z), mesh)
|
drawSideQuad(min.x)
|
||||||
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)
|
|
||||||
|
|
||||||
// right quad
|
// right quad
|
||||||
drawLine(Vec3(max.x, min.y, min.z), Vec3(max.x, max.y, min.z), mesh)
|
drawSideQuad(max.x)
|
||||||
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)
|
|
||||||
|
|
||||||
// connections between 2 quads
|
// connections between 2 quads
|
||||||
drawLine(Vec3(min.x, min.y, min.z), Vec3(max.x, min.y, min.z), mesh)
|
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) {
|
private fun draw(mesh: BlockOutlineMesh) {
|
||||||
GL11.glDisable(GL11.GL_CULL_FACE)
|
glDisable(GL_CULL_FACE)
|
||||||
outlineShader.use()
|
outlineShader.use()
|
||||||
mesh.draw()
|
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() {
|
override fun draw() {
|
||||||
val rayCastHit = renderWindow.inputHandler.camera.getTargetBlock()
|
val raycastHit = renderWindow.inputHandler.camera.getTargetBlock()
|
||||||
|
|
||||||
var outlineMesh = outlineMesh
|
var outlineMesh = outlineMesh
|
||||||
|
|
||||||
|
|
||||||
if (rayCastHit == null) {
|
|
||||||
outlineMesh ?: return
|
if (raycastHit == null) {
|
||||||
outlineMesh.unload()
|
unload()
|
||||||
this.outlineMesh = null
|
|
||||||
this.currentOutlinePosition = null
|
|
||||||
this.currentOutlineBlockState = null
|
|
||||||
return
|
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!!)
|
draw(outlineMesh!!)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -111,11 +132,11 @@ class BlockOutlineRenderer(
|
|||||||
outlineMesh?.unload()
|
outlineMesh?.unload()
|
||||||
outlineMesh = BlockOutlineMesh()
|
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()
|
outlineMesh.load()
|
||||||
|
|
||||||
this.currentOutlinePosition = rayCastHit.blockPosition
|
this.currentOutlinePosition = raycastHit.blockPosition
|
||||||
this.currentOutlineBlockState = rayCastHit.blockState
|
this.currentOutlineBlockState = raycastHit.blockState
|
||||||
this.outlineMesh = outlineMesh
|
this.outlineMesh = outlineMesh
|
||||||
draw(outlineMesh)
|
draw(outlineMesh)
|
||||||
}
|
}
|
||||||
@ -123,7 +144,7 @@ class BlockOutlineRenderer(
|
|||||||
|
|
||||||
companion object : RendererBuilder<BlockOutlineRenderer> {
|
companion object : RendererBuilder<BlockOutlineRenderer> {
|
||||||
override val RESOURCE_LOCATION = ResourceLocation("minosoft:block_outline")
|
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
|
private const val HALF_LINE_WIDTH = LINE_WIDTH / 2.0f
|
||||||
|
|
||||||
override fun build(connection: PlayConnection, renderWindow: RenderWindow): BlockOutlineRenderer {
|
override fun build(connection: PlayConnection, renderWindow: RenderWindow): BlockOutlineRenderer {
|
||||||
|
@ -87,10 +87,10 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer
|
|||||||
allocatedMemoryText.sText = "Allocated: ${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}"
|
allocatedMemoryText.sText = "Allocated: ${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}"
|
||||||
val rayCastHit = hudRenderer.renderWindow.inputHandler.camera.getTargetBlock()
|
val rayCastHit = hudRenderer.renderWindow.inputHandler.camera.getTargetBlock()
|
||||||
if (rayCastHit == null) {
|
if (rayCastHit == null) {
|
||||||
targetPosition.sText = "No blocks in reach!"
|
targetPosition.sText = ""
|
||||||
targetBlockState.sText = ""
|
targetBlockState.sText = ""
|
||||||
} else {
|
} else {
|
||||||
targetPosition.sText = "looking at ${rayCastHit.blockPosition}"
|
targetPosition.sText = "Target block: ${rayCastHit.blockPosition}"
|
||||||
targetBlockState.sText = rayCastHit.blockState.toString()
|
targetBlockState.sText = rayCastHit.blockState.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,9 +28,10 @@ abstract class Mesh(
|
|||||||
_data = value
|
_data = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private var vao: Int = -1
|
protected var vao: Int = -1
|
||||||
|
private set
|
||||||
private var vbo: Int = -1
|
private var vbo: Int = -1
|
||||||
var trianglesCount: Int = -1
|
var primitiveCount: Int = -1
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var state = MeshStates.PREPARING
|
var state = MeshStates.PREPARING
|
||||||
@ -42,7 +43,7 @@ abstract class Mesh(
|
|||||||
protected fun initializeBuffers(floatsPerVertex: Int) {
|
protected fun initializeBuffers(floatsPerVertex: Int) {
|
||||||
check(state == MeshStates.PREPARING) { "Mesh already loaded: $state" }
|
check(state == MeshStates.PREPARING) { "Mesh already loaded: $state" }
|
||||||
|
|
||||||
trianglesCount = data.size / floatsPerVertex
|
primitiveCount = data.size / floatsPerVertex
|
||||||
vao = glGenVertexArrays()
|
vao = glGenVertexArrays()
|
||||||
vbo = glGenBuffers()
|
vbo = glGenBuffers()
|
||||||
glBindVertexArray(vao)
|
glBindVertexArray(vao)
|
||||||
@ -58,10 +59,10 @@ abstract class Mesh(
|
|||||||
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun draw() {
|
open fun draw() {
|
||||||
// check(state == MeshStates.LOADED) { "Mesh not loaded: $state" }
|
// check(state == MeshStates.LOADED) { "Mesh not loaded: $state" }
|
||||||
glBindVertexArray(vao)
|
glBindVertexArray(vao)
|
||||||
glDrawArrays(GL_TRIANGLES, 0, trianglesCount)
|
glDrawArrays(GL_TRIANGLES, 0, primitiveCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unload(checkLoaded: Boolean = true) {
|
fun unload(checkLoaded: Boolean = true) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user