Skip to content
This repository was archived by the owner on Mar 22, 2026. It is now read-only.

Commit 67240d7

Browse files
committed
修复模型闪烁问题
1 parent 0d3217b commit 67240d7

33 files changed

+546
-884
lines changed

blazerod/example/ball_block/src/main/java/top/fifthlight/blazerod/example/ballblock/BallBlockMod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ private void loadModel() {
5151
var loader = new ModelLoader();
5252
BALL_SCENE = loader.loadModel(model);
5353
BALL_SCENE.increaseReferenceCount();
54-
BALL_INSTANCE = new ModelInstance(BALL_SCENE, ModelBufferManager.INSTANCE.getEntry(BALL_SCENE));
54+
BALL_INSTANCE = new ModelInstance(BALL_SCENE);
5555
BALL_INSTANCE.increaseReferenceCount();
5656
var rootTransformNodeIndex = BALL_SCENE.getRootTransformNodeIndex();
5757
var rootTransformNode = (RenderNode.Transform) BALL_SCENE.getNodes().get(rootTransformNodeIndex);

blazerod/render/src/main/kotlin/top/fifthlight/blazerod/debug/ResourceCountTracker.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class ResourceCountTracker {
1313

1414
fun decrease(identifier: Identifier) {
1515
refCounts.compute(identifier) { key, value ->
16-
check(value != null) { "Decrease zero count: $key" }
16+
// Crash at here!
17+
check(value != null && value > 0) { "Decrease null or zero count: $key" }
1718
value - 1
1819
}
1920
}

blazerod/render/src/main/kotlin/top/fifthlight/blazerod/model/ModelBufferManager.kt

Lines changed: 0 additions & 71 deletions
This file was deleted.

blazerod/render/src/main/kotlin/top/fifthlight/blazerod/model/ModelInstance.kt

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,40 +11,30 @@ import org.joml.Vector3f
1111
import top.fifthlight.blazerod.BlazeRod
1212
import top.fifthlight.blazerod.model.data.ModelMatricesBuffer
1313
import top.fifthlight.blazerod.model.data.RenderSkinBuffer
14-
import top.fifthlight.blazerod.model.data.RenderTargetBuffer
14+
import top.fifthlight.blazerod.model.data.MorphTargetBuffer
1515
import top.fifthlight.blazerod.util.AbstractRefCount
16+
import top.fifthlight.blazerod.util.CowBuffer
17+
import top.fifthlight.blazerod.util.CowBufferList
18+
import top.fifthlight.blazerod.util.copy
1619
import top.fifthlight.blazerod.util.mapToArray
1720
import top.fifthlight.blazerod.util.mapToArrayIndexed
1821
import java.util.function.Consumer
1922

20-
class ModelInstance(
21-
val scene: RenderScene,
22-
bufferEntry: ModelBufferManager.BufferEntry,
23-
) : AbstractRefCount() {
23+
class ModelInstance(val scene: RenderScene) : AbstractRefCount() {
2424
companion object {
2525
private val TYPE_ID = Identifier.of("blazerod", "model_instance")
2626
}
2727

2828
override val typeId: Identifier
2929
get() = TYPE_ID
3030

31-
val modelData = ModelData(
32-
scene = scene,
33-
bufferEntry = bufferEntry,
34-
)
31+
val modelData = ModelData(scene)
3532

3633
init {
3734
scene.increaseReferenceCount()
3835
}
3936

40-
class ModelData(
41-
scene: RenderScene,
42-
private val bufferEntry: ModelBufferManager.BufferEntry,
43-
) : AutoCloseable {
44-
init {
45-
bufferEntry.increaseReferenceCount()
46-
}
47-
37+
class ModelData(scene: RenderScene) : AutoCloseable {
4838
val defaultTransforms = scene.transformNodeIndices.mapToArray { nodeIndex ->
4939
val node = scene.nodes[nodeIndex] as RenderNode.Transform
5040
node.defaultTransform?.clone()
@@ -56,46 +46,41 @@ class ModelInstance(
5646

5747
val transformsDirty = Array(scene.transformNodeIndices.size) { true }
5848

59-
val modelMatricesBuffer = ModelMatricesBuffer(scene, bufferEntry.modelMatricesBuffers.allocateSlot()).also {
60-
it.clear()
49+
val modelMatricesBuffer = run {
50+
val buffer = ModelMatricesBuffer(scene)
51+
buffer.clear()
52+
CowBuffer.acquire(buffer).also { it.increaseReferenceCount() }
6153
}
6254

63-
val skinBuffers = scene.skins.mapToArrayIndexed { index, skin ->
64-
RenderSkinBuffer(skin, bufferEntry.skinBuffers[index].allocateSlot()).also {
65-
it.clear()
66-
}
55+
val skinBuffers = scene.skins.mapIndexed { index, skin ->
56+
val skinBuffer = RenderSkinBuffer(skin)
57+
skinBuffer.clear()
58+
CowBuffer.acquire(skinBuffer).also { it.increaseReferenceCount() }
6759
}
6860

69-
val targetBuffers = scene.morphedPrimitiveNodeIndices.mapToArrayIndexed { index, nodeIndex ->
61+
val targetBuffers = scene.morphedPrimitiveNodeIndices.mapIndexed { index, nodeIndex ->
7062
val node = scene.nodes[nodeIndex] as RenderNode.Primitive
7163
val primitive = node.primitive
7264
val targets = primitive.targets!!
73-
val targetBuffers = RenderTargetBuffer(
74-
targets = targets,
75-
weightsSlot = bufferEntry.morphWeightBuffers[index].allocateSlot(),
76-
indicesSlot = bufferEntry.morphIndicesBuffers[index].allocateSlot(),
77-
)
65+
val targetBuffers = MorphTargetBuffer(targets)
7866
for (targetGroup in primitive.targetGroups) {
79-
fun processGroup(index: Int?, channel: RenderTargetBuffer.WeightChannel, weight: Float) =
67+
fun processGroup(index: Int?, channel: MorphTargetBuffer.WeightChannel, weight: Float) =
8068
index?.let {
8169
channel[index] = weight
8270
}
8371
processGroup(targetGroup.position, targetBuffers.positionChannel, targetGroup.weight)
8472
processGroup(targetGroup.color, targetBuffers.colorChannel, targetGroup.weight)
8573
processGroup(targetGroup.texCoord, targetBuffers.texCoordChannel, targetGroup.weight)
8674
}
87-
targetBuffers
75+
CowBuffer.acquire(targetBuffers).also { it.increaseReferenceCount() }
8876
}
8977

90-
val cameraTransforms = scene.cameras.mapToArray { CameraTransform(it.camera) }
78+
val cameraTransforms = scene.cameras.map { CameraTransform(it.camera) }
9179

9280
override fun close() {
93-
// release slots
94-
modelMatricesBuffer.close()
95-
skinBuffers.forEach { it.close() }
96-
targetBuffers.forEach { it.close() }
97-
// release underlying slot buffer
98-
bufferEntry.decreaseReferenceCount()
81+
modelMatricesBuffer.decreaseReferenceCount()
82+
skinBuffers.forEach { it.decreaseReferenceCount() }
83+
targetBuffers.forEach { it.decreaseReferenceCount() }
9984
}
10085
}
10186

@@ -190,9 +175,11 @@ class ModelInstance(
190175
val weightsIndex =
191176
requireNotNull(node.morphedPrimitiveIndex) { "Node $nodeIndex don't have target? Check model loader" }
192177
val weights = modelData.targetBuffers[weightsIndex]
193-
group.position?.let { weights.positionChannel[it] = weight }
194-
group.color?.let { weights.colorChannel[it] = weight }
195-
group.texCoord?.let { weights.texCoordChannel[it] = weight }
178+
weights.edit {
179+
group.position?.let { positionChannel[it] = weight }
180+
group.color?.let { colorChannel[it] = weight }
181+
group.texCoord?.let { texCoordChannel[it] = weight }
182+
}
196183
}
197184

198185
private val updateMatrixStack = Matrix4fStack(BlazeRod.MAX_TRANSFORM_DEPTH)
@@ -210,13 +197,29 @@ class ModelInstance(
210197
}
211198

212199
fun render(modelViewMatrix: Matrix4fc, light: Int) {
213-
scene.render(this, modelViewMatrix, light)
200+
// Upload indices don't change the actual data
201+
modelData.targetBuffers.forEach { it.content.uploadIndices() }
202+
scene.render(
203+
modelViewMatrix = modelViewMatrix,
204+
light = light,
205+
modelMatricesBuffer = modelData.modelMatricesBuffer.content,
206+
skinBuffer = CowBufferList(modelData.skinBuffers),
207+
morphTargetBuffer = CowBufferList(modelData.targetBuffers),
208+
)
214209
}
215210

216-
fun schedule(modelViewMatrix: Matrix4fc, light: Int) = RenderTask.Instance.acquire(
211+
fun schedule(modelViewMatrix: Matrix4fc, light: Int): RenderTask = RenderTask.acquire(
217212
instance = this,
218213
modelViewMatrix = modelViewMatrix,
219214
light = light,
215+
modelMatricesBuffer = modelData.modelMatricesBuffer.copy(),
216+
skinBuffer = modelData.skinBuffers.copy(),
217+
morphTargetBuffer = modelData.targetBuffers.copy().also { buffer ->
218+
// Upload indices don't change the actual data
219+
buffer.forEach {
220+
it.content.uploadIndices()
221+
}
222+
},
220223
)
221224

222225
override fun onClosed() {

blazerod/render/src/main/kotlin/top/fifthlight/blazerod/model/ModelLoader.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,7 @@ class ModelLoader {
259259
check(accessor.type == Accessor.AccessorType.SCALAR)
260260
if (accessor.componentType == Accessor.ComponentType.UNSIGNED_BYTE) {
261261
// We need some workaround, because there is just no index type of BYTE
262-
val byteBuffer = ByteBuffer.allocateDirect(2 * accessor.count)
263-
byteBuffer.order(ByteOrder.nativeOrder())
262+
val byteBuffer = ByteBuffer.allocateDirect(2 * accessor.count).order(ByteOrder.nativeOrder())
264263
accessor.read { input ->
265264
val index = input.get().toUByte()
266265
byteBuffer.putShort(index.toShort())
@@ -313,7 +312,7 @@ class ModelLoader {
313312
buffer.flip()
314313
val targetBuffer = if (!buffer.hasRemaining()) {
315314
// No targets, but we can't create an empty buffer, so let's create a dummy one
316-
ByteBuffer.allocateDirect(textureFormat.pixelSize())
315+
ByteBuffer.allocateDirect(textureFormat.pixelSize()).order(ByteOrder.nativeOrder())
317316
} else {
318317
buffer
319318
}

blazerod/render/src/main/kotlin/top/fifthlight/blazerod/model/RenderMaterial.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ abstract class RenderMaterial<Desc : RenderMaterial.Descriptor> : AbstractRefCou
111111
withShaderDefine("MORPHED")
112112
withShaderDefine("MAX_ENABLED_MORPH_TARGETS", BlazeRod.MAX_ENABLED_MORPH_TARGETS)
113113
withUniform("MorphData", UniformType.UNIFORM_BUFFER)
114-
withUniform("MorphModelIndices", UniformType.UNIFORM_BUFFER)
115114
withUniform("MorphPositionData", UniformType.TEXEL_BUFFER, TextureFormatExt.RGB32F)
116115
withUniform("MorphColorData", UniformType.TEXEL_BUFFER, TextureFormatExt.RGBA32F)
117116
withUniform("MorphTexCoordData", UniformType.TEXEL_BUFFER, TextureFormatExt.RG32F)

blazerod/render/src/main/kotlin/top/fifthlight/blazerod/model/RenderNode.kt

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package top.fifthlight.blazerod.model
22

3-
import net.minecraft.client.gl.RenderPassImpl
43
import net.minecraft.client.render.RenderLayer
54
import net.minecraft.client.render.VertexConsumerProvider
65
import net.minecraft.client.util.math.MatrixStack
76
import net.minecraft.util.Colors
87
import net.minecraft.util.Identifier
98
import org.joml.*
9+
import top.fifthlight.blazerod.model.data.ModelMatricesBuffer
10+
import top.fifthlight.blazerod.model.data.MorphTargetBuffer
11+
import top.fifthlight.blazerod.model.data.RenderSkinBuffer
1012
import top.fifthlight.blazerod.util.AbstractRefCount
11-
import top.fifthlight.blazerod.util.SlottedGpuBuffer
1213
import top.fifthlight.blazerod.util.drawBox
1314
import top.fifthlight.blazerod.util.iteratorOf
1415

@@ -93,46 +94,36 @@ sealed class RenderNode : AbstractRefCount(), Iterable<RenderNode> {
9394
return
9495
}
9596
if (skinIndex == null) {
96-
instance.modelData.modelMatricesBuffer.setMatrix(primitiveIndex, matrixStack)
97+
instance.modelData.modelMatricesBuffer.edit {
98+
setMatrix(primitiveIndex, matrixStack)
99+
}
97100
}
98101
}
99102

100-
fun render(instance: ModelInstance, modelViewMatrix: Matrix4fc, light: Int) {
101-
val skinBuffer = skinIndex?.let { instance.modelData.skinBuffers[it] }
102-
val targetBuffer = morphedPrimitiveIndex?.let { instance.modelData.targetBuffers[it] }
103-
primitive.render(instance, primitiveIndex, modelViewMatrix, light, skinBuffer, targetBuffer)
103+
fun render(
104+
scene: RenderScene,
105+
modelViewMatrix: Matrix4fc,
106+
light: Int,
107+
modelMatricesBuffer: ModelMatricesBuffer,
108+
skinBuffer: List<RenderSkinBuffer>?,
109+
morphTargetBuffer: List<MorphTargetBuffer>?,
110+
) {
111+
primitive.render(
112+
scene = scene,
113+
primitiveIndex = primitiveIndex,
114+
viewModelMatrix = modelViewMatrix,
115+
light = light,
116+
modelMatricesBuffer = modelMatricesBuffer,
117+
skinBuffer = skinIndex?.let {
118+
(skinBuffer ?: error("Has skin but no skin buffer"))[it]
119+
},
120+
targetBuffer = morphedPrimitiveIndex?.let {
121+
(morphTargetBuffer ?: error("Has morph targets but no morph target buffer"))[it]
122+
}
123+
)
104124
}
105125

106-
fun renderInstanced(tasks: List<RenderTask.Instance>) {
107-
if (RenderPassImpl.IS_DEVELOPMENT) {
108-
val firstInstance = tasks.first().instance
109-
skinIndex?.let {
110-
val firstBufferSlot = firstInstance.modelData.skinBuffers[it].slot
111-
require(firstBufferSlot is SlottedGpuBuffer.Slotted)
112-
val buffer = firstBufferSlot.buffer
113-
for (task in tasks) {
114-
val bufferSlot = task.instance.modelData.skinBuffers[it].slot
115-
require(bufferSlot is SlottedGpuBuffer.Slotted)
116-
require(bufferSlot.buffer == buffer)
117-
}
118-
}
119-
morphedPrimitiveIndex?.let {
120-
val firstWeightsBufferSlot = firstInstance.modelData.targetBuffers[it].weightsSlot
121-
val firstIndicesBufferSlot = firstInstance.modelData.targetBuffers[it].indicesSlot
122-
require(firstWeightsBufferSlot is SlottedGpuBuffer.Slotted)
123-
require(firstIndicesBufferSlot is SlottedGpuBuffer.Slotted)
124-
val weightsBuffer = firstWeightsBufferSlot.buffer
125-
val indicesBuffer = firstIndicesBufferSlot.buffer
126-
for (task in tasks) {
127-
val weightsBufferSlot = task.instance.modelData.targetBuffers[it].weightsSlot
128-
val indicesBufferSlot = task.instance.modelData.targetBuffers[it].indicesSlot
129-
require(weightsBufferSlot is SlottedGpuBuffer.Slotted)
130-
require(indicesBufferSlot is SlottedGpuBuffer.Slotted)
131-
require(weightsBufferSlot.buffer == weightsBuffer)
132-
require(indicesBufferSlot.buffer == indicesBuffer)
133-
}
134-
}
135-
}
126+
fun renderInstanced(tasks: List<RenderTask>) {
136127
primitive.renderInstanced(tasks, this)
137128
}
138129

@@ -276,11 +267,13 @@ sealed class RenderNode : AbstractRefCount(), Iterable<RenderNode> {
276267

277268
val matrix = cacheMatrix
278269
matrix.set(matrixStack)
270+
val skin = instance.scene.skins[skinIndex]
279271
val skinBuffer = instance.modelData.skinBuffers[skinIndex]
280-
281-
val inverseMatrix = skinBuffer.skin.inverseBindMatrices?.get(jointIndex)
282-
inverseMatrix?.let { matrix.mul(it) }
283-
skinBuffer.setMatrix(jointIndex, matrix)
272+
val inverseMatrix = skin.inverseBindMatrices?.get(jointIndex)
273+
skinBuffer.edit {
274+
inverseMatrix?.let { matrix.mul(it) }
275+
setMatrix(jointIndex, matrix)
276+
}
284277
}
285278

286279
override fun iterator() = iteratorOf<RenderNode>()

0 commit comments

Comments
 (0)