mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 11:54:59 -04:00
remove greedy meshing #47
This commit is contained in:
parent
d3bf46c327
commit
e581e19873
@ -66,5 +66,4 @@ class WeightedBakedModel(
|
|||||||
random.setSeed(VecUtil.generatePositionHash(blockPosition.x, blockPosition.y, blockPosition.z))
|
random.setSeed(VecUtil.generatePositionHash(blockPosition.x, blockPosition.y, blockPosition.z))
|
||||||
return getModel(random)?.getParticleTexture(random, blockPosition)
|
return getModel(random)?.getParticleTexture(random, blockPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTex
|
|||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh
|
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -69,15 +68,6 @@ class BakedBlockStateModel(
|
|||||||
return rendered
|
return rendered
|
||||||
}
|
}
|
||||||
|
|
||||||
fun greedyRender(start: Vec3i, end: Vec3i, side: Directions, mesh: SingleWorldMesh, light: Int) {
|
|
||||||
TODO()
|
|
||||||
val floatStart = start.toVec3()
|
|
||||||
val floatEnd = end.toVec3()
|
|
||||||
for (face in faces[side.ordinal]) {
|
|
||||||
face.greedyRender(floatStart, floatEnd, side, mesh, light)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getParticleTexture(random: Random, blockPosition: Vec3i): AbstractTexture? {
|
override fun getParticleTexture(random: Random, blockPosition: Vec3i): AbstractTexture? {
|
||||||
return particleTexture
|
return particleTexture
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,7 @@ import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFacePropertie
|
|||||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
||||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh
|
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.get
|
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rgb
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rgb
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh
|
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||||
|
|
||||||
class BakedFace(
|
class BakedFace(
|
||||||
@ -55,34 +53,4 @@ class BakedFace(
|
|||||||
meshToUse.addVertex(floatArrayOf(indexPosition[0] + position[0], indexPosition[1] + position[1], indexPosition[2] + position[2]), uv[textureIndex], texture, color.rgb, light)
|
meshToUse.addVertex(floatArrayOf(indexPosition[0] + position[0], indexPosition[1] + position[1], indexPosition[2] + position[2]), uv[textureIndex], texture, color.rgb, light)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun greedyRender(start: Vec3, end: Vec3, side: Directions, mesh: SingleWorldMesh, light: Int) {
|
|
||||||
val multiplier = end - start
|
|
||||||
val positions = arrayOf(
|
|
||||||
(positions[0] * multiplier) + start,
|
|
||||||
(positions[1] * multiplier) + start,
|
|
||||||
(positions[2] * multiplier) + start,
|
|
||||||
(positions[3] * multiplier) + start,
|
|
||||||
)
|
|
||||||
val fixPosition = this.positions[0][side.axis]
|
|
||||||
for (position in positions) {
|
|
||||||
when (side.axis) {
|
|
||||||
Axes.X -> position.x = start.x + fixPosition
|
|
||||||
Axes.Y -> position.y = start.y + fixPosition
|
|
||||||
Axes.Z -> position.z = start.z + fixPosition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val uvMultiplier = side.getUVMultiplier(start, end)
|
|
||||||
val uv = arrayOf(
|
|
||||||
uv[0] * uvMultiplier,
|
|
||||||
uv[1] * uvMultiplier,
|
|
||||||
uv[2] * uvMultiplier,
|
|
||||||
uv[3] * uvMultiplier,
|
|
||||||
)
|
|
||||||
for ((index, textureIndex) in mesh.order) {
|
|
||||||
// ToDo
|
|
||||||
mesh.addVertex(positions[index].array, uv[textureIndex], texture, 0xFFFFFF, light)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020-2022 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.models.baked.block
|
|
||||||
|
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
|
||||||
import de.bixilon.minosoft.data.direction.Directions
|
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh
|
|
||||||
|
|
||||||
interface GreedyBakedBlockModel {
|
|
||||||
val canGreedyMesh: Boolean
|
|
||||||
val greedyMeshableFaces: BooleanArray
|
|
||||||
|
|
||||||
// ToDo: Tint
|
|
||||||
fun greedyRender(start: Vec3i, end: Vec3i, side: Directions, mesh: SingleWorldMesh, light: Int)
|
|
||||||
}
|
|
@ -1,238 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020-2022 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.world.preparer
|
|
||||||
|
|
||||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
|
||||||
import de.bixilon.kutil.primitive.BooleanUtil.decide
|
|
||||||
import de.bixilon.minosoft.data.direction.Directions
|
|
||||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
|
||||||
import de.bixilon.minosoft.data.world.Chunk
|
|
||||||
import de.bixilon.minosoft.data.world.ChunkSection
|
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
|
||||||
import de.bixilon.minosoft.gui.rendering.models.baked.block.GreedyBakedBlockModel
|
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh
|
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.SECTION_SIZE
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
@Deprecated("TODO")
|
|
||||||
class GreedySectionPreparer(
|
|
||||||
val renderWindow: RenderWindow,
|
|
||||||
) /*: SolidSectionPreparer*/ {
|
|
||||||
|
|
||||||
private fun renderNormal(block: BlockState, directions: Directions?, position: Vec3i, section: ChunkSection, mesh: SingleWorldMesh, random: Random) {
|
|
||||||
val neighbour = section.blocks[ChunkSection.getIndex(position.x, position.y, position.z)]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// base taken from https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/
|
|
||||||
@Deprecated("TODO")
|
|
||||||
fun prepareSolid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array<ChunkSection?>, neighbourChunks: Array<Chunk>): WorldMesh {
|
|
||||||
val mesh = SingleWorldMesh(renderWindow, 20000)
|
|
||||||
|
|
||||||
val random = Random(0L)
|
|
||||||
|
|
||||||
var currentBlock: BlockState?
|
|
||||||
var compareBlock: BlockState?
|
|
||||||
var start: Vec3i
|
|
||||||
var end: Vec3i
|
|
||||||
|
|
||||||
var i: Int
|
|
||||||
var j: Int
|
|
||||||
var k: Int
|
|
||||||
var l: Int
|
|
||||||
var w: Int
|
|
||||||
var h: Int
|
|
||||||
val stateMask: Array<BlockState?> = arrayOfNulls(SECTION_SIZE * SECTION_SIZE)
|
|
||||||
val meshableMask = BooleanArray(SECTION_SIZE * SECTION_SIZE) { true }
|
|
||||||
val endOffset = IntArray(3)
|
|
||||||
|
|
||||||
for (direction in Directions.VALUES) {
|
|
||||||
// Sweep over each direction
|
|
||||||
val negative = direction.negative
|
|
||||||
val axis = direction.axis.ordinal
|
|
||||||
val nextAxis = (axis + 1) % 3
|
|
||||||
val nextNextAxis = (axis + 2) % 3
|
|
||||||
val position = IntArray(3)
|
|
||||||
val checkOffset = IntArray(3)
|
|
||||||
|
|
||||||
checkOffset[axis] = 1
|
|
||||||
|
|
||||||
val offsetCheck = negative.decide(-1, 1)
|
|
||||||
|
|
||||||
// Check each slice of the chunk one at a time
|
|
||||||
|
|
||||||
position[axis] = -1
|
|
||||||
while (position[axis] < SECTION_SIZE) {
|
|
||||||
|
|
||||||
// Compute the mask
|
|
||||||
var n = 0
|
|
||||||
position[nextNextAxis] = 0
|
|
||||||
while (position[nextNextAxis] < SECTION_SIZE) {
|
|
||||||
position[nextAxis] = 0
|
|
||||||
while (position[nextAxis] < SECTION_SIZE) {
|
|
||||||
if ((offsetCheck == 1 && position[axis] < 0) || (offsetCheck == -1 && position[axis] > SECTION_SIZE)) {
|
|
||||||
++position[nextAxis]
|
|
||||||
n++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
currentBlock = if (position[axis] >= 0) section.blocks[ChunkSection.getIndex(position[0], position[1], position[2])] else null
|
|
||||||
compareBlock = if (position[axis] < SECTION_SIZE - 1) section.blocks[ChunkSection.getIndex(position[0] + checkOffset[0], position[1] + checkOffset[1], position[2] + checkOffset[2])] else null
|
|
||||||
|
|
||||||
// The mask is set to true if there is a visible face between those two blocks
|
|
||||||
val primaryBlock = if (negative) {
|
|
||||||
compareBlock
|
|
||||||
} else {
|
|
||||||
currentBlock
|
|
||||||
}
|
|
||||||
val model = primaryBlock?.blockModel
|
|
||||||
|
|
||||||
val meshable = model is GreedyBakedBlockModel
|
|
||||||
&& model.canGreedyMesh
|
|
||||||
&& model.greedyMeshableFaces[direction.ordinal]
|
|
||||||
|
|
||||||
|
|
||||||
val face = currentBlock == null
|
|
||||||
|| compareBlock == null
|
|
||||||
|| currentBlock != compareBlock
|
|
||||||
|| !meshable
|
|
||||||
|
|
||||||
if (!meshable) {
|
|
||||||
meshableMask[n] = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (face) {
|
|
||||||
stateMask[n] = primaryBlock
|
|
||||||
}
|
|
||||||
n++
|
|
||||||
|
|
||||||
++position[nextAxis]
|
|
||||||
}
|
|
||||||
++position[nextNextAxis]
|
|
||||||
}
|
|
||||||
++position[axis]
|
|
||||||
n = 0
|
|
||||||
|
|
||||||
// Generate a mesh from the mask using lexicographic ordering,
|
|
||||||
// by looping over each block in this slice of the chunk
|
|
||||||
j = 0
|
|
||||||
while (j < SECTION_SIZE) {
|
|
||||||
i = 0
|
|
||||||
while (i < SECTION_SIZE) {
|
|
||||||
if (stateMask[n] != null) {
|
|
||||||
// Compute the width of this quad and store it in w
|
|
||||||
// This is done by searching along the current axis until mask[n + w] is false
|
|
||||||
w = 1
|
|
||||||
while (i + w < SECTION_SIZE && stateMask[n + w] == stateMask[n]) {
|
|
||||||
w++
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Compute the height of this quad and store it in h
|
|
||||||
// This is done by checking if every block next to this row (range 0 to w) is also part of the mask.
|
|
||||||
// For example, if w is 5 we currently have a quad of dimensions 1 x 5. To reduce triangle count,
|
|
||||||
// greedy meshing will attempt to expand this quad out to CHUNK_SIZE x 5, but will stop if it reaches a hole in the mask
|
|
||||||
var done = false
|
|
||||||
|
|
||||||
h = 1
|
|
||||||
while (j + h < SECTION_SIZE) {
|
|
||||||
k = 0
|
|
||||||
while (k < w) {
|
|
||||||
val compareIndex = n + k + h * SECTION_SIZE
|
|
||||||
if (stateMask[compareIndex] != stateMask[n] || !meshableMask[compareIndex]) {
|
|
||||||
done = true
|
|
||||||
}
|
|
||||||
k++
|
|
||||||
}
|
|
||||||
if (done) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
h++
|
|
||||||
}
|
|
||||||
|
|
||||||
position[nextAxis] = i
|
|
||||||
position[nextNextAxis] = j
|
|
||||||
|
|
||||||
// du and dv determine the size and orientation of this face
|
|
||||||
val du = IntArray(3)
|
|
||||||
du[nextAxis] = w
|
|
||||||
val dv = IntArray(3)
|
|
||||||
dv[nextNextAxis] = h
|
|
||||||
|
|
||||||
endOffset[0] = du[0] + dv[0]
|
|
||||||
endOffset[1] = du[1] + dv[1]
|
|
||||||
endOffset[2] = du[2] + dv[2]
|
|
||||||
|
|
||||||
|
|
||||||
if (!negative) {
|
|
||||||
position[axis] -= offsetCheck
|
|
||||||
}
|
|
||||||
|
|
||||||
start = Vec3i(position)
|
|
||||||
|
|
||||||
currentBlock = section.blocks[ChunkSection.getIndex(position[0], position[1], position[2])]!!
|
|
||||||
|
|
||||||
if (endOffset[0] == 0 && endOffset[1] == 0 && endOffset[2] == 0) {
|
|
||||||
// single render
|
|
||||||
renderNormal(currentBlock, direction, start, section, mesh, random)
|
|
||||||
} else {
|
|
||||||
endOffset[0] += position[0]
|
|
||||||
endOffset[1] += position[1]
|
|
||||||
endOffset[2] += position[2]
|
|
||||||
|
|
||||||
end = Vec3i(endOffset)
|
|
||||||
|
|
||||||
val model = currentBlock.blockModel
|
|
||||||
model as GreedyBakedBlockModel
|
|
||||||
|
|
||||||
|
|
||||||
model.greedyRender(start, end, direction, mesh, 0xFF)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!negative) {
|
|
||||||
position[axis] += offsetCheck
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear this part of the mask, so we don't add duplicate faces
|
|
||||||
l = 0
|
|
||||||
while (l < h) {
|
|
||||||
k = 0
|
|
||||||
while (k < w) {
|
|
||||||
val index = n + k + l * SECTION_SIZE
|
|
||||||
stateMask[index] = null
|
|
||||||
meshableMask[index] = true
|
|
||||||
++k
|
|
||||||
}
|
|
||||||
++l
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment counters and continue
|
|
||||||
i += w
|
|
||||||
n += w
|
|
||||||
} else {
|
|
||||||
i++
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++j
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TODO()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user