rendering: improvements, change chunk preparations (meshing)

* Camera: Preserve rotation
* Improve meshing code
* Fix crash in windows
This commit is contained in:
Bixilon 2021-02-07 16:40:59 +01:00
parent c31a24135a
commit bfcd2f50f3
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
7 changed files with 138 additions and 104 deletions

View File

@ -34,7 +34,7 @@ class Camera(private var fov: Float, private val windowId: Long) {
} else if (this.pitch < -89.0) { } else if (this.pitch < -89.0) {
this.pitch = -89.0 this.pitch = -89.0
} }
cameraFront = Vec3((cos(glm.radians(yaw)) * cos(glm.radians(pitch))).toFloat(), sin(glm.radians(pitch)).toFloat(), (sin(glm.radians(yaw)) * cos(glm.radians(pitch))).toFloat()).normalize() setRotation(yaw, pitch)
} }
fun handleInput(deltaTime: Double) { fun handleInput(deltaTime: Double) {
@ -56,7 +56,7 @@ class Camera(private var fov: Float, private val windowId: Long) {
if (GLFW.glfwGetKey(windowId, GLFW.GLFW_KEY_D) == GLFW.GLFW_PRESS) { if (GLFW.glfwGetKey(windowId, GLFW.GLFW_KEY_D) == GLFW.GLFW_PRESS) {
cameraPosition = cameraPosition + (cameraFront.cross(CAMERA_UP_VEC3).normalize()) * cameraSpeed cameraPosition = cameraPosition + (cameraFront.cross(CAMERA_UP_VEC3).normalize()) * cameraSpeed
} }
this.cameraPosition.y = currentY // stay on xz line when moving (aka. no clip) this.cameraPosition.y = currentY // stay on xz line when moving (aka. no clip): ToDo: make movement not slower when you look up
if (GLFW.glfwGetKey(windowId, GLFW.GLFW_KEY_LEFT_SHIFT) == GLFW.GLFW_PRESS) { if (GLFW.glfwGetKey(windowId, GLFW.GLFW_KEY_LEFT_SHIFT) == GLFW.GLFW_PRESS) {
cameraPosition = cameraPosition - CAMERA_UP_VEC3 * cameraSpeed cameraPosition = cameraPosition - CAMERA_UP_VEC3 * cameraSpeed
} }
@ -89,6 +89,10 @@ class Camera(private var fov: Float, private val windowId: Long) {
cameraPosition = position cameraPosition = position
} }
fun setRotation(yaw: Double, pitch: Double) {
cameraFront = Vec3((cos(glm.radians(yaw)) * cos(glm.radians(pitch))).toFloat(), sin(glm.radians(pitch)).toFloat(), (sin(glm.radians(yaw)) * cos(glm.radians(pitch))).toFloat()).normalize()
}
companion object { companion object {
private val CAMERA_UP_VEC3 = Vec3(0.0f, 1.0f, 0.0f) private val CAMERA_UP_VEC3 = Vec3(0.0f, 1.0f, 0.0f)
} }

View File

@ -25,78 +25,41 @@ object ChunkPreparer {
val east = world.allChunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight) val east = world.allChunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight)
for ((position, block) in section.blocks) { for ((position, block) in section.blocks) {
for (direction in Directions.DIRECTIONS) { val blockBelow: Block? = if (position.y == 0 && below != null) {
var blockToCheck: Block? = null below.getBlock(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z)
when (direction) { } else {
Directions.DOWN -> { section.getBlock(position.getLocationByDirection(Directions.DOWN))
if (position.y == 0) {
below?.let {
blockToCheck = it.getBlock(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z)
} }
val blockAbove: Block? = if (position.y == ProtocolDefinition.SECTION_HEIGHT_Y - 1 && above != null) {
above.getBlock(position.x, 0, position.z)
} else {
section.getBlock(position.getLocationByDirection(Directions.UP))
} }
val blockNorth: Block? = if (position.z == 0 && north != null) {
north.getBlock(position.x, position.y, ProtocolDefinition.SECTION_WIDTH_Z - 1)
} else {
section.getBlock(position.getLocationByDirection(Directions.NORTH))
} }
Directions.UP -> { val blockSouth: Block? = if (position.z == ProtocolDefinition.SECTION_WIDTH_Z - 1 && south != null) {
if (position.y == ProtocolDefinition.SECTION_HEIGHT_Y - 1) { south.getBlock(position.x, position.y, 0)
above?.let { } else {
blockToCheck = it.getBlock(position.x, 0, position.z) section.getBlock(position.getLocationByDirection(Directions.SOUTH))
}
}
}
Directions.NORTH -> {
if (position.z == 0) {
north?.let {
blockToCheck = it.getBlock(position.x, position.y, ProtocolDefinition.SECTION_WIDTH_Z - 1)
}
}
}
Directions.SOUTH -> {
if (position.z == ProtocolDefinition.SECTION_WIDTH_Z - 1) {
south?.let {
blockToCheck = it.getBlock(position.x, position.y, 0)
}
}
}
Directions.WEST -> {
if (position.x == 0) {
west?.let {
blockToCheck = it.getBlock(ProtocolDefinition.SECTION_WIDTH_X - 1, position.y, position.z)
}
}
}
Directions.EAST -> {
if (position.x == ProtocolDefinition.SECTION_WIDTH_X - 1) {
east?.let {
blockToCheck = it.getBlock(0, position.y, position.z)
}
} }
val blockWest: Block? = if (position.x == 0 && west != null) {
west.getBlock(ProtocolDefinition.SECTION_WIDTH_X - 1, position.y, position.x)
} else {
section.getBlock(position.getLocationByDirection(Directions.WEST))
} }
val blockEast: Block? = if (position.x == ProtocolDefinition.SECTION_WIDTH_X - 1 && east != null) {
east.getBlock(0, position.y, position.x)
} else {
section.getBlock(position.getLocationByDirection(Directions.EAST))
} }
fun drawFace() { fun drawBlock() {
block.blockModel.render(position, direction, data) block.blockModel.render(position, data, arrayOf(blockBelow, blockAbove, blockNorth, blockSouth, blockWest, blockEast))
}
if (blockToCheck == null) {
blockToCheck = section.getBlock(position.getLocationByDirection(direction))
}
if (blockToCheck != null) {
val blockTransparent = block.blockModel.isTransparent(direction)
val checkTransparent = blockToCheck!!.blockModel.isTransparent(direction)
if (blockTransparent && checkTransparent) {
continue
}
if (checkTransparent) {
drawFace()
continue
}
if (block.blockModel.isCullFace(direction) && blockToCheck!!.blockModel.isCullFace(direction.inverse())) {
continue
}
// ToDo: Block rotations (this is buggy)
}
drawFace()
} }
drawBlock()
} }
return data.toFloatArray() return data.toFloatArray()
} }

View File

@ -60,15 +60,6 @@ class RenderWindow(private val connection: Connection) {
} }
camera = Camera(60f, windowId) camera = Camera(60f, windowId)
glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() {
override fun invoke(window: Long, width: Int, height: Int) {
glViewport(0, 0, width, height)
screenWidth = width
screenHeight = height
camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader)
}
})
glfwSetKeyCallback(this.windowId) { windowId: Long, key: Int, scanCode: Int, action: Int, mods: Int -> glfwSetKeyCallback(this.windowId) { windowId: Long, key: Int, scanCode: Int, action: Int, mods: Int ->
run { run {
if (action != GLFW_RELEASE) { if (action != GLFW_RELEASE) {
@ -126,6 +117,16 @@ class RenderWindow(private val connection: Connection) {
camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader) camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader)
camera.calculateViewMatrix(chunkShader) camera.calculateViewMatrix(chunkShader)
glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() {
override fun invoke(window: Long, width: Int, height: Int) {
glViewport(0, 0, width, height)
screenWidth = width
screenHeight = height
camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader)
}
})
latch?.countDown() latch?.countDown()
} }

View File

@ -1,5 +1,6 @@
package de.bixilon.minosoft.gui.rendering package de.bixilon.minosoft.gui.rendering
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.Location import de.bixilon.minosoft.data.entities.Location
import de.bixilon.minosoft.data.world.Chunk import de.bixilon.minosoft.data.world.Chunk
import de.bixilon.minosoft.data.world.ChunkLocation import de.bixilon.minosoft.data.world.ChunkLocation
@ -67,4 +68,10 @@ class Renderer(private val connection: Connection) {
} }
} }
fun rotate(rotation: EntityRotation) {
renderWindow.renderQueue.add {
renderWindow.camera.setRotation(rotation.yaw.toDouble(), rotation.pitch.toDouble())
}
}
} }

View File

@ -2,6 +2,7 @@ package de.bixilon.minosoft.gui.rendering.models
import com.google.gson.JsonObject import com.google.gson.JsonObject
import de.bixilon.minosoft.data.Directions import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.blocks.Block
import de.bixilon.minosoft.data.world.InChunkSectionLocation import de.bixilon.minosoft.data.world.InChunkSectionLocation
import de.bixilon.minosoft.gui.rendering.textures.Texture import de.bixilon.minosoft.gui.rendering.textures.Texture
import glm_.glm import glm_.glm
@ -12,6 +13,7 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
private val textures: MutableMap<String, String> = parent?.textures?.toMutableMap() ?: mutableMapOf() private val textures: MutableMap<String, String> = parent?.textures?.toMutableMap() ?: mutableMapOf()
private val textureMapping: MutableMap<String, Texture> = mutableMapOf() private val textureMapping: MutableMap<String, Texture> = mutableMapOf()
private var elements: MutableList<BlockModelElement> = parent?.elements?.toMutableList() ?: mutableListOf() private var elements: MutableList<BlockModelElement> = parent?.elements?.toMutableList() ?: mutableListOf()
private val fullFaceDirections: MutableSet<Directions> = parent?.fullFaceDirections?.toMutableSet() ?: mutableSetOf()
private var rotation: Vec3 private var rotation: Vec3
private var uvLock = false // ToDo private var uvLock = false // ToDo
@ -28,41 +30,54 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
} }
json["elements"]?.let { it -> json["elements"]?.let { it ->
elements.clear() elements.clear()
fullFaceDirections.clear()
for (element in it.asJsonArray) { for (element in it.asJsonArray) {
elements.add(BlockModelElement(element.asJsonObject)) val blockModelElement = BlockModelElement(element.asJsonObject)
elements.add(blockModelElement)
fullFaceDirections.addAll(blockModelElement.fullFaceDirections)
} }
} }
var rotateX = parent?.rotation?.x ?: 0 var rotateX = parent?.rotation?.x ?: 0f
var rotateY = parent?.rotation?.y ?: 0 var rotateY = parent?.rotation?.y ?: 0f
var rotateZ = parent?.rotation?.z ?: 0 var rotateZ = parent?.rotation?.z ?: 0f
json["x"]?.let { json["x"]?.let {
rotateX = it.asInt rotateX = it.asFloat
} }
json["y"]?.let { json["y"]?.let {
rotateY = it.asInt rotateY = it.asFloat
} }
json["z"]?.let { json["z"]?.let {
rotateZ = it.asInt rotateZ = it.asFloat
} }
json["uvlock"]?.let { json["uvlock"]?.let {
uvLock = it.asBoolean uvLock = it.asBoolean
} }
rotation = Vec3(rotateX, rotateY, rotateZ) rotation = glm.radians(Vec3(rotateX, rotateY, rotateZ))
} }
open fun render(position: InChunkSectionLocation, direction: Directions, data: MutableList<Float>) { open fun render(position: InChunkSectionLocation, data: MutableList<Float>, neighbourBlocks: Array<Block?>) {
var model = Mat4().translate(Vec3(position.x, position.y, position.z)) var modelMatrix = Mat4().translate(Vec3(position.x, position.y, position.z))
if (rotation.x > 0 || rotation.y > 0 || rotation.z > 0) { if (rotation.x > 0 || rotation.y > 0 || rotation.z > 0) {
model = model.rotate(glm.radians(rotation.x), Vec3(-1, 0, 0)) modelMatrix = modelMatrix.rotate(rotation.x, Vec3(-1, 0, 0))
.rotate(glm.radians(rotation.y), Vec3(0, -1, 0)) .rotate(rotation.y, Vec3(0, -1, 0))
.rotate(glm.radians(rotation.z), Vec3(0, 0, -1)) .rotate(rotation.z, Vec3(0, 0, -1))
// ToDo: this should be made easier/effizienter // ToDo: this should be made easier/more efficient
} }
for (direction in Directions.DIRECTIONS) {
for (element in elements) { for (element in elements) {
element.render(textureMapping, model, direction, rotation, data) val blockFullFace = fullFaceDirections.contains(direction)
val neighbourBlockFullFace = neighbourBlocks[direction.ordinal]?.blockModel?.fullFaceDirections?.contains(direction.inverse()) == true
if (blockFullFace && neighbourBlockFullFace) {
continue
}
if (!blockFullFace && neighbourBlockFullFace) {
continue
}
element.render(textureMapping, modelMatrix, direction, rotation, data)
}
} }
} }

View File

@ -13,6 +13,8 @@ open class BlockModelElement(data: JsonObject) {
private var from: Vec3 = Vec3(0, 0, 0) private var from: Vec3 = Vec3(0, 0, 0)
private var to: Vec3 = Vec3(16, 16, 16) private var to: Vec3 = Vec3(16, 16, 16)
private val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf() private val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
var fullFace = false
init { init {
data["from"]?.let { data["from"]?.let {
@ -24,10 +26,47 @@ open class BlockModelElement(data: JsonObject) {
to = Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat) to = Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
} }
data["faces"]?.let { data["faces"]?.let {
for ((direction, json) in it.asJsonObject.entrySet()) { for ((directionName, json) in it.asJsonObject.entrySet()) {
faces[Directions.valueOf(direction.toUpperCase())] = BlockModelFace(json.asJsonObject) val direction = Directions.valueOf(directionName.toUpperCase())
when (direction) {
Directions.DOWN -> {
if ((from.y == 0f || to.y == 0f) && ((from.x == 0f && to.z == 16f) || (from.z == 16f && to.x == 0f))) {
fullFace = true
} }
} }
Directions.UP -> {
if ((from.y == 16f || to.y == 16f) && ((from.x == 0f && to.z == 16f) || (from.z == 16f && to.x == 0f))) {
fullFace = true
}
}
Directions.NORTH -> {
if ((from.x == 0f || to.x == 0f) && ((from.y == 0f && to.y == 16f) || (from.z == 16f && to.z == 0f))) {
fullFace = true
}
}
Directions.SOUTH -> {
if ((from.x == 16f || to.x == 16f) && ((from.y == 0f && to.y == 16f) || (from.z == 16f && to.z == 0f))) {
fullFace = true
}
}
Directions.EAST -> {
if ((from.z == 0f || to.z == 0f) && ((from.y == 0f && to.y == 16f) || (from.x == 16f && to.x == 0f))) {
fullFace = true
}
}
Directions.WEST -> {
if ((from.z == 16f || to.z == 16f) && ((from.y == 0f && to.y == 16f) || (from.x == 16f && to.x == 0f))) {
fullFace = true
}
}
}
faces[direction] = BlockModelFace(json.asJsonObject)
if (fullFace) {
fullFaceDirections.add(direction)
}
}
}
} }
private val positionUpLeftFront = Vec3(BlockModel.positionToFloat(from.x), BlockModel.positionToFloat(to.y), BlockModel.positionToFloat(from.z)) private val positionUpLeftFront = Vec3(BlockModel.positionToFloat(from.x), BlockModel.positionToFloat(to.y), BlockModel.positionToFloat(from.z))
@ -40,20 +79,24 @@ open class BlockModelElement(data: JsonObject) {
private val positionDownRightFront = Vec3(BlockModel.positionToFloat(to.x), BlockModel.positionToFloat(from.y), BlockModel.positionToFloat(from.z)) private val positionDownRightFront = Vec3(BlockModel.positionToFloat(to.x), BlockModel.positionToFloat(from.y), BlockModel.positionToFloat(from.z))
private val positionDownRightBack = Vec3(BlockModel.positionToFloat(to.x), BlockModel.positionToFloat(from.y), BlockModel.positionToFloat(to.z)) private val positionDownRightBack = Vec3(BlockModel.positionToFloat(to.x), BlockModel.positionToFloat(from.y), BlockModel.positionToFloat(to.z))
open fun render(textureMapping: MutableMap<String, Texture>, model: Mat4, direction: Directions, rotation: Vec3, data: MutableList<Float>) { open fun render(textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, rotation: Vec3, data: MutableList<Float>) {
val face = faces[direction] ?: return // Not our face val face = faces[direction] ?: return // Not our face
val texture = textureMapping[face.textureName]?.id ?: TextureArray.DEBUG_TEXTURE.id val texture = textureMapping[face.textureName] ?: TextureArray.DEBUG_TEXTURE
if (texture.isTransparent) {
return
}
fun addToData(vec3: Vec3, textureCoordinates: Vec2) { fun addToData(vec3: Vec3, textureCoordinates: Vec2) {
val input = Vec4(vec3, 1.0f) val input = Vec4(vec3, 1.0f)
val output = model * input val output = modelMatrix * input
data.add(output.x) data.add(output.x)
data.add(output.y) data.add(output.y)
data.add(output.z) data.add(output.z)
data.add(textureCoordinates.x) data.add(textureCoordinates.x)
data.add(textureCoordinates.y) data.add(textureCoordinates.y)
data.add(texture.toFloat()) // ToDo: Compact this data.add(texture.id.toFloat()) // ToDo: Compact this
} }
fun createQuad(vertexPosition1: Vec3, vertexPosition2: Vec3, vertexPosition3: Vec3, vertexPosition4: Vec3, texturePosition1: Vec2, texturePosition2: Vec2, texturePosition3: Vec2, texturePosition4: Vec2) { fun createQuad(vertexPosition1: Vec3, vertexPosition2: Vec3, vertexPosition3: Vec3, vertexPosition4: Vec3, texturePosition1: Vec2, texturePosition2: Vec2, texturePosition3: Vec2, texturePosition4: Vec2) {

View File

@ -59,6 +59,7 @@ public class PacketPlayerPositionAndRotation extends ClientboundPacket {
connection.sendPacket(new PacketPlayerPositionAndRotationSending(getLocation(), getRotation(), isOnGround())); connection.sendPacket(new PacketPlayerPositionAndRotationSending(getLocation(), getRotation(), isOnGround()));
} }
connection.getRenderer().teleport(this.location); connection.getRenderer().teleport(this.location);
connection.getRenderer().rotate(this.rotation);
} }
@Override @Override