mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-27 12:14:40 +01:00
Less omissions in mesh emission
- Cannibalize shade separated vertex consumer to function as the mesh emitter for baked model buffering - Create one MeshEmitter per chunk RenderType to allow more coherency during multi block buffering - MeshEmitters own BufferBuilders, and the buffering functions call #begin on the mesh emitters directly - Each time the emitter sees a quad with a different shade flag than the previous run of quads, it emits a mesh and begins again - Finally, the buffering functions call #end on the mesh emitters to emit trailing meshes and clear transient state - Add diffuse debug mode - Order indirect draws by mesh index first - Remove non-shade separated option from buffering utilities because it allows you to opt in to incorrect behaviour - Remove TessellatedModel - Document mesh ordering contract in Model
This commit is contained in:
parent
183ea1f0f8
commit
96eb5ea47c
12 changed files with 246 additions and 387 deletions
|
@ -7,6 +7,16 @@ import org.joml.Vector4fc;
|
|||
import com.jozufozu.flywheel.api.material.Material;
|
||||
|
||||
public interface Model {
|
||||
/**
|
||||
* Get a list of all meshes in this model.
|
||||
*
|
||||
* <p>The contents of the returned list will be queried, but never modified.</p>
|
||||
*
|
||||
* <p>Meshes will be rendered in the order they appear in this list, though
|
||||
* no render order guarantees are made for meshes between different models.</p>
|
||||
*
|
||||
* @return A list of meshes.
|
||||
*/
|
||||
List<ConfiguredMesh> meshes();
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,6 +33,7 @@ import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
|||
|
||||
public class IndirectCullingGroup<I extends Instance> {
|
||||
private static final Comparator<IndirectDraw> DRAW_COMPARATOR = Comparator.comparing(IndirectDraw::stage)
|
||||
.thenComparing(IndirectDraw::indexOfMeshInModel)
|
||||
.thenComparing(IndirectDraw::material, MaterialRenderState.COMPARATOR);
|
||||
|
||||
private static final int DRAW_BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT;
|
||||
|
@ -179,12 +180,15 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||
instancer.index = instancers.size();
|
||||
instancers.add(instancer);
|
||||
|
||||
for (var entry : model.meshes()) {
|
||||
MeshPool.PooledMesh mesh = meshPool.alloc(entry.mesh());
|
||||
var draw = new IndirectDraw(instancer, entry.material(), mesh, stage);
|
||||
indirectDraws.add(draw);
|
||||
instancer.addDraw(draw);
|
||||
}
|
||||
List<Model.ConfiguredMesh> meshes = model.meshes();
|
||||
for (int i = 0; i < meshes.size(); i++) {
|
||||
var entry = meshes.get(i);
|
||||
|
||||
MeshPool.PooledMesh mesh = meshPool.alloc(entry.mesh());
|
||||
var draw = new IndirectDraw(instancer, entry.material(), mesh, stage, i);
|
||||
indirectDraws.add(draw);
|
||||
instancer.addDraw(draw);
|
||||
}
|
||||
|
||||
needsDrawSort = true;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ public class IndirectDraw {
|
|||
private final Material material;
|
||||
private final MeshPool.PooledMesh mesh;
|
||||
private final RenderStage stage;
|
||||
private final int indexOfMeshInModel;
|
||||
|
||||
private final int materialVertexIndex;
|
||||
private final int materialFragmentIndex;
|
||||
|
@ -20,11 +21,12 @@ public class IndirectDraw {
|
|||
private final int packedMaterialProperties;
|
||||
private boolean deleted;
|
||||
|
||||
public IndirectDraw(IndirectInstancer<?> model, Material material, MeshPool.PooledMesh mesh, RenderStage stage) {
|
||||
public IndirectDraw(IndirectInstancer<?> model, Material material, MeshPool.PooledMesh mesh, RenderStage stage, int indexOfMeshInModel) {
|
||||
this.model = model;
|
||||
this.material = material;
|
||||
this.mesh = mesh;
|
||||
this.stage = stage;
|
||||
this.indexOfMeshInModel = indexOfMeshInModel;
|
||||
|
||||
mesh.acquire();
|
||||
|
||||
|
@ -50,6 +52,10 @@ public class IndirectDraw {
|
|||
return stage;
|
||||
}
|
||||
|
||||
public int indexOfMeshInModel() {
|
||||
return indexOfMeshInModel;
|
||||
}
|
||||
|
||||
public void write(long ptr) {
|
||||
MemoryUtil.memPutInt(ptr, mesh.indexCount()); // count
|
||||
MemoryUtil.memPutInt(ptr + 4, 0); // instanceCount - to be set by the apply shader
|
||||
|
|
|
@ -7,5 +7,6 @@ public enum DebugMode {
|
|||
LIGHT_LEVEL,
|
||||
LIGHT_COLOR,
|
||||
OVERLAY,
|
||||
DIFFUSE,
|
||||
LIGHT_VOLUME,
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
import net.minecraft.client.renderer.ItemBlockRenderTypes;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
@ -41,7 +39,7 @@ final class BakedModelBufferer {
|
|||
poseStack = objects.identityPoseStack;
|
||||
}
|
||||
RandomSource random = objects.random;
|
||||
BufferBuilder[] buffers = objects.shadedBuffers;
|
||||
var consumers = objects.emitters;
|
||||
|
||||
modelData = model.getModelData(renderWorld, BlockPos.ZERO, state, modelData);
|
||||
random.setSeed(42L);
|
||||
|
@ -49,64 +47,18 @@ final class BakedModelBufferer {
|
|||
|
||||
for (RenderType renderType : renderTypes) {
|
||||
int layerIndex = renderType.getChunkLayerId();
|
||||
var consumer = consumers[layerIndex];
|
||||
|
||||
BufferBuilder buffer = buffers[layerIndex];
|
||||
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
consumer.begin(resultConsumer);
|
||||
|
||||
poseStack.pushPose();
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, buffer, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, consumer, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
poseStack.popPose();
|
||||
|
||||
RenderedBuffer data = buffer.endOrDiscardIfEmpty();
|
||||
if (data != null) {
|
||||
resultConsumer.accept(renderType, data);
|
||||
data.release();
|
||||
}
|
||||
consumer.end();
|
||||
}
|
||||
}
|
||||
|
||||
public static void bufferSingleShadeSeparated(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ShadeSeparatedResultConsumer resultConsumer) {
|
||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||
if (poseStack == null) {
|
||||
poseStack = objects.identityPoseStack;
|
||||
}
|
||||
RandomSource random = objects.random;
|
||||
ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper;
|
||||
BufferBuilder[] shadedBuffers = objects.shadedBuffers;
|
||||
BufferBuilder[] unshadedBuffers = objects.unshadedBuffers;
|
||||
|
||||
modelData = model.getModelData(renderWorld, BlockPos.ZERO, state, modelData);
|
||||
random.setSeed(42L);
|
||||
ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData);
|
||||
|
||||
for (RenderType renderType : renderTypes) {
|
||||
int layerIndex = renderType.getChunkLayerId();
|
||||
|
||||
BufferBuilder shadedBuffer = shadedBuffers[layerIndex];
|
||||
BufferBuilder unshadedBuffer = unshadedBuffers[layerIndex];
|
||||
shadeSeparatingWrapper.prepare(shadedBuffer, unshadedBuffer);
|
||||
shadedBuffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
unshadedBuffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
|
||||
poseStack.pushPose();
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, shadeSeparatingWrapper, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
poseStack.popPose();
|
||||
|
||||
RenderedBuffer shadedData = shadedBuffer.endOrDiscardIfEmpty();
|
||||
if (shadedData != null) {
|
||||
resultConsumer.accept(renderType, true, shadedData);
|
||||
shadedData.release();
|
||||
}
|
||||
RenderedBuffer unshadedData = unshadedBuffer.endOrDiscardIfEmpty();
|
||||
if (unshadedData != null) {
|
||||
resultConsumer.accept(renderType, false, unshadedData);
|
||||
unshadedData.release();
|
||||
}
|
||||
}
|
||||
|
||||
shadeSeparatingWrapper.clear();
|
||||
}
|
||||
|
||||
public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ResultConsumer resultConsumer) {
|
||||
if (state.getRenderShape() != RenderShape.MODEL) {
|
||||
return;
|
||||
|
@ -115,14 +67,6 @@ final class BakedModelBufferer {
|
|||
bufferSingle(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer);
|
||||
}
|
||||
|
||||
public static void bufferBlockShadeSeparated(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ShadeSeparatedResultConsumer resultConsumer) {
|
||||
if (state.getRenderShape() != RenderShape.MODEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
bufferSingleShadeSeparated(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer);
|
||||
}
|
||||
|
||||
public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Function<BlockPos, ModelData> modelDataLookup, boolean renderFluids, ResultConsumer resultConsumer) {
|
||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||
if (poseStack == null) {
|
||||
|
@ -131,9 +75,10 @@ final class BakedModelBufferer {
|
|||
RandomSource random = objects.random;
|
||||
TransformingVertexConsumer transformingWrapper = objects.transformingWrapper;
|
||||
|
||||
BufferBuilder[] buffers = objects.shadedBuffers;
|
||||
for (BufferBuilder buffer : buffers) {
|
||||
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
var emitters = objects.emitters;
|
||||
|
||||
for (var emitter : emitters) {
|
||||
emitter.begin(resultConsumer);
|
||||
}
|
||||
|
||||
ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer();
|
||||
|
@ -145,89 +90,12 @@ final class BakedModelBufferer {
|
|||
|
||||
if (renderFluids) {
|
||||
FluidState fluidState = state.getFluidState();
|
||||
|
||||
|
||||
if (!fluidState.isEmpty()) {
|
||||
RenderType layer = ItemBlockRenderTypes.getRenderLayer(fluidState);
|
||||
int layerIndex = layer.getChunkLayerId();
|
||||
|
||||
transformingWrapper.prepare(buffers[layerIndex], poseStack);
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF));
|
||||
renderDispatcher.renderLiquid(pos, renderWorld, transformingWrapper, state, fluidState);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
if (state.getRenderShape() == RenderShape.MODEL) {
|
||||
long seed = state.getSeed(pos);
|
||||
BakedModel model = renderDispatcher.getBlockModel(state);
|
||||
ModelData modelData = modelDataLookup.apply(pos);
|
||||
modelData = model.getModelData(renderWorld, pos, state, modelData);
|
||||
random.setSeed(seed);
|
||||
ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData);
|
||||
|
||||
for (RenderType renderType : renderTypes) {
|
||||
int layerIndex = renderType.getChunkLayerId();
|
||||
|
||||
BufferBuilder buffer = buffers[layerIndex];
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, buffer, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModelBlockRenderer.clearCache();
|
||||
|
||||
transformingWrapper.clear();
|
||||
|
||||
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
|
||||
RenderType renderType = CHUNK_LAYERS[layerIndex];
|
||||
BufferBuilder buffer = buffers[layerIndex];
|
||||
RenderedBuffer data = buffer.endOrDiscardIfEmpty();
|
||||
if (data != null) {
|
||||
resultConsumer.accept(renderType, data);
|
||||
data.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void bufferMultiBlockShadeSeparated(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Function<BlockPos, ModelData> modelDataLookup, boolean renderFluids, ShadeSeparatedResultConsumer resultConsumer) {
|
||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||
if (poseStack == null) {
|
||||
poseStack = objects.identityPoseStack;
|
||||
}
|
||||
RandomSource random = objects.random;
|
||||
ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper;
|
||||
TransformingVertexConsumer transformingWrapper = objects.transformingWrapper;
|
||||
|
||||
BufferBuilder[] shadedBuffers = objects.shadedBuffers;
|
||||
BufferBuilder[] unshadedBuffers = objects.unshadedBuffers;
|
||||
for (BufferBuilder buffer : shadedBuffers) {
|
||||
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
}
|
||||
for (BufferBuilder buffer : unshadedBuffers) {
|
||||
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
}
|
||||
|
||||
ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer();
|
||||
ModelBlockRenderer.enableCaching();
|
||||
|
||||
while (posIterator.hasNext()) {
|
||||
BlockPos pos = posIterator.next();
|
||||
BlockState state = renderWorld.getBlockState(pos);
|
||||
|
||||
if (renderFluids) {
|
||||
FluidState fluidState = state.getFluidState();
|
||||
|
||||
if (!fluidState.isEmpty()) {
|
||||
RenderType layer = ItemBlockRenderTypes.getRenderLayer(fluidState);
|
||||
int layerIndex = layer.getChunkLayerId();
|
||||
|
||||
transformingWrapper.prepare(shadedBuffers[layerIndex], poseStack);
|
||||
transformingWrapper.prepare(emitters[layerIndex], poseStack);
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF));
|
||||
|
@ -247,11 +115,9 @@ final class BakedModelBufferer {
|
|||
for (RenderType renderType : renderTypes) {
|
||||
int layerIndex = renderType.getChunkLayerId();
|
||||
|
||||
shadeSeparatingWrapper.prepare(shadedBuffers[layerIndex], unshadedBuffers[layerIndex]);
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, shadeSeparatingWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, emitters[layerIndex], true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
|
@ -259,31 +125,14 @@ final class BakedModelBufferer {
|
|||
|
||||
ModelBlockRenderer.clearCache();
|
||||
|
||||
shadeSeparatingWrapper.clear();
|
||||
transformingWrapper.clear();
|
||||
|
||||
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
|
||||
RenderType renderType = CHUNK_LAYERS[layerIndex];
|
||||
BufferBuilder shadedBuffer = shadedBuffers[layerIndex];
|
||||
BufferBuilder unshadedBuffer = unshadedBuffers[layerIndex];
|
||||
RenderedBuffer shadedData = shadedBuffer.endOrDiscardIfEmpty();
|
||||
if (shadedData != null) {
|
||||
resultConsumer.accept(renderType, true, shadedData);
|
||||
shadedData.release();
|
||||
}
|
||||
RenderedBuffer unshadedData = unshadedBuffer.endOrDiscardIfEmpty();
|
||||
if (unshadedData != null) {
|
||||
resultConsumer.accept(renderType, false, unshadedData);
|
||||
unshadedData.release();
|
||||
}
|
||||
for (var emitter : emitters) {
|
||||
emitter.end();
|
||||
}
|
||||
|
||||
transformingWrapper.clear();
|
||||
}
|
||||
|
||||
public interface ResultConsumer {
|
||||
void accept(RenderType renderType, RenderedBuffer data);
|
||||
}
|
||||
|
||||
public interface ShadeSeparatedResultConsumer {
|
||||
void accept(RenderType renderType, boolean shaded, RenderedBuffer data);
|
||||
}
|
||||
|
||||
|
@ -291,17 +140,16 @@ final class BakedModelBufferer {
|
|||
public final PoseStack identityPoseStack = new PoseStack();
|
||||
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
||||
|
||||
public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer();
|
||||
public final TransformingVertexConsumer transformingWrapper = new TransformingVertexConsumer();
|
||||
|
||||
public final BufferBuilder[] shadedBuffers = new BufferBuilder[CHUNK_LAYER_AMOUNT];
|
||||
public final BufferBuilder[] unshadedBuffers = new BufferBuilder[CHUNK_LAYER_AMOUNT];
|
||||
public final MeshEmitter[] emitters = new MeshEmitter[CHUNK_LAYER_AMOUNT];
|
||||
|
||||
{
|
||||
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
|
||||
int initialSize = CHUNK_LAYERS[layerIndex].bufferSize();
|
||||
shadedBuffers[layerIndex] = new BufferBuilder(initialSize);
|
||||
unshadedBuffers[layerIndex] = new BufferBuilder(initialSize);
|
||||
var renderType = CHUNK_LAYERS[layerIndex];
|
||||
// FIXME: We leak the memory owned by the BufferBuilder here.
|
||||
var buffer = new BufferBuilder(renderType.bufferSize());
|
||||
emitters[layerIndex] = new MeshEmitter(buffer, renderType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.jozufozu.flywheel.lib.model.baked;
|
|||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
|
@ -9,8 +11,8 @@ import com.jozufozu.flywheel.api.vertex.VertexView;
|
|||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer;
|
||||
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ShadeSeparatedResultConsumer;
|
||||
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
|
@ -23,11 +25,15 @@ import net.minecraftforge.client.model.data.ModelData;
|
|||
|
||||
public class BakedModelBuilder {
|
||||
private final BakedModel bakedModel;
|
||||
@Nullable
|
||||
private BlockAndTintGetter renderWorld;
|
||||
@Nullable
|
||||
private BlockState blockState;
|
||||
@Nullable
|
||||
private PoseStack poseStack;
|
||||
@Nullable
|
||||
private ModelData modelData;
|
||||
private boolean shadeSeparated = true;
|
||||
@Nullable
|
||||
private BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||
|
||||
public BakedModelBuilder(BakedModel bakedModel) {
|
||||
|
@ -54,17 +60,12 @@ public class BakedModelBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public BakedModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BakedModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||
this.materialFunc = materialFunc;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TessellatedModel build() {
|
||||
public SimpleModel build() {
|
||||
if (renderWorld == null) {
|
||||
renderWorld = VirtualEmptyBlockGetter.INSTANCE;
|
||||
}
|
||||
|
@ -80,30 +81,17 @@ public class BakedModelBuilder {
|
|||
|
||||
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||
|
||||
if (shadeSeparated) {
|
||||
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
||||
Material material = materialFunc.apply(renderType, shaded);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer);
|
||||
} else {
|
||||
ResultConsumer resultConsumer = (renderType, data) -> {
|
||||
Material material = materialFunc.apply(renderType, true);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer);
|
||||
}
|
||||
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
||||
Material material = materialFunc.apply(renderType, shaded);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer);
|
||||
|
||||
return new TessellatedModel(out.build(), shadeSeparated);
|
||||
return new SimpleModel(out.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.jozufozu.flywheel.lib.model.baked;
|
|||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
|
@ -9,8 +11,8 @@ import com.jozufozu.flywheel.api.vertex.VertexView;
|
|||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer;
|
||||
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ShadeSeparatedResultConsumer;
|
||||
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
|
@ -21,10 +23,13 @@ import net.minecraftforge.client.model.data.ModelData;
|
|||
|
||||
public class BlockModelBuilder {
|
||||
private final BlockState state;
|
||||
@Nullable
|
||||
private BlockAndTintGetter renderWorld;
|
||||
@Nullable
|
||||
private PoseStack poseStack;
|
||||
@Nullable
|
||||
private ModelData modelData;
|
||||
private boolean shadeSeparated = true;
|
||||
@Nullable
|
||||
private BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||
|
||||
public BlockModelBuilder(BlockState state) {
|
||||
|
@ -46,17 +51,12 @@ public class BlockModelBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public BlockModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||
this.materialFunc = materialFunc;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TessellatedModel build() {
|
||||
public SimpleModel build() {
|
||||
if (renderWorld == null) {
|
||||
renderWorld = VirtualEmptyBlockGetter.INSTANCE;
|
||||
}
|
||||
|
@ -69,30 +69,17 @@ public class BlockModelBuilder {
|
|||
|
||||
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||
|
||||
if (shadeSeparated) {
|
||||
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
||||
Material material = materialFunc.apply(renderType, shaded);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer);
|
||||
} else {
|
||||
ResultConsumer resultConsumer = (renderType, data) -> {
|
||||
Material material = materialFunc.apply(renderType, true);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer);
|
||||
}
|
||||
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
||||
Material material = materialFunc.apply(renderType, shaded);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer);
|
||||
|
||||
return new TessellatedModel(out.build(), shadeSeparated);
|
||||
return new SimpleModel(out.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
|
||||
class MeshEmitter implements VertexConsumer {
|
||||
private final BufferBuilder bufferBuilder;
|
||||
private final RenderType renderType;
|
||||
private boolean lastQuadWasShaded;
|
||||
private boolean seenFirstQuad;
|
||||
@Nullable
|
||||
private BakedModelBufferer.ResultConsumer resultConsumer;
|
||||
|
||||
MeshEmitter(BufferBuilder bufferBuilder, RenderType renderType) {
|
||||
this.bufferBuilder = bufferBuilder;
|
||||
this.renderType = renderType;
|
||||
}
|
||||
|
||||
public void begin(BakedModelBufferer.ResultConsumer resultConsumer) {
|
||||
this.resultConsumer = resultConsumer;
|
||||
|
||||
begin();
|
||||
}
|
||||
|
||||
public void end() {
|
||||
emit();
|
||||
seenFirstQuad = false;
|
||||
resultConsumer = null;
|
||||
}
|
||||
|
||||
private void begin() {
|
||||
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
}
|
||||
|
||||
private void emit() {
|
||||
var renderedBuffer = bufferBuilder.endOrDiscardIfEmpty();
|
||||
|
||||
if (renderedBuffer != null) {
|
||||
if (resultConsumer != null) {
|
||||
resultConsumer.accept(renderType, lastQuadWasShaded, renderedBuffer);
|
||||
}
|
||||
renderedBuffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
private void observeQuadAndEmitIfNecessary(BakedQuad quad) {
|
||||
if (seenFirstQuad && lastQuadWasShaded != quad.isShade()) {
|
||||
emit();
|
||||
begin();
|
||||
}
|
||||
|
||||
seenFirstQuad = true;
|
||||
lastQuadWasShaded = quad.isShade();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) {
|
||||
observeQuadAndEmitIfNecessary(quad);
|
||||
|
||||
bufferBuilder.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad quad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) {
|
||||
observeQuadAndEmitIfNecessary(quad);
|
||||
|
||||
bufferBuilder.putBulkData(matrixEntry, quad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer vertex(double x, double y, double z) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer color(int red, int green, int blue, int alpha) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv(float u, float v) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer overlayCoords(int u, int v) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv2(int u, int v) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer normal(float x, float y, float z) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVertex() {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultColor(int red, int green, int blue, int alpha) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetDefaultColor() {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ package com.jozufozu.flywheel.lib.model.baked;
|
|||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
|
@ -10,8 +12,8 @@ import com.jozufozu.flywheel.api.vertex.VertexView;
|
|||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer;
|
||||
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ShadeSeparatedResultConsumer;
|
||||
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
|
@ -23,10 +25,12 @@ import net.minecraftforge.client.model.data.ModelData;
|
|||
public class MultiBlockModelBuilder {
|
||||
private final BlockAndTintGetter renderWorld;
|
||||
private final Iterable<BlockPos> positions;
|
||||
@Nullable
|
||||
private PoseStack poseStack;
|
||||
@Nullable
|
||||
private Function<BlockPos, ModelData> modelDataLookup;
|
||||
private boolean renderFluids = false;
|
||||
private boolean shadeSeparated = true;
|
||||
@Nullable
|
||||
private BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||
|
||||
public MultiBlockModelBuilder(BlockAndTintGetter renderWorld, Iterable<BlockPos> positions) {
|
||||
|
@ -49,17 +53,12 @@ public class MultiBlockModelBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public MultiBlockModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MultiBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||
this.materialFunc = materialFunc;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TessellatedModel build() {
|
||||
public SimpleModel build() {
|
||||
if (modelDataLookup == null) {
|
||||
modelDataLookup = pos -> ModelData.EMPTY;
|
||||
}
|
||||
|
@ -69,30 +68,17 @@ public class MultiBlockModelBuilder {
|
|||
|
||||
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||
|
||||
if (shadeSeparated) {
|
||||
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
||||
Material material = materialFunc.apply(renderType, shaded);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferMultiBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, positions.iterator(), renderWorld, poseStack, modelDataLookup, renderFluids, resultConsumer);
|
||||
} else {
|
||||
ResultConsumer resultConsumer = (renderType, data) -> {
|
||||
Material material = materialFunc.apply(renderType, true);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), renderWorld, poseStack, modelDataLookup, renderFluids, resultConsumer);
|
||||
}
|
||||
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
||||
Material material = materialFunc.apply(renderType, shaded);
|
||||
if (material != null) {
|
||||
VertexView vertexView = new NoOverlayVertexView();
|
||||
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), renderWorld, poseStack, modelDataLookup, renderFluids, resultConsumer);
|
||||
|
||||
return new TessellatedModel(out.build(), shadeSeparated);
|
||||
return new SimpleModel(out.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
|
||||
class ShadeSeparatingVertexConsumer implements VertexConsumer {
|
||||
private VertexConsumer shadedConsumer;
|
||||
private VertexConsumer unshadedConsumer;
|
||||
|
||||
public void prepare(VertexConsumer shadedConsumer, VertexConsumer unshadedConsumer) {
|
||||
this.shadedConsumer = shadedConsumer;
|
||||
this.unshadedConsumer = unshadedConsumer;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
shadedConsumer = null;
|
||||
unshadedConsumer = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) {
|
||||
if (quad.isShade()) {
|
||||
shadedConsumer.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor);
|
||||
} else {
|
||||
unshadedConsumer.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad bakedQuad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) {
|
||||
if (bakedQuad.isShade()) {
|
||||
shadedConsumer.putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor);
|
||||
} else {
|
||||
unshadedConsumer.putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer vertex(double x, double y, double z) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer color(int red, int green, int blue, int alpha) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv(float u, float v) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer overlayCoords(int u, int v) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv2(int u, int v) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer normal(float x, float y, float z) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVertex() {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultColor(int red, int green, int blue, int alpha) {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetDefaultColor() {
|
||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||
|
||||
public class TessellatedModel extends SimpleModel {
|
||||
private final boolean shadeSeparated;
|
||||
|
||||
public TessellatedModel(ImmutableList<ConfiguredMesh> meshes, boolean shadeSeparated) {
|
||||
super(meshes);
|
||||
this.shadeSeparated = shadeSeparated;
|
||||
}
|
||||
|
||||
public boolean isShadeSeparated() {
|
||||
return shadeSeparated;
|
||||
}
|
||||
}
|
|
@ -25,6 +25,18 @@ flat in uint _flw_instanceID;
|
|||
|
||||
out vec4 _flw_outputColor;
|
||||
|
||||
float _flw_diffuseFactor() {
|
||||
if (flw_material.diffuse) {
|
||||
if (flw_constantAmbientLight == 1u) {
|
||||
return diffuseNether(flw_vertexNormal);
|
||||
} else {
|
||||
return diffuse(flw_vertexNormal);
|
||||
}
|
||||
} else {
|
||||
return 1.;
|
||||
}
|
||||
}
|
||||
|
||||
void _flw_main() {
|
||||
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
|
||||
flw_fragColor = flw_vertexColor * flw_sampleColor;
|
||||
|
@ -49,15 +61,8 @@ void _flw_main() {
|
|||
|
||||
vec4 color = flw_fragColor;
|
||||
|
||||
if (flw_material.diffuse) {
|
||||
float diffuseFactor;
|
||||
if (flw_constantAmbientLight == 1u) {
|
||||
diffuseFactor = diffuseNether(flw_vertexNormal);
|
||||
} else {
|
||||
diffuseFactor = diffuse(flw_vertexNormal);
|
||||
}
|
||||
color.rgb *= diffuseFactor;
|
||||
}
|
||||
float diffuseFactor = _flw_diffuseFactor();
|
||||
color.rgb *= diffuseFactor;
|
||||
|
||||
if (flw_material.useOverlay) {
|
||||
vec4 overlayColor = texelFetch(flw_overlayTex, flw_fragOverlay, 0);
|
||||
|
@ -90,8 +95,11 @@ void _flw_main() {
|
|||
case 5u:
|
||||
color = vec4(flw_fragOverlay / 16., 0., 1.);
|
||||
break;
|
||||
#ifdef _FLW_EMBEDDED
|
||||
case 6u:
|
||||
color = vec4(vec3(diffuseFactor), 1.);
|
||||
break;
|
||||
#ifdef _FLW_EMBEDDED
|
||||
case 7u:
|
||||
color = vec4(_flw_lightVolumeCoord, 1.);
|
||||
break;
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue