Skip to content

Instantly share code, notes, and snippets.

@Talon1024
Created May 28, 2023 07:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Talon1024/636a82cae21da1ace3452f619de6f2eb to your computer and use it in GitHub Desktop.
Save Talon1024/636a82cae21da1ace3452f619de6f2eb to your computer and use it in GitHub Desktop.
Blender script - export mesh to vertex/index buffers (for Rust)
from collections import namedtuple
from itertools import zip_longest
import bpy
# Copied from https://docs.python.org/3/library/itertools.html#itertools-recipes
# Used for grouping triangle vertex indices
def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
"Collect data into non-overlapping fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, fillvalue='x') --> ABC DEF Gxx
# grouper('ABCDEFG', 3, incomplete='strict') --> ABC DEF ValueError
# grouper('ABCDEFG', 3, incomplete='ignore') --> ABC DEF
args = [iter(iterable)] * n
if incomplete == 'fill':
return zip_longest(*args, fillvalue=fillvalue)
if incomplete == 'strict':
return zip(*args, strict=True)
if incomplete == 'ignore':
return zip(*args)
else:
raise ValueError('Expected fill, strict, or ignore')
output_vertices = "pub const VERTICES: [Vertex; {count}] = [\n{vertices}\n];"
output_indices = "pub const INDICES: [u32; {count}] = [\n{indices}\n];"
output_vertex = """Vertex {{
position: Vec3 {{ x: {position.x:.4f}, y: {position.y:.4f}, z: {position.z:.4f} }},
tex_coords: Vec2 {{ x: {tex_coords.x:.4f}, y: {tex_coords.y:.4f} }},
}}"""
ob = bpy.context.active_object
obm = ob.to_mesh()
obm.transform(ob.matrix_world)
obm.calc_loop_triangles()
BufferVertex = namedtuple("BufferVertex", "position tex_coords")
looped_vertices = {}
indices = []
for loopt in obm.loop_triangles:
for loop in loopt.loops:
loop = obm.loops[loop]
pos = obm.vertices[loop.vertex_index].co.copy().freeze()
uv = obm.uv_layers.active.uv[loop.index].vector.copy()
uv.y = 1 - uv.y
uv.freeze()
bv = BufferVertex(pos, uv)
looped_index = looped_vertices.setdefault(bv, len(looped_vertices))
indices.append(looped_index)
vertices = sorted(looped_vertices.keys(), key=looped_vertices.get)
with open("/tmp/data", "w") as dataf:
dataf.write("// The following data was auto-generated "
"by Blender " + bpy.app.version_string + "\n\n")
dataf.write(
output_vertices.format(
count=len(vertices),
vertices=",\n".join(map(\
lambda v: output_vertex.format(**v._asdict()), \
vertices))
)
)
dataf.write("\n\n// ============================\n\n")
dataf.write(
output_indices.format(
count=len(indices),
indices=",\n".join(\
map(", ".join, \
grouper(map(str, indices), 3, incomplete="strict"))
)
)
)
ob.to_mesh_clear()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment