If you’re using Blender, this script may be useful for you to perfectly realign (probably multiple) meshes the way they were originally were placed in Blender rather than eyeballing it all the time.~~~
Select a single object in Blender (merge objects if you export multiple at the same time, the Studio mesh importer does the same as far as I know anyway), then run this script in Blender:
import bpy
export_scale = .01 # configure your fbx export scale in Blender here
import_scale = .01
outp_script = """
local sel = game.Selection:Get();
assert(#sel == 2);
local meshPart = sel[1];
local anchorPart = sel[2];
if (anchorPart:IsA("MeshPart")) then
meshPart, anchorPart = anchorPart, meshPart;
end
meshPart.CFrame = anchorPart.CFrame * CFrame.new({:.20f}, {:.20f}, {:.20f});
"""
scale = export_scale / import_scale
for obj in bpy.data.objects:
if obj.select and obj.type == 'MESH':
dims = obj.dimensions
mesh = obj.data
vertices_world = [(obj.matrix_world * vert.co) for vert in mesh.vertices]
offx = (min([vec.x for vec in vertices_world]) + dims.x * .5) * scale
offy = (min([vec.y for vec in vertices_world]) + dims.y * .5) * scale
offz = (min([vec.z for vec in vertices_world]) + dims.z * .5) * scale
# note: blender has the Z-axis pointing up
bpy.context.window_manager.clipboard = outp_script.format(offx, offz, -offy)
After doing this, it will copy a Lua script to your system clipboard. In Studio, select both your MeshPart you want to align and another normal BasePart you want to base its alignment on. Then paste and run the Lua script in Studio’s command bar, which will move the selected MeshPart such that it is offset and rotated from the normal BasePart as it were in Blender from the world origin (this alignment BasePart is thus basically the Blender world origin).
If you align multiple MeshParts to the same BasePart this way, you get perfect alignment.
Bit of a messy workflow, but maybe it’s useful to someone else too ;).
The original (Python) script is only used in Blender, but that script outputs a Lua script to the system clipboard, which you can paste into Studio’s command bar to actually update the MeshPart CFrame. That generated script changes depending on the bounding box your objects have in Blender.
Just select what you want to be mesh, then right click and “export selection”. It will be an .obj file so use some program to export it to .fbx. Remember about 5000 poly limit.
The export scale is determined by this value during export:
Roblox sees 1 “blender unit” as 100 studs, which is the .01 fixed import scale.
This all assumes you do actually use the blender units (“None”).
Should note that I’ve figured the dimensions of the object used in the script are object-space, not world-space, so if you have applied either a rotation or scale object transformation (in object mode), you should apply those first before running the script. I’ll probably change the script itself later to compute a proper world-space AABB later on, but that could cause issues too with the positioning.
If anyone else still cares enough to use my technique for properly aligning meshes ( ), here’s an updated script to be used in Blender which computes the bounds properly.
import bpy
from mathutils import Vector
export_scale = .01 # configure your fbx export scale in Blender here
import_scale = .01 # do NOT edit this value, only the export_scale above!!!
outp_script = """
local sel = game.Selection:Get();
assert(#sel == 2);
local meshPart = sel[1];
local anchorPart = sel[2];
if (anchorPart:IsA("MeshPart")) then
meshPart, anchorPart = anchorPart, meshPart;
end
meshPart.CFrame = anchorPart.CFrame * CFrame.new({:.20f}, {:.20f}, {:.20f});
"""
scale = export_scale / import_scale
for obj in bpy.data.objects:
if obj.select and obj.type == 'MESH':
dims = obj.dimensions
mesh = obj.data
vertices_world = [(obj.matrix_world * vert.co) for vert in mesh.vertices]
# compute world space bounds of the selected object
minvec = Vector()
maxvec = Vector()
for axis in ['x', 'y', 'z']:
setattr(minvec, axis, min([getattr(vec, axis) for vec in vertices_world]) * scale)
setattr(maxvec, axis, max([getattr(vec, axis) for vec in vertices_world]) * scale)
offsetvec = (minvec + maxvec) * .5
# note: blender has the Z-axis pointing up
bpy.context.window_manager.clipboard = outp_script.format(offsetvec.x, offsetvec.z, -offsetvec.y)
I think the reason that uploading meshes is free is because too many things can mess up: flipped normals, missing textures, bad smoothing, etc. It would cost the dev too much to re-upload (I think it took me over a dozen tries just to get the mesh I was uploading to appear correctly). As for audio, it’s pretty safe to say that what you’re uploading is what you’re getting in-game. Also, I think they’re planning on making the payments for audio uploads tiered.