Blender 2.8 exporter script

From Legacy Roblox Wiki
Jump to navigationJump to search

The process of using this mesh on Roblox is no longer relevant, as there is no known way to upload it. If you would like to have some details on how these meshes were once used with roblox.com, and how you could use them today, check here

Script

bl_info = {
	"name": "Roblox Mesh 1.0 (.mesh)",
	"author": "Nukley",
	"version": (0, 1),
	"blender": (2, 80, 0),
	"location": "File > Export",
	"description": "Save a Roblox Mesh 1.0 File",
	"category": "Import-Export",
}

import math
import bpy
import bmesh
from bpy_extras.io_utils import ExportHelper

def triangulate_object(obj):
	me = obj.data
	bm = bmesh.new()
	bm.from_mesh(me)
	bmesh.ops.triangulate(bm, faces=bm.faces[:])
	bmesh.ops.split_edges(bm, edges=bm.edges)
	bm.to_mesh(me)
	bm.free()
	
def FixNumber(number):
	rounded = math.ceil(float("%.6g" % number) * 1000000) / 1000000
	return "{:.6f}".format(rounded).rstrip('0').rstrip('.')

def do_export(filename):
	bpy.ops.object.mode_set(mode='OBJECT')
	objects = bpy.context.scene.objects
	numFaces = 0
	iterator = 0
	arr = []
	for shape in objects:
		if (shape.type == "MESH"):
			triangulate_object(shape)
			vMatrix = shape.matrix_world
			nMatrix = vMatrix.to_3x3().inverted().transposed()
			data = shape.data.polygons
			numFaces = numFaces + sum([(len(p.vertices) - 2) for p in data])

			for face in data:
				for vert_idx, loop_idx in zip(reversed(face.vertices), reversed(face.loop_indices)):
					iterator = iterator + 1

					p = shape.matrix_basis @ shape.data.vertices[vert_idx].co
					n = nMatrix @ shape.data.vertices[vert_idx].normal
					l = math.sqrt( n[0]**2 + n[2]**2 + n[1]**2 )
					u = shape.data.uv_layers.active.data[loop_idx].uv

					arr.append(f"[{FixNumber(p[0])}, {FixNumber(p[2])}, {FixNumber(-p[1])}]"
							f"[{FixNumber(n[0] / l)}, {FixNumber(n[2] / l)}, {FixNumber(-n[1] / l)}]"
							f"[{FixNumber(u[0])}, {FixNumber(u[1])}, 0]")

					if (iterator % 3 == 0):
						arr.insert(iterator-2, arr.pop(iterator-1))

	open(filename, "w").write(f"version 1.00\n{numFaces}\n")
	for triangle in arr:
		open(filename, "a").write(triangle)

class RbxExporter(bpy.types.Operator, ExportHelper):
	bl_idname = 'export.mesh'
	bl_label = 'Export RBXMesh'
	filename_ext = ".mesh"

	def execute(self, context):
		do_export(self.filepath)
		return {'FINISHED'}

	def invoke(self, context, event):
		wm = context.window_manager
		wm.fileselect_add(self)
		return {'RUNNING_MODAL'}
		
def menu_func(self, context):
	self.layout.operator(RbxExporter.bl_idname, text="Roblox Mesh (.mesh)");

def register():
	bpy.utils.register_class(RbxExporter)
	bpy.types.TOPBAR_MT_file_export.append(menu_func)

def unregister():
	bpy.utils.unregister_class(RbxExporter)
	bpy.types.TOPBAR_MT_file_export.remove(menu_func)