I've been trying to make a Roblox Mesh 1.0 exporter, and I'm nearly there, but I have encountered one problem that's causing a lot of annoying lighting issues: the float values for the Normals are not as I expected at first.
For comparison, the custom exporter that inspired me to make this is an anim8or plugin, and when I export a mesh from that, the normals are lit pretty well.
I did also notice that importing an obj into anim8or, exporting it back into an obj, importing that back into blender, and then running the python code produces near identical results.
Here is the code, I hope it helps give some context.
import math
import bmesh
import bpy
from bpy import context
def triangulate_object(obj):
me = obj.data
bm = bmesh.new()
bm.from_mesh(me)
bmesh.ops.triangulate(bm, faces=bm.faces[:])
bm.to_mesh(me)
bm.free()
def FixNumber(number):
return str("{:.9f}".format(math.ceil(float('%.9g' % number) * 1000000000) / 1000000000)).rstrip('0').rstrip('.')
bpy.ops.object.mode_set(mode='OBJECT')
filename = "traffic2.mesh"
objects = context.scene.objects
numFaces = 0
iterator = 0
Output = ""
arr = []
for shape in objects:
if (shape.type == "MESH"):
triangulate_object(shape)
data = shape.data.polygons
tMatrix = shape.matrix_world
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
pointx, pointz, pointy = shape.matrix_basis @ shape.data.vertices[vert_idx].co
pointx = FixNumber(pointx)
pointy = FixNumber(pointy)
pointz = FixNumber(-pointz)
normal_local = shape.data.vertices[vert_idx].normal
normalx, normaly, normalz = normal_local
length = math.sqrt( normalx**2 + normaly**2 + normalz**2 )
normalx = FixNumber(normalx / length)
normaly = FixNumber(normaly / length)
normalz = FixNumber(normalz / length)
uvx, uvy = shape.data.uv_layers.active.data[loop_idx].uv
uvx = FixNumber(uvx)
uvy = FixNumber(uvy)
arr.append(f"[{pointx}, {pointy}, {pointz}][{normalx}, {normaly}, {normalz}][{uvx}, {uvy}, 0]")
if (iterator % 3 == 0):
print(iterator)
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)
What I do know, is that anim8or is giving the obj some "Custom Split Normals", as what blender tells me. However all my efforts trying to change the Normal values in blender on the original model using modifiers have failed.
To elaborate on the Roblox mesh format, it's quite simple.
version 1.00
TriangleCount
[VertexX, VertexY, VertexZ][NormalX, NormalY, NormalZ][UVX, UVY, unused]
The last line gets repeated for every Triangle
The Mesh 1.0 format does not support any kind of materials, or nodes. It only supports vertices, normals, and uvs.
Here is an archive of the anim8or script in question, and instructions on how to install it.
I want to be able to recreate these anim8or Normal values in python automatically, and then have it export those, but I'm not entirely sure what to do here.