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) {
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) {
@ -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) {
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) {
cameraPosition = cameraPosition - CAMERA_UP_VEC3 * cameraSpeed
}
@ -89,6 +89,10 @@ class Camera(private var fov: Float, private val windowId: Long) {
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 {
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)
for ((position, block) in section.blocks) {
for (direction in Directions.DIRECTIONS) {
var blockToCheck: Block? = null
when (direction) {
Directions.DOWN -> {
if (position.y == 0) {
below?.let {
blockToCheck = it.getBlock(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z)
val blockBelow: Block? = if (position.y == 0 && below != null) {
below.getBlock(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z)
} else {
section.getBlock(position.getLocationByDirection(Directions.DOWN))
}
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 -> {
if (position.y == ProtocolDefinition.SECTION_HEIGHT_Y - 1) {
above?.let {
blockToCheck = it.getBlock(position.x, 0, position.z)
}
}
}
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 blockSouth: Block? = if (position.z == ProtocolDefinition.SECTION_WIDTH_Z - 1 && south != null) {
south.getBlock(position.x, position.y, 0)
} else {
section.getBlock(position.getLocationByDirection(Directions.SOUTH))
}
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() {
block.blockModel.render(position, direction, data)
}
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()
fun drawBlock() {
block.blockModel.render(position, data, arrayOf(blockBelow, blockAbove, blockNorth, blockSouth, blockWest, blockEast))
}
drawBlock()
}
return data.toFloatArray()
}

View File

@ -60,15 +60,6 @@ class RenderWindow(private val connection: Connection) {
}
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 ->
run {
if (action != GLFW_RELEASE) {
@ -126,6 +117,16 @@ class RenderWindow(private val connection: Connection) {
camera.calculateProjectionMatrix(screenWidth, screenHeight, 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()
}

View File

@ -1,5 +1,6 @@
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.world.Chunk
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 de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.blocks.Block
import de.bixilon.minosoft.data.world.InChunkSectionLocation
import de.bixilon.minosoft.gui.rendering.textures.Texture
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 textureMapping: MutableMap<String, Texture> = mutableMapOf()
private var elements: MutableList<BlockModelElement> = parent?.elements?.toMutableList() ?: mutableListOf()
private val fullFaceDirections: MutableSet<Directions> = parent?.fullFaceDirections?.toMutableSet() ?: mutableSetOf()
private var rotation: Vec3
private var uvLock = false // ToDo
@ -28,41 +30,54 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
}
json["elements"]?.let { it ->
elements.clear()
fullFaceDirections.clear()
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 rotateY = parent?.rotation?.y ?: 0
var rotateZ = parent?.rotation?.z ?: 0
var rotateX = parent?.rotation?.x ?: 0f
var rotateY = parent?.rotation?.y ?: 0f
var rotateZ = parent?.rotation?.z ?: 0f
json["x"]?.let {
rotateX = it.asInt
rotateX = it.asFloat
}
json["y"]?.let {
rotateY = it.asInt
rotateY = it.asFloat
}
json["z"]?.let {
rotateZ = it.asInt
rotateZ = it.asFloat
}
json["uvlock"]?.let {
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>) {
var model = Mat4().translate(Vec3(position.x, position.y, position.z))
open fun render(position: InChunkSectionLocation, data: MutableList<Float>, neighbourBlocks: Array<Block?>) {
var modelMatrix = Mat4().translate(Vec3(position.x, position.y, position.z))
if (rotation.x > 0 || rotation.y > 0 || rotation.z > 0) {
model = model.rotate(glm.radians(rotation.x), Vec3(-1, 0, 0))
.rotate(glm.radians(rotation.y), Vec3(0, -1, 0))
.rotate(glm.radians(rotation.z), Vec3(0, 0, -1))
// ToDo: this should be made easier/effizienter
modelMatrix = modelMatrix.rotate(rotation.x, Vec3(-1, 0, 0))
.rotate(rotation.y, Vec3(0, -1, 0))
.rotate(rotation.z, Vec3(0, 0, -1))
// ToDo: this should be made easier/more efficient
}
for (direction in Directions.DIRECTIONS) {
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 to: Vec3 = Vec3(16, 16, 16)
private val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
var fullFace = false
init {
data["from"]?.let {
@ -24,10 +26,47 @@ open class BlockModelElement(data: JsonObject) {
to = Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
}
data["faces"]?.let {
for ((direction, json) in it.asJsonObject.entrySet()) {
faces[Directions.valueOf(direction.toUpperCase())] = BlockModelFace(json.asJsonObject)
for ((directionName, json) in it.asJsonObject.entrySet()) {
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))
@ -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 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 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) {
val input = Vec4(vec3, 1.0f)
val output = model * input
val output = modelMatrix * input
data.add(output.x)
data.add(output.y)
data.add(output.z)
data.add(textureCoordinates.x)
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) {

View File

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