mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 03:44:54 -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))
|
||||
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.getWorldOffset
|
||||
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 java.util.*
|
||||
|
||||
@ -69,15 +68,6 @@ class BakedBlockStateModel(
|
||||
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? {
|
||||
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.texture.AbstractTexture
|
||||
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.world.mesh.SingleWorldMesh
|
||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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