mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 18:05:51 -04:00
rendering: improvements, change chunk preparations (meshing)
* Camera: Preserve rotation * Improve meshing code * Fix crash in windows
This commit is contained in:
parent
c31a24135a
commit
bfcd2f50f3
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
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))
|
||||
}
|
||||
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 drawBlock() {
|
||||
block.blockModel.render(position, data, arrayOf(blockBelow, blockAbove, blockNorth, blockSouth, blockWest, blockEast))
|
||||
}
|
||||
drawBlock()
|
||||
}
|
||||
return data.toFloatArray()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 (element in elements) {
|
||||
element.render(textureMapping, model, direction, rotation, data)
|
||||
for (direction in Directions.DIRECTIONS) {
|
||||
for (element in elements) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user