minecraft: custom meshes for torch and fence

This commit is contained in:
Zack Buhman 2026-03-07 21:01:35 -06:00
parent 3469ccacfd
commit f890e4e550
15 changed files with 170 additions and 49 deletions

View File

@ -8,3 +8,11 @@ short index_buffer_configuration_offsets[] = {
768, 780, 798, 816, 840, 858, 882, 906,
936, 954, 978, 1002, 1032, 1056, 1086, 1116,
};
struct {
short offset;
short count;
} index_buffer_custom_offsets[] = {
{1152, 12}, // tallgrass.obj
{1164, 36}, // fence.obj
{1200, 36}, // torch.obj
};

Binary file not shown.

48
minecraft/gen/fence.obj Normal file
View File

@ -0,0 +1,48 @@
# Blender 5.0.0
# www.blender.org
o Cube
v 0.250000 1.000000 -0.250000
v 0.250000 -1.000000 -0.250000
v 0.250000 1.000000 0.250000
v 0.250000 -1.000000 0.250000
v -0.250000 1.000000 -0.250000
v -0.250000 -1.000000 -0.250000
v -0.250000 1.000000 0.250000
v -0.250000 -1.000000 0.250000
vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vt 0.250000 1.250000
vt 0.500000 1.000000
vt 0.500000 1.250000
vt 0.250050 0.000100
vt 0.500000 0.999900
vt 0.250050 0.999900
vt 0.500000 0.000100
vt 0.749950 0.999900
vt 0.250000 0.000000
vt 0.500000 -0.250000
vt 0.500000 0.000000
vt 0.000100 0.000100
vt 0.000100 0.999900
vt 0.749950 0.000100
vt 0.999900 0.999900
vt 0.250000 1.000000
vt 0.250000 -0.250000
vt 0.999900 0.000100
s 0
f 5/1/1 3/2/1 1/3/1
f 3/4/2 8/5/2 4/6/2
f 7/7/3 6/8/3 8/5/3
f 2/9/4 8/10/4 6/11/4
f 1/12/5 4/6/5 2/13/5
f 5/14/6 2/15/6 6/8/6
f 5/1/1 7/16/1 3/2/1
f 3/4/2 7/7/2 8/5/2
f 7/7/3 5/14/3 6/8/3
f 2/9/4 4/17/4 8/10/4
f 1/12/5 3/4/5 4/6/5
f 5/14/6 1/18/6 2/15/6

View File

@ -4,12 +4,15 @@ from pprint import pprint
from itertools import chain
from collections import defaultdict
import functools
import os
import mcregion
import vec3
import vertex_buffer
import data
FAST = "FAST" in os.environ
def wrap_n(nc, chunk_c):
if nc < 0:
nc = 15
@ -19,14 +22,24 @@ def wrap_n(nc, chunk_c):
chunk_c = chunk_c + 1
return nc, chunk_c
non_solid_blocks = {
custom_blocks = [
{ # "tallgrass" model
data.BlockID.TALL_GRASS,
data.BlockID.MUSHROOM_1,
data.BlockID.MUSHROOM_2,
data.BlockID.FLOWER,
data.BlockID.ROSE,
data.BlockID.SAPLING,
}
},
{ # "fence" model
data.BlockID.FENCE,
},
{ # "torch" model
data.BlockID.TORCH,
},
]
non_solid_blocks = set(chain.from_iterable(custom_blocks))
def neighbor_exists(level_table, chunk_x, chunk_z, nx, ny, nz):
if ny > 127 or ny < 0:
@ -67,6 +80,8 @@ def devoxelize_region(level_table, level_table_keys):
for chunk_x, chunk_z in level_table_keys:
for block_index in range(128 * 16 * 16):
yield from block_neighbors(level_table, chunk_x, chunk_z, block_index)
if FAST:
return
def build_level_table(level_table, mem, locations):
for location in locations:
@ -92,15 +107,6 @@ def build_block_configuration_table():
indices.extend(vertex_buffer.faces_by_normal[vertex_buffer.normals[j]])
yield indices
non_cube_blocks = {
data.BlockID.TALL_GRASS,
data.BlockID.MUSHROOM_1,
data.BlockID.MUSHROOM_2,
data.BlockID.FLOWER,
data.BlockID.ROSE,
data.BlockID.SAPLING,
}
def pack_instance_data(position, block_id):
packed = struct.pack("<hhhBB",
position[0], position[1], position[2],
@ -111,11 +117,18 @@ def pack_instance_data(position, block_id):
def build_block_instances(blocks):
by_configuration = defaultdict(list)
deferred_blocks = []
deferred_blocks = defaultdict(list)
def is_deferred_block(position, block_id):
for i, custom_block_types in enumerate(custom_blocks):
if block_id in custom_block_types:
deferred_blocks[i].append((position, block_id))
return True
return False
for position, block_id, normal_indices in blocks:
if block_id in non_cube_blocks:
deferred_blocks.append((position, block_id))
if is_deferred_block(position, block_id):
assert block_id in non_solid_blocks
continue
configuration = normal_indices_as_block_configuration(normal_indices)
by_configuration[configuration].append((position, block_id))
@ -133,7 +146,7 @@ def build_block_instances(blocks):
_blocks = by_configuration[configuration]
configuration_instance_count_offset.append((len(_blocks), offset))
for position, block_id in _blocks:
assert block_id not in non_cube_blocks, block_id
assert block_id not in non_solid_blocks, block_id
packed = pack_instance_data(position, block_id)
f.write(packed)
offset += len(packed)
@ -141,11 +154,11 @@ def build_block_instances(blocks):
######################################################################
# non-cubes
######################################################################
for custom_block_ix in range(len(custom_blocks)):
nc_offset = offset
nc_instance_count = 0
for position, block_id in deferred_blocks:
if block_id not in non_cube_blocks:
continue
for position, block_id in deferred_blocks[custom_block_ix]:
assert block_id in non_solid_blocks, block_id
packed = pack_instance_data(position, block_id)
f.write(packed)
offset += len(packed)

40
minecraft/gen/torch.obj Normal file
View File

@ -0,0 +1,40 @@
# Blender 5.0.0
# www.blender.org
o Cube
v 0.125000 0.250000 -0.125000
v 0.125000 -1.000000 -0.125000
v 0.125000 0.250000 0.125000
v 0.125000 -1.000000 0.125000
v -0.125000 0.250000 -0.125000
v -0.125000 -1.000000 -0.125000
v -0.125000 0.250000 0.125000
v -0.125000 -1.000000 0.125000
vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vt 0.531250 0.406250
vt 0.468750 0.468750
vt 0.468750 0.406250
vt 0.437500 0.375000
vt 0.562500 1.000000
vt 0.437500 1.000000
vt 0.562500 0.875000
vt 0.437500 0.875000
vt 0.531250 0.468750
vt 0.562500 0.375000
s 0
f 5/1/1 3/2/1 1/3/1
f 3/4/2 8/5/2 4/6/2
f 7/4/3 6/5/3 8/6/3
f 2/7/4 8/6/4 6/8/4
f 1/4/5 4/5/5 2/6/5
f 5/4/6 2/5/6 6/6/6
f 5/1/1 7/9/1 3/2/1
f 3/4/2 7/10/2 8/5/2
f 7/4/3 5/10/3 6/5/3
f 2/7/4 4/5/4 8/6/4
f 1/4/5 3/10/5 4/5/5
f 5/4/6 1/10/6 2/5/6

View File

@ -13,7 +13,7 @@ normals = [
(1.0, 0.0, 0.0),
]
def build_configuration_index_buffers(f, faces_by_normal):
def build_configuration_index_buffers(f, faces_by_normal, index_buffer):
assert(set(normals) == set(faces_by_normal.keys()))
offset = 0
@ -27,6 +27,7 @@ def build_configuration_index_buffers(f, faces_by_normal):
indices = faces_by_normal[normal]
for index in indices:
f.write(struct.pack("<B", index))
index_buffer.append(index)
offset += 1
for i, offset in enumerate(configuration_offsets):
@ -43,25 +44,35 @@ def write_indices(f, index_buffer, start, count):
for i in range(count):
f.write(struct.pack("<B", index_buffer[start + i]))
def write_custom_obj(f, vertex_buffer, index_buffer, index_lookup, path):
index_start = len(index_buffer)
state = obj.parse_obj_from_filename(path)
obj_state.append_triangles(state, vertex_buffer, index_buffer, index_lookup)
index_count = len(index_buffer) - index_start
write_indices(f, index_buffer, index_start, index_count)
print(f"{index_start}, {index_count}, // {path}")
def main():
cube_index_buffer = []
cube_index_lookup = {}
vertex_buffer = []
index_buffer = []
index_lookup = {}
cube_state = obj.parse_obj_from_filename("cube.obj")
obj_state.append_triangles(cube_state, vertex_buffer, index_buffer, index_lookup)
cube_faces_by_normal = obj_state.build_faces_by_normal(vertex_buffer, index_buffer)
tallgrass_index_start = len(index_buffer)
tallgrass_state = obj.parse_obj_from_filename("tallgrass.obj")
obj_state.append_triangles(tallgrass_state, vertex_buffer, index_buffer, index_lookup)
tallgrass_index_count = len(index_buffer) - tallgrass_index_start
print(tallgrass_index_start, tallgrass_index_count)
obj_state.append_triangles(cube_state, vertex_buffer, cube_index_buffer, cube_index_lookup)
cube_faces_by_normal = obj_state.build_faces_by_normal(vertex_buffer, cube_index_buffer)
with open("../configuration.idx", "wb") as f:
build_configuration_index_buffers(f, cube_faces_by_normal)
write_indices(f, index_buffer, tallgrass_index_start, tallgrass_index_count)
build_configuration_index_buffers(f, cube_faces_by_normal, index_buffer)
index_lookup = {}
write_custom_obj(f, vertex_buffer, index_buffer, index_lookup, "tallgrass.obj")
index_lookup = {}
write_custom_obj(f, vertex_buffer, index_buffer, index_lookup, "fence.obj")
index_lookup = {}
write_custom_obj(f, vertex_buffer, index_buffer, index_lookup, "torch.obj")
with open("../per_vertex.vtx", "wb") as f:
build_vertex_buffer(f, vertex_buffer)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -49,7 +49,8 @@ static unsigned int per_vertex_buffer;
static const int vertex_size = 8;
static const int per_vertex_size = (3 + 3 + 2) * 2;
static const int instance_cfg_length = 64 + 1;
static const int custom_block_types = 3;
static const int instance_cfg_length = 64 + custom_block_types;
struct instance_cfg {
struct region_instance {
@ -327,13 +328,13 @@ void draw()
}
//////////////////////////////////////////////////////////////////////
// non-cube blocks
// custom blocks
//////////////////////////////////////////////////////////////////////
{
int element_count = 6 * 2;
const void * indices = (void *)((ptrdiff_t)1152);
int instance_count = instance_cfg[region_index].cfg[64].instance_count;
int base_instance = instance_cfg[region_index].cfg[64].offset / vertex_size; // index into region.0.0.instance.vtx
for (int i = 0; i < custom_block_types; i++) {
int element_count = index_buffer_custom_offsets[i].count;
const void * indices = (void *)((ptrdiff_t)index_buffer_custom_offsets[i].offset);
int instance_count = instance_cfg[region_index].cfg[64 + i].instance_count;
int base_instance = instance_cfg[region_index].cfg[64 + i].offset / vertex_size; // index into region.0.0.instance.vtx
if (instance_count == 0)
continue;
glDrawElementsInstancedBaseInstance(GL_TRIANGLES, element_count, GL_UNSIGNED_BYTE, indices, instance_count, base_instance);