Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ebeb0d262 | ||
|
|
8edfac9bfb | ||
|
|
1121b18fcb | ||
|
|
dcd8c3ea65 | ||
|
|
283a44aec5 |
@@ -3,3 +3,6 @@
|
|||||||
This is a Blender addon allowing you to export static meshes to the now-defunct ASE (ASCII Scene Export) format still in use in legacy programs like Unreal Tournament 2004.
|
This is a Blender addon allowing you to export static meshes to the now-defunct ASE (ASCII Scene Export) format still in use in legacy programs like Unreal Tournament 2004.
|
||||||
|
|
||||||
Check out [this video](https://www.youtube.com/watch?v=gpmBxCGHQjU) on how to install and use the addon.
|
Check out [this video](https://www.youtube.com/watch?v=gpmBxCGHQjU) on how to install and use the addon.
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
* https://wiki.beyondunreal.com/Legacy:ASE_File_Format
|
||||||
@@ -2,7 +2,7 @@ bl_info = {
|
|||||||
'name': 'ASCII Scene Export',
|
'name': 'ASCII Scene Export',
|
||||||
'description': 'Export ASE (ASCII Scene Export) files',
|
'description': 'Export ASE (ASCII Scene Export) files',
|
||||||
'author': 'Colin Basnett (Darklight Games)',
|
'author': 'Colin Basnett (Darklight Games)',
|
||||||
'version': (1, 0, 1),
|
'version': (1, 1, 0),
|
||||||
'blender': (2, 90, 0),
|
'blender': (2, 90, 0),
|
||||||
'location': 'File > Import-Export',
|
'location': 'File > Import-Export',
|
||||||
'warning': 'This add-on is under development.',
|
'warning': 'This add-on is under development.',
|
||||||
|
|||||||
@@ -26,11 +26,16 @@ def is_collision_name(name):
|
|||||||
return name.startswith('MCDCX_')
|
return name.startswith('MCDCX_')
|
||||||
|
|
||||||
|
|
||||||
|
class ASEUVLayer(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.texture_vertices = []
|
||||||
|
|
||||||
|
|
||||||
class ASEGeometryObject(object):
|
class ASEGeometryObject(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.name = ''
|
self.name = ''
|
||||||
self.vertices = []
|
self.vertices = []
|
||||||
self.texture_vertices = []
|
self.uv_layers = []
|
||||||
self.faces = []
|
self.faces = []
|
||||||
self.texture_vertex_faces = []
|
self.texture_vertex_faces = []
|
||||||
self.face_normals = []
|
self.face_normals = []
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ class ASEBuilder(object):
|
|||||||
if not geometry_object.is_collision and len(mesh_data.materials) == 0:
|
if not geometry_object.is_collision and len(mesh_data.materials) == 0:
|
||||||
raise ASEBuilderError(f'Mesh \'{obj.name}\' must have at least one material')
|
raise ASEBuilderError(f'Mesh \'{obj.name}\' must have at least one material')
|
||||||
|
|
||||||
geometry_object.vertex_offset += len(geometry_object.vertices)
|
|
||||||
vertex_transform = Matrix.Scale(options.scale, 4) @ Matrix.Rotation(math.pi, 4, 'Z') @ obj.matrix_world
|
vertex_transform = Matrix.Scale(options.scale, 4) @ Matrix.Rotation(math.pi, 4, 'Z') @ obj.matrix_world
|
||||||
for vertex_index, vertex in enumerate(mesh_data.vertices):
|
for vertex_index, vertex in enumerate(mesh_data.vertices):
|
||||||
geometry_object.vertices.append(vertex_transform @ vertex.co)
|
geometry_object.vertices.append(vertex_transform @ vertex.co)
|
||||||
@@ -69,6 +68,11 @@ class ASEBuilder(object):
|
|||||||
face.material_index = material_indices[loop_triangle.material_index]
|
face.material_index = material_indices[loop_triangle.material_index]
|
||||||
# The UT2K4 importer only accepts 32 smoothing groups. Anything past this completely mangles the
|
# The UT2K4 importer only accepts 32 smoothing groups. Anything past this completely mangles the
|
||||||
# smoothing groups and effectively makes the whole model use sharp-edge rendering.
|
# smoothing groups and effectively makes the whole model use sharp-edge rendering.
|
||||||
|
# The fix is to constrain the smoothing group between 0 and 31 by applying a modulo of 32 to the actual
|
||||||
|
# smoothing group index.
|
||||||
|
# This may result in bad calculated normals on export in rare cases. For example, if a face with a
|
||||||
|
# smoothing group of 3 is adjacent to a face with a smoothing group of 35 (35 % 32 == 3), those faces
|
||||||
|
# will be treated as part of the same smoothing group.
|
||||||
face.smoothing = (poly_groups[loop_triangle.polygon_index] - 1) % 32
|
face.smoothing = (poly_groups[loop_triangle.polygon_index] - 1) % 32
|
||||||
geometry_object.faces.append(face)
|
geometry_object.faces.append(face)
|
||||||
|
|
||||||
@@ -85,14 +89,15 @@ class ASEBuilder(object):
|
|||||||
face_normal.vertex_normals.append(vertex_normal)
|
face_normal.vertex_normals.append(vertex_normal)
|
||||||
geometry_object.face_normals.append(face_normal)
|
geometry_object.face_normals.append(face_normal)
|
||||||
|
|
||||||
uv_layer = mesh_data.uv_layers.active.data
|
|
||||||
|
|
||||||
# Texture Coordinates
|
|
||||||
geometry_object.texture_vertex_offset += len(geometry_object.texture_vertices)
|
|
||||||
if not geometry_object.is_collision:
|
if not geometry_object.is_collision:
|
||||||
|
# Texture Coordinates
|
||||||
|
for i, uv_layer_data in enumerate([x.data for x in mesh_data.uv_layers]):
|
||||||
|
if i >= len(geometry_object.uv_layers):
|
||||||
|
geometry_object.uv_layers.append(ASEUVLayer())
|
||||||
|
uv_layer = geometry_object.uv_layers[i]
|
||||||
for loop_index, loop in enumerate(mesh_data.loops):
|
for loop_index, loop in enumerate(mesh_data.loops):
|
||||||
u, v = uv_layer[loop_index].uv
|
u, v = uv_layer_data[loop_index].uv
|
||||||
geometry_object.texture_vertices.append((u, v, 0.0))
|
uv_layer.texture_vertices.append((u, v, 0.0))
|
||||||
|
|
||||||
# Texture Faces
|
# Texture Faces
|
||||||
if not geometry_object.is_collision:
|
if not geometry_object.is_collision:
|
||||||
@@ -103,6 +108,10 @@ class ASEBuilder(object):
|
|||||||
geometry_object.texture_vertex_offset + loop_triangle.loops[2]
|
geometry_object.texture_vertex_offset + loop_triangle.loops[2]
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# Update data offsets for next iteration
|
||||||
|
geometry_object.texture_vertex_offset = len(mesh_data.loops)
|
||||||
|
geometry_object.vertex_offset = len(geometry_object.vertices)
|
||||||
|
|
||||||
if len(ase.geometry_objects) == 0:
|
if len(ase.geometry_objects) == 0:
|
||||||
raise ASEBuilderError('At least one mesh object must be selected')
|
raise ASEBuilderError('At least one mesh object must be selected')
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class ASE_OT_ExportOperator(bpy.types.Operator, bpy_extras.io_utils.ExportHelper
|
|||||||
maxlen=255, # Max internal buffer length, longer would be hilighted.
|
maxlen=255, # Max internal buffer length, longer would be hilighted.
|
||||||
)
|
)
|
||||||
|
|
||||||
units = EnumProperty(
|
units: EnumProperty(
|
||||||
items=(('M', 'Meters', ''),
|
items=(('M', 'Meters', ''),
|
||||||
('U', 'Unreal', '')),
|
('U', 'Unreal', '')),
|
||||||
name='Units'
|
name='Units'
|
||||||
|
|||||||
Binary file not shown.
@@ -146,18 +146,20 @@ class ASEWriter(object):
|
|||||||
face_node.push_sub_command('MESH_MTLID').push_datum(face.material_index)
|
face_node.push_sub_command('MESH_MTLID').push_datum(face.material_index)
|
||||||
|
|
||||||
# Texture Coordinates
|
# Texture Coordinates
|
||||||
if len(geometry_object.texture_vertices) > 0:
|
for i, uv_layer in enumerate(geometry_object.uv_layers):
|
||||||
mesh_node.push_child('MESH_NUMTVERTEX').push_datum(len(geometry_object.texture_vertices))
|
parent_node = mesh_node if i == 0 else mesh_node.push_child('MESH_MAPPINGCHANNEL')
|
||||||
tvertlist_node = mesh_node.push_child('MESH_TVERTLIST')
|
if i > 0:
|
||||||
for tvert_index, tvert in enumerate(geometry_object.texture_vertices):
|
parent_node.push_datum(i + 1)
|
||||||
|
parent_node.push_child('MESH_NUMTVERTEX').push_datum(len(uv_layer.texture_vertices))
|
||||||
|
tvertlist_node = parent_node.push_child('MESH_TVERTLIST')
|
||||||
|
for tvert_index, tvert in enumerate(uv_layer.texture_vertices):
|
||||||
tvert_node = tvertlist_node.push_child('MESH_TVERT')
|
tvert_node = tvertlist_node.push_child('MESH_TVERT')
|
||||||
tvert_node.push_datum(tvert_index)
|
tvert_node.push_datum(tvert_index)
|
||||||
tvert_node.push_data(list(tvert))
|
tvert_node.push_data(list(tvert))
|
||||||
|
|
||||||
# Texture Faces
|
# Texture Faces
|
||||||
if len(geometry_object.texture_vertex_faces) > 0:
|
if len(geometry_object.texture_vertex_faces) > 0:
|
||||||
mesh_node.push_child('MESH_NUMTVFACES').push_datum(len(geometry_object.texture_vertex_faces))
|
parent_node.push_child('MESH_NUMTVFACES').push_datum(len(geometry_object.texture_vertex_faces))
|
||||||
texture_faces_node = mesh_node.push_child('MESH_TFACELIST')
|
texture_faces_node = parent_node.push_child('MESH_TFACELIST')
|
||||||
for texture_face_index, texture_face in enumerate(geometry_object.texture_vertex_faces):
|
for texture_face_index, texture_face in enumerate(geometry_object.texture_vertex_faces):
|
||||||
texture_face_node = texture_faces_node.push_child('MESH_TFACE')
|
texture_face_node = texture_faces_node.push_child('MESH_TFACE')
|
||||||
texture_face_node.push_data([texture_face_index] + list(texture_face))
|
texture_face_node.push_data([texture_face_index] + list(texture_face))
|
||||||
|
|||||||
Reference in New Issue
Block a user