mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 03:15:35 -04:00
rendering: transparency improvements (2 meshes)
This commit is contained in:
parent
c31115b858
commit
6930fa378a
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.chunk
|
||||
|
||||
data class ChunkMeshCollection(
|
||||
val opaqueSectionArrayMesh: SectionArrayMesh = SectionArrayMesh(),
|
||||
var transparentSectionArrayMesh: SectionArrayMesh? = SectionArrayMesh(),
|
||||
) {
|
||||
var lowestBlockHeight = 0
|
||||
var highestBlockHeight = 0
|
||||
}
|
@ -25,8 +25,6 @@ import org.lwjgl.opengl.GL20.glEnableVertexAttribArray
|
||||
import org.lwjgl.opengl.GL20.glVertexAttribPointer
|
||||
|
||||
class SectionArrayMesh : Mesh(initialCacheSize = 100000) {
|
||||
var lowestBlockHeight = 0
|
||||
var highestBlockHeight = 0
|
||||
|
||||
fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?, lightLevel: Int = 14) {
|
||||
val data = data!!
|
||||
|
@ -37,8 +37,8 @@ class WorldRenderer(
|
||||
val renderWindow: RenderWindow,
|
||||
) : Renderer {
|
||||
lateinit var chunkShader: Shader
|
||||
val allChunkSections = ConcurrentHashMap<ChunkPosition, ConcurrentHashMap<Int, SectionArrayMesh>>()
|
||||
val visibleChunks = ConcurrentHashMap<ChunkPosition, ConcurrentHashMap<Int, SectionArrayMesh>>()
|
||||
val allChunkSections = ConcurrentHashMap<ChunkPosition, ConcurrentHashMap<Int, ChunkMeshCollection>>()
|
||||
val visibleChunks = ConcurrentHashMap<ChunkPosition, ConcurrentHashMap<Int, ChunkMeshCollection>>()
|
||||
val queuedChunks: MutableSet<ChunkPosition> = mutableSetOf()
|
||||
|
||||
var meshes = 0
|
||||
@ -46,7 +46,7 @@ class WorldRenderer(
|
||||
var triangles = 0
|
||||
private set
|
||||
|
||||
private fun prepareSections(chunkPosition: ChunkPosition, sections: Map<Int, ChunkSection>): SectionArrayMesh {
|
||||
private fun prepareSections(chunkPosition: ChunkPosition, sections: Map<Int, ChunkSection>): ChunkMeshCollection {
|
||||
// val stopwatch = Stopwatch()
|
||||
|
||||
check(sections.isNotEmpty()) { "Illegal argument!" }
|
||||
@ -56,7 +56,7 @@ class WorldRenderer(
|
||||
val chunk = world.getChunk(chunkPosition) ?: error("Chunk in world is null at $chunkPosition?")
|
||||
|
||||
val dimensionSupports3dBiomes = connection.player.world.dimension?.supports3DBiomes ?: false
|
||||
val mesh = SectionArrayMesh()
|
||||
val meshCollection = ChunkMeshCollection()
|
||||
|
||||
for ((sectionHeight, section) in sections) {
|
||||
for ((index, blockInfo) in section.blocks.withIndex()) {
|
||||
@ -88,12 +88,16 @@ class WorldRenderer(
|
||||
blockInfo.tintColor?.let { tintColor = it }
|
||||
}
|
||||
|
||||
blockInfo.getBlockRenderer(blockPosition).render(blockInfo, world.worldLightAccessor, tintColor, blockPosition, mesh, neighborBlocks, world)
|
||||
blockInfo.getBlockRenderer(blockPosition).render(blockInfo, world.worldLightAccessor, tintColor, blockPosition, meshCollection, neighborBlocks, world)
|
||||
}
|
||||
}
|
||||
|
||||
if (meshCollection.transparentSectionArrayMesh!!.trianglesCount == 0) {
|
||||
meshCollection.transparentSectionArrayMesh = null
|
||||
}
|
||||
|
||||
// stopwatch.labPrint()
|
||||
return mesh
|
||||
return meshCollection
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
@ -127,7 +131,13 @@ class WorldRenderer(
|
||||
|
||||
for ((_, map) in visibleChunks) {
|
||||
for ((_, mesh) in map) {
|
||||
mesh.draw()
|
||||
mesh.opaqueSectionArrayMesh.draw()
|
||||
}
|
||||
}
|
||||
|
||||
for ((_, map) in visibleChunks) {
|
||||
for ((_, mesh) in map) {
|
||||
mesh.transparentSectionArrayMesh?.draw()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,7 +224,7 @@ class WorldRenderer(
|
||||
return
|
||||
}
|
||||
Minosoft.THREAD_POOL.execute {
|
||||
val mesh = prepareSections(chunkPosition, sections)
|
||||
val meshCollection = prepareSections(chunkPosition, sections)
|
||||
|
||||
var lowestBlockHeight = 0
|
||||
var highestBlockHeight = 0
|
||||
@ -232,27 +242,41 @@ class WorldRenderer(
|
||||
|
||||
|
||||
val index = getSectionIndex(highestBlockHeight)
|
||||
mesh.lowestBlockHeight = lowestBlockHeight
|
||||
mesh.highestBlockHeight = highestBlockHeight
|
||||
meshCollection.lowestBlockHeight = lowestBlockHeight
|
||||
meshCollection.highestBlockHeight = highestBlockHeight
|
||||
|
||||
|
||||
renderWindow.renderQueue.add {
|
||||
val sectionMap = allChunkSections.getOrPut(chunkPosition, { ConcurrentHashMap() })
|
||||
|
||||
sectionMap[index]?.let {
|
||||
it.unload()
|
||||
it.opaqueSectionArrayMesh.unload()
|
||||
meshes--
|
||||
triangles -= it.trianglesCount
|
||||
triangles -= it.opaqueSectionArrayMesh.trianglesCount
|
||||
|
||||
it.transparentSectionArrayMesh?.let {
|
||||
it.unload()
|
||||
meshes--
|
||||
triangles -= it.trianglesCount
|
||||
}
|
||||
}
|
||||
|
||||
mesh.load()
|
||||
meshes++
|
||||
triangles += mesh.trianglesCount
|
||||
meshCollection.opaqueSectionArrayMesh.let {
|
||||
it.load()
|
||||
meshes++
|
||||
triangles += it.trianglesCount
|
||||
}
|
||||
meshCollection.transparentSectionArrayMesh?.let {
|
||||
it.load()
|
||||
meshes++
|
||||
triangles += it.trianglesCount
|
||||
}
|
||||
|
||||
sectionMap[index] = mesh
|
||||
|
||||
sectionMap[index] = meshCollection
|
||||
|
||||
if (renderWindow.camera.frustum.containsChunk(chunkPosition, lowestBlockHeight, highestBlockHeight)) {
|
||||
visibleChunks.getOrPut(chunkPosition, { ConcurrentHashMap() })[index] = mesh
|
||||
visibleChunks.getOrPut(chunkPosition, { ConcurrentHashMap() })[index] = meshCollection
|
||||
} else {
|
||||
visibleChunks[chunkPosition]?.remove(index)
|
||||
}
|
||||
@ -289,10 +313,17 @@ class WorldRenderer(
|
||||
}
|
||||
renderWindow.renderQueue.add {
|
||||
allChunkSections[chunkPosition]?.let {
|
||||
for ((_, mesh) in it) {
|
||||
mesh.unload()
|
||||
meshes--
|
||||
triangles -= mesh.trianglesCount
|
||||
for ((_, meshCollection) in it) {
|
||||
meshCollection.opaqueSectionArrayMesh.let {
|
||||
it.unload()
|
||||
meshes--
|
||||
triangles -= it.trianglesCount
|
||||
}
|
||||
meshCollection.transparentSectionArrayMesh?.let {
|
||||
it.unload()
|
||||
meshes--
|
||||
triangles -= it.trianglesCount
|
||||
}
|
||||
}
|
||||
allChunkSections.remove(chunkPosition)
|
||||
visibleChunks.remove(chunkPosition)
|
||||
@ -314,7 +345,7 @@ class WorldRenderer(
|
||||
fun recalculateVisibleChunks() {
|
||||
visibleChunks.clear()
|
||||
for ((chunkLocation, indexMap) in allChunkSections) {
|
||||
val visibleIndexMap: ConcurrentHashMap<Int, SectionArrayMesh> = ConcurrentHashMap()
|
||||
val visibleIndexMap: ConcurrentHashMap<Int, ChunkMeshCollection> = ConcurrentHashMap()
|
||||
for ((index, mesh) in indexMap) {
|
||||
if (renderWindow.camera.frustum.containsChunk(chunkLocation, mesh.lowestBlockHeight, mesh.highestBlockHeight)) {
|
||||
visibleIndexMap[index] = mesh
|
||||
|
@ -6,14 +6,14 @@ import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
|
||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||
|
||||
interface BlockRenderInterface {
|
||||
val fullFaceDirections: Array<Directions?>
|
||||
val transparentFaces: Array<Directions?>
|
||||
|
||||
fun render(blockState: BlockState, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: SectionArrayMesh, neighbourBlocks: Array<BlockState?>, world: World)
|
||||
fun render(blockState: BlockState, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, meshCollection: ChunkMeshCollection, neighbourBlocks: Array<BlockState?>, world: World)
|
||||
|
||||
fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>)
|
||||
|
||||
|
@ -21,7 +21,7 @@ import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
|
||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureTransparencies
|
||||
@ -92,7 +92,7 @@ class BlockRenderer: BlockRenderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(blockState: BlockState, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: SectionArrayMesh, neighbourBlocks: Array<BlockState?>, world: World) {
|
||||
override fun render(blockState: BlockState, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, meshCollection: ChunkMeshCollection, neighbourBlocks: Array<BlockState?>, world: World) {
|
||||
val modelMatrix = Mat4().translate(position.toVec3())
|
||||
|
||||
for (direction in Directions.DIRECTIONS) {
|
||||
@ -112,7 +112,7 @@ class BlockRenderer: BlockRenderInterface {
|
||||
if (neighbourBlockFullFace && cullFace) {
|
||||
continue
|
||||
}
|
||||
element.render(tintColor, position, lightAccessor, textureMapping, modelMatrix, direction, mesh)
|
||||
element.render(tintColor, position, lightAccessor, textureMapping, modelMatrix, direction, meshCollection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,13 @@ import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelFace
|
||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||
import glm_.Java.Companion.glm
|
||||
import glm_.mat4x4.Mat4
|
||||
@ -62,7 +64,7 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
||||
}
|
||||
|
||||
|
||||
fun render(tintColor: RGBColor?, position: BlockPosition, lightAccessor: LightAccessor, textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, mesh: SectionArrayMesh) {
|
||||
fun render(tintColor: RGBColor?, position: BlockPosition, lightAccessor: LightAccessor, textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, meshCollection: ChunkMeshCollection) {
|
||||
val realDirection = directionMapping.inverse()[direction]!!
|
||||
|
||||
val face = faces[realDirection] ?: return // Not our face
|
||||
@ -74,6 +76,8 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
||||
|
||||
val drawPositions = arrayOf(positions[positionTemplate[0]], positions[positionTemplate[1]], positions[positionTemplate[2]], positions[positionTemplate[3]])
|
||||
|
||||
val mesh = getMesh(meshCollection, texture.transparency)
|
||||
|
||||
fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>) {
|
||||
for (vertex in DRAW_ODER) {
|
||||
val input = Vec4(drawPositions[vertex.first], 1.0f)
|
||||
@ -91,6 +95,7 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val texturePositions = face.getTexturePositionArray(realDirection)
|
||||
createQuad(drawPositions, texturePositions)
|
||||
}
|
||||
@ -181,6 +186,14 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
||||
setOf(POSITION_2, POSITION_4, POSITION_6, POSITION_8),
|
||||
setOf(POSITION_1, POSITION_3, POSITION_5, POSITION_7)
|
||||
)
|
||||
|
||||
fun getMesh(meshCollection: ChunkMeshCollection, textureTransparencies: TextureTransparencies): SectionArrayMesh {
|
||||
return if (textureTransparencies == TextureTransparencies.SEMI_TRANSPARENT) {
|
||||
meshCollection.transparentSectionArrayMesh!!
|
||||
} else {
|
||||
meshCollection.opaqueSectionArrayMesh
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelFace
|
||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||
@ -28,7 +28,7 @@ class FluidRenderer(
|
||||
private var still: Texture? = null
|
||||
private var flowing: Texture? = null
|
||||
|
||||
override fun render(blockState: BlockState, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: SectionArrayMesh, neighbourBlocks: Array<BlockState?>, world: World) {
|
||||
override fun render(blockState: BlockState, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, meshCollection: ChunkMeshCollection, neighbourBlocks: Array<BlockState?>, world: World) {
|
||||
val modelMatrix = Mat4().translate(position.toVec3())
|
||||
val lightLevel = lightAccessor.getLightLevel(position)
|
||||
val heights = calculateHeights(neighbourBlocks, blockState, world, position)
|
||||
@ -56,7 +56,7 @@ class FluidRenderer(
|
||||
face.rotate(angle)
|
||||
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[direction.ordinal]
|
||||
val drawPositions = arrayOf(positions[positionTemplate[0]], positions[positionTemplate[1]], positions[positionTemplate[2]], positions[positionTemplate[3]])
|
||||
createQuad(drawPositions, face.getTexturePositionArray(direction), texture, modelMatrix, mesh, tintColor, lightLevel)
|
||||
createQuad(drawPositions, face.getTexturePositionArray(direction), texture, modelMatrix, meshCollection, tintColor, lightLevel)
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +103,8 @@ class FluidRenderer(
|
||||
return heights.toSet().size != 1 // liquid is flowing, if not all of the heights are the same
|
||||
}
|
||||
|
||||
private fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>, texture: Texture, modelMatrix: Mat4, mesh: SectionArrayMesh, tintColor: RGBColor?, lightLevel: Int) {
|
||||
private fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>, texture: Texture, modelMatrix: Mat4, meshCollection: ChunkMeshCollection, tintColor: RGBColor?, lightLevel: Int) {
|
||||
val mesh = ElementRenderer.getMesh(meshCollection, texture.transparency)
|
||||
for (vertex in ElementRenderer.DRAW_ODER) {
|
||||
val input = Vec4(drawPositions[vertex.first], 1.0f)
|
||||
val output = modelMatrix * input
|
||||
|
Loading…
x
Reference in New Issue
Block a user