Skip to content

Commit b9e6d46

Browse files
committed
Material AO
1 parent f5b0bd4 commit b9e6d46

12 files changed

Lines changed: 100 additions & 27 deletions

File tree

common/src/api/java/dev/engine_room/flywheel/api/material/Material.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ public interface Material {
5555
*/
5656
CardinalLightingMode cardinalLightingMode();
5757

58+
/**
59+
* Whether this material should receive ambient occlusion from nearby chunk geometry.
60+
*
61+
* @return {@code true} if this material should receive ambient occlusion.
62+
*/
63+
default boolean ambientOcclusion() {
64+
return true;
65+
}
66+
5867
/**
5968
* Check for field-wise equality between this Material and another.
6069
*
@@ -81,6 +90,7 @@ default boolean equals(@Nullable Material other) {
8190
&& this.useOverlay() == other.useOverlay()
8291
&& this.useLight() == other.useLight()
8392
&& this.cardinalLightingMode() == other.cardinalLightingMode()
93+
&& this.ambientOcclusion() == other.ambientOcclusion()
8494
&& this.shaders().fragmentSource().equals(other.shaders().fragmentSource())
8595
&& this.shaders().vertexSource().equals(other.shaders().vertexSource())
8696
&& this.fog().source().equals(other.fog().source())

common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialEncoder.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public final class MaterialEncoder {
2121
private static final int USE_OVERLAY_LENGTH = 1;
2222
private static final int USE_LIGHT_LENGTH = 1;
2323
private static final int CARDINAL_LIGHTING_MODE_LENGTH = Mth.ceillog2(CardinalLightingMode.values().length);
24+
private static final int AMBIENT_OCCLUSION_LENGTH = 1;
2425

2526
// The bit offset of each property
2627
private static final int BLUR_OFFSET = 0;
@@ -33,6 +34,7 @@ public final class MaterialEncoder {
3334
private static final int USE_OVERLAY_OFFSET = WRITE_MASK_OFFSET + WRITE_MASK_LENGTH;
3435
private static final int USE_LIGHT_OFFSET = USE_OVERLAY_OFFSET + USE_OVERLAY_LENGTH;
3536
private static final int CARDINAL_LIGHTING_MODE_OFFSET = USE_LIGHT_OFFSET + USE_LIGHT_LENGTH;
37+
private static final int AMBIENT_OCCLUSION_OFFSET = CARDINAL_LIGHTING_MODE_OFFSET + CARDINAL_LIGHTING_MODE_LENGTH;
3638

3739
// The bit mask for each property
3840
private static final int BLUR_MASK = bitMask(BLUR_LENGTH, BLUR_OFFSET);
@@ -45,6 +47,7 @@ public final class MaterialEncoder {
4547
private static final int USE_OVERLAY_MASK = bitMask(USE_OVERLAY_LENGTH, USE_OVERLAY_OFFSET);
4648
private static final int USE_LIGHT_MASK = bitMask(USE_LIGHT_LENGTH, USE_LIGHT_OFFSET);
4749
private static final int CARDINAL_LIGHTING_MODE_MASK = bitMask(CARDINAL_LIGHTING_MODE_LENGTH, CARDINAL_LIGHTING_MODE_OFFSET);
50+
private static final int AMBIENT_OCCLUSION_MASK = bitMask(AMBIENT_OCCLUSION_LENGTH, AMBIENT_OCCLUSION_OFFSET);
4851

4952
private MaterialEncoder() {
5053
}
@@ -60,7 +63,7 @@ public static int packUberShader(Material material) {
6063
}
6164

6265
// Packed format:
63-
// cardinalLightingMode[2] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
66+
// ambientOcclusion[1] | cardinalLightingMode[2] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
6467
public static int packProperties(Material material) {
6568
int bits = 0;
6669

@@ -75,6 +78,7 @@ public static int packProperties(Material material) {
7578
if (material.useLight()) bits |= USE_LIGHT_MASK;
7679
bits |= (material.cardinalLightingMode()
7780
.ordinal() << CARDINAL_LIGHTING_MODE_OFFSET) & CARDINAL_LIGHTING_MODE_MASK;
81+
if (material.ambientOcclusion()) bits |= AMBIENT_OCCLUSION_MASK;
7882

7983
return bits;
8084
}

common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialRenderState.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ public static boolean materialEquals(Material lhs, Material rhs) {
188188
return true;
189189
}
190190

191-
// Not here because ubershader: useLight, useOverlay, diffuse, fog shader
191+
// Not here because ubershader: useLight, useOverlay, diffuse, fog shader, ambient occlusion
192192
// Everything in the comparator should be here.
193193
// @formatter:off
194194
return lhs.blur() == rhs.blur()

common/src/backend/resources/assets/flywheel/flywheel/internal/material.glsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ struct FlwMaterial {
3434
bool useOverlay;
3535
bool useLight;
3636
uint cardinalLightingMode;
37+
bool ambientOcclusion;
3738
};

common/src/backend/resources/assets/flywheel/flywheel/internal/packed_material.glsl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const uint _FLW_WRITE_MASK_LENGTH = 2u;
99
const uint _FLW_USE_OVERLAY_LENGTH = 1u;
1010
const uint _FLW_USE_LIGHT_LENGTH = 1u;
1111
const uint _FLW_CARDINAL_LIGHTING_MODE_LENGTH = 2u;
12+
const uint _FLW_AMBIENT_OCCLUSION_LENGTH = 1u;
1213

1314
// The bit offset of each property
1415
const uint _FLW_BLUR_OFFSET = 0u;
@@ -21,6 +22,7 @@ const uint _FLW_WRITE_MASK_OFFSET = _FLW_TRANSPARENCY_OFFSET + _FLW_TRANSPARENCY
2122
const uint _FLW_USE_OVERLAY_OFFSET = _FLW_WRITE_MASK_OFFSET + _FLW_WRITE_MASK_LENGTH;
2223
const uint _FLW_USE_LIGHT_OFFSET = _FLW_USE_OVERLAY_OFFSET + _FLW_USE_OVERLAY_LENGTH;
2324
const uint _FLW_CARDINAL_LIGHTING_MODE_OFFSET = _FLW_USE_LIGHT_OFFSET + _FLW_USE_LIGHT_LENGTH;
25+
const uint _FLW_AMBIENT_OCCLUSION_OFFSET = _FLW_CARDINAL_LIGHTING_MODE_OFFSET + _FLW_CARDINAL_LIGHTING_MODE_LENGTH;
2426

2527
// The bit mask for each property
2628
const uint _FLW_BLUR_MASK = ((1u << _FLW_BLUR_LENGTH) - 1u) << _FLW_BLUR_OFFSET;
@@ -33,9 +35,10 @@ const uint _FLW_WRITE_MASK_MASK = ((1u << _FLW_WRITE_MASK_LENGTH) - 1u) << _FLW_
3335
const uint _FLW_USE_OVERLAY_MASK = ((1u << _FLW_USE_OVERLAY_LENGTH) - 1u) << _FLW_USE_OVERLAY_OFFSET;
3436
const uint _FLW_USE_LIGHT_MASK = ((1u << _FLW_USE_LIGHT_LENGTH) - 1u) << _FLW_USE_LIGHT_OFFSET;
3537
const uint _FLW_CARDINAL_LIGHTING_MODE_MASK = ((1u << _FLW_CARDINAL_LIGHTING_MODE_LENGTH) - 1u) << _FLW_CARDINAL_LIGHTING_MODE_OFFSET;
38+
const uint _FLW_AMBIENT_OCCLUSION_MASK = ((1u << _FLW_AMBIENT_OCCLUSION_LENGTH) - 1u) << _FLW_AMBIENT_OCCLUSION_OFFSET;
3639

3740
// Packed format:
38-
// cardinalLightingMode[2] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
41+
// ambientOcclusion[1] | cardinalLightingMode[2] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
3942
void _flw_unpackMaterialProperties(uint p, out FlwMaterial m) {
4043
m.blur = (p & _FLW_BLUR_MASK) != 0u;
4144
m.mipmap = (p & _FLW_MIPMAP_MASK) != 0u;
@@ -47,6 +50,7 @@ void _flw_unpackMaterialProperties(uint p, out FlwMaterial m) {
4750
m.useOverlay = (p & _FLW_USE_OVERLAY_MASK) != 0u;
4851
m.useLight = (p & _FLW_USE_LIGHT_MASK) != 0u;
4952
m.cardinalLightingMode = (p & _FLW_CARDINAL_LIGHTING_MODE_MASK) >> _FLW_CARDINAL_LIGHTING_MODE_OFFSET;
53+
m.ambientOcclusion = (p & _FLW_AMBIENT_OCCLUSION_MASK) != 0;
5054
}
5155

5256
void _flw_unpackUint2x16(uint s, out uint hi, out uint lo) {

common/src/lib/java/dev/engine_room/flywheel/lib/material/SimpleMaterial.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public class SimpleMaterial implements Material {
3232
protected final boolean useLight;
3333
protected final CardinalLightingMode cardinalLightingMode;
3434

35+
protected final boolean ambientOcclusion;
36+
3537
protected SimpleMaterial(Builder builder) {
3638
shaders = builder.shaders();
3739
fog = builder.fog();
@@ -48,6 +50,7 @@ protected SimpleMaterial(Builder builder) {
4850
useOverlay = builder.useOverlay();
4951
useLight = builder.useLight();
5052
cardinalLightingMode = builder.cardinalLightingMode();
53+
ambientOcclusion = builder.ambientOcclusion();
5154
}
5255

5356
public static Builder builder() {
@@ -133,6 +136,11 @@ public CardinalLightingMode cardinalLightingMode() {
133136
return cardinalLightingMode;
134137
}
135138

139+
@Override
140+
public boolean ambientOcclusion() {
141+
return ambientOcclusion;
142+
}
143+
136144
public static class Builder implements Material {
137145
protected MaterialShaders shaders;
138146
protected FogShader fog;
@@ -153,6 +161,8 @@ public static class Builder implements Material {
153161
protected boolean useLight;
154162
protected CardinalLightingMode cardinalLightingMode;
155163

164+
protected boolean ambientOcclusion;
165+
156166
public Builder() {
157167
shaders = StandardMaterialShaders.DEFAULT;
158168
fog = FogShaders.LINEAR;
@@ -169,6 +179,7 @@ public Builder() {
169179
useOverlay = true;
170180
useLight = true;
171181
cardinalLightingMode = CardinalLightingMode.ENTITY;
182+
ambientOcclusion = true;
172183
}
173184

174185
public Builder(Material material) {
@@ -191,6 +202,7 @@ public Builder copyFrom(Material material) {
191202
useOverlay = material.useOverlay();
192203
useLight = material.useLight();
193204
cardinalLightingMode = material.cardinalLightingMode();
205+
ambientOcclusion = material.ambientOcclusion();
194206
return this;
195207
}
196208

@@ -355,5 +367,15 @@ public CardinalLightingMode cardinalLightingMode() {
355367
public SimpleMaterial build() {
356368
return new SimpleMaterial(this);
357369
}
370+
371+
public Builder ambientOcclusion(boolean ambientOcclusion) {
372+
this.ambientOcclusion = ambientOcclusion;
373+
return this;
374+
}
375+
376+
@Override
377+
public boolean ambientOcclusion() {
378+
return ambientOcclusion;
379+
}
358380
}
359381
}

common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelUtil.java

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import org.joml.Vector3f;
77
import org.joml.Vector4f;
88

9+
import dev.engine_room.flywheel.api.material.CardinalLightingMode;
910
import dev.engine_room.flywheel.api.material.Material;
1011
import dev.engine_room.flywheel.api.model.Mesh;
1112
import dev.engine_room.flywheel.api.model.Model;
1213
import dev.engine_room.flywheel.api.vertex.VertexList;
1314
import dev.engine_room.flywheel.lib.material.Materials;
15+
import dev.engine_room.flywheel.lib.material.SimpleMaterial;
1416
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
1517
import dev.engine_room.flywheel.lib.vertex.PosVertexView;
1618
import net.minecraft.client.renderer.RenderType;
@@ -19,6 +21,36 @@
1921
public final class ModelUtil {
2022
private static final float BOUNDING_SPHERE_EPSILON = 1e-4f;
2123

24+
private static final RenderType[] CHUNK_LAYERS = new RenderType[]{RenderType.solid(), RenderType.cutoutMipped(), RenderType.cutout(), RenderType.translucent(), RenderType.tripwire()};
25+
26+
// Array of chunk materials to make lookups easier.
27+
// Index by (renderTypeIdx * 4 + shaded * 2 + ambientOcclusion).
28+
private static final Material[] CHUNK_MATERIALS = new Material[20];
29+
30+
static {
31+
Material[] baseChunkMaterials = new Material[]{Materials.SOLID_BLOCK, Materials.CUTOUT_MIPPED_BLOCK, Materials.CUTOUT_BLOCK, Materials.TRANSLUCENT_BLOCK, Materials.TRIPWIRE_BLOCK,};
32+
for (int chunkLayerIdx = 0; chunkLayerIdx < CHUNK_LAYERS.length; chunkLayerIdx++) {
33+
int baseMaterialIdx = chunkLayerIdx * 4;
34+
Material baseChunkMaterial = baseChunkMaterials[chunkLayerIdx];
35+
36+
// shaded: false, ambientOcclusion: false
37+
CHUNK_MATERIALS[baseMaterialIdx] = SimpleMaterial.builderOf(baseChunkMaterial)
38+
.cardinalLightingMode(CardinalLightingMode.OFF)
39+
.ambientOcclusion(false)
40+
.build();
41+
// shaded: false, ambientOcclusion: true
42+
CHUNK_MATERIALS[baseMaterialIdx + 1] = SimpleMaterial.builderOf(baseChunkMaterial)
43+
.cardinalLightingMode(CardinalLightingMode.OFF)
44+
.build();
45+
// shaded: true, ambientOcclusion: false
46+
CHUNK_MATERIALS[baseMaterialIdx + 2] = SimpleMaterial.builderOf(baseChunkMaterial)
47+
.ambientOcclusion(false)
48+
.build();
49+
// shaded: true, ambientOcclusion: true
50+
CHUNK_MATERIALS[baseMaterialIdx + 3] = baseChunkMaterial;
51+
}
52+
}
53+
2254
private ModelUtil() {
2355
}
2456

@@ -29,27 +61,22 @@ public static Material getMaterial(RenderType chunkRenderType, boolean shaded) {
2961

3062
@Nullable
3163
public static Material getMaterial(RenderType chunkRenderType, boolean shaded, boolean ambientOcclusion) {
32-
if (chunkRenderType == RenderType.solid()) {
33-
return shaded ? Materials.SOLID_BLOCK : Materials.SOLID_UNSHADED_BLOCK;
34-
}
35-
if (chunkRenderType == RenderType.cutoutMipped()) {
36-
return shaded ? Materials.CUTOUT_MIPPED_BLOCK : Materials.CUTOUT_MIPPED_UNSHADED_BLOCK;
37-
}
38-
if (chunkRenderType == RenderType.cutout()) {
39-
return shaded ? Materials.CUTOUT_BLOCK : Materials.CUTOUT_UNSHADED_BLOCK;
40-
}
41-
if (chunkRenderType == RenderType.translucent()) {
42-
return shaded ? Materials.TRANSLUCENT_BLOCK : Materials.TRANSLUCENT_UNSHADED_BLOCK;
43-
}
44-
if (chunkRenderType == RenderType.tripwire()) {
45-
return shaded ? Materials.TRIPWIRE_BLOCK : Materials.TRIPWIRE_UNSHADED_BLOCK;
64+
for (int chunkLayerIdx = 0; chunkLayerIdx < CHUNK_LAYERS.length; ++chunkLayerIdx) {
65+
if (chunkRenderType == CHUNK_LAYERS[chunkLayerIdx]) {
66+
int shadedIdx = shaded ? 1 : 0;
67+
int ambientOcclusionIdx = ambientOcclusion ? 1 : 0;
68+
69+
int materialIdx = chunkLayerIdx * 4 + shadedIdx * 2 + ambientOcclusionIdx;
70+
71+
return CHUNK_MATERIALS[materialIdx];
72+
}
4673
}
4774
return null;
4875
}
4976

5077
@Nullable
5178
public static Material getItemMaterial(RenderType renderType) {
52-
var chunkMaterial = getMaterial(renderType, true);
79+
var chunkMaterial = getMaterial(renderType, true, false);
5380

5481
if (chunkMaterial != null) {
5582
return chunkMaterial;

common/src/lib/java/dev/engine_room/flywheel/lib/model/baked/BlockModelBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ public BlockModelBuilder materialFunc(@Nullable BiFunction<RenderType, Boolean,
5353
return this;
5454
}
5555

56+
public abstract SimpleModel build();
57+
5658
public BlockModelBuilder materialFunc(@Nullable BlockMaterialFunction materialFunc) {
5759
this.materialFunc = materialFunc;
5860
return this;
5961
}
60-
61-
public abstract SimpleModel build();
6262
}

common/src/lib/java/dev/engine_room/flywheel/lib/model/baked/MeshEmitter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import dev.engine_room.flywheel.api.model.Model;
1515

1616
class MeshEmitter {
17-
private static final int INITIAL_CAPACITY = 4;
17+
private static final int INITIAL_CAPACITY = 1;
1818

1919
private final BufferBuilderStack bufferBuilderStack;
2020

@@ -64,6 +64,7 @@ public void end(ImmutableList.Builder<Model.ConfiguredMesh> out) {
6464

6565
currentIndex = 0;
6666
numBufferBuildersPopulated = 0;
67+
blockMaterialFunction = null;
6768
}
6869

6970
public BufferBuilder getBuffer(Material material) {

common/src/lib/resources/assets/flywheel/flywheel/light/smooth.glsl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ void flw_shaderLight() {
33
if (flw_light(flw_vertexPos.xyz, flw_vertexNormal, light)) {
44
flw_fragLight = max(flw_fragLight, light.light);
55

6-
flw_fragColor.rgb *= light.ao;
6+
if (flw_material.ambientOcclusion) {
7+
flw_fragColor.rgb *= light.ao;
8+
}
79
}
810
}

0 commit comments

Comments
 (0)