UnrealSP.org, now with 100% more Web 2.0!

Python | Wavefront to Unreal Mesh!

For questions and discussion about UnrealEd, UnrealScript, and other aspects of Unreal Engine design.

Moderators: ividyon, Semfry, zYnthetic

User avatar Gustavo6046
Skaarj Scout Skaarj Scout
Posts: 20
Joined: 09 Apr 2016, 14:35
Location: Porto Alegre, Rio Grande do Sul, Brazil
Contact:

Subject: Python | Wavefront to Unreal Mesh!

Post Posted: 15 Sep 2016, 14:37

So I've been working in standalone tools instead of direct exporters from Blender, inspired by Jet. Rock on man! :D

Despite the distorted exports, I seem to have got the overall binary format of those files, in general. But I think Python simply can't do some vector to Unreal vertex long conversion, probably due to the way it handles ints. So I might end up needing to use some class from `ctypes`...

Either way, nerdy stuff behind, this is a simple command-line tool that takes a bunch of Wavefront .obj files inside a folder (ordered by any number in their filename), takes each of them as a frame, and converts the result into an aniv and a data file, with the format `(filename)_(type).3d`.

Copy this into a file named unreal_conv.py:

Code: Select all

import struct_helper
import glob
import sys
import struct


def unreal_vertex(vertex):
   """
   Returns a long int that represents the vertex
   in Unreal Engine 1 (1998/1999)'s aniv data format.
   """
   (x, y, z) = vertex
   
   return int(   (int(x * 8.0) & 0x7ff)
         |  ((int(y * 8.0) & 0x7ff) << 11)
         |  ((int(z * 4.0) & 0x3ff) << 22) )

def export_unreal(obj_folder, export_name, frame_sort=sorted):
   frames = [open(path) for path in frame_sort(glob.glob(obj_folder + "\*.obj"))]
   
   vertices = []
   texture_coords = []
   polys = []
   processed_polys = []
   
   # Reads the mesh data.
   for line in frames[0].readlines():
      if line.startswith("vt "):
         texture_coords.append([float(x) for x in line.split(" ")[1:3]])
            
      elif line.startswith("f "):
         polys.append(line.split(" ")[1:4])
         
   # Reads per-frame vertex data.
   for frame in frames:
      vertices.append([])
   
      for line in frame.readlines():
         if line.startswith("v "):
            vertices[-1].append([float(x) for x in line.split(" ")[1:4]])
            
   # Processes the poly strings.
   for poly in polys:
      processed_polys.append([])
   
      for indexes in poly:
         processed_polys[-1].append([int(x) for x in indexes.split("/")[:2]])
         
   aniv = struct_helper.BinaryFile(export_name + "_a.3d")
   data = struct_helper.BinaryFile(export_name + "_d.3d")
   
   # Write aniv file
   aniv.write_binary(True, "=HL", len(frames), len(vertices[0]) * struct.calcsize("=L")) # header
   
   for frame in vertices:
      for vertex in frame:
         aniv.write_binary(True, "=L", unreal_vertex(vertex))
      
   del aniv
      
   # Write data file
   data.write_binary(True, "=4H7L12B", len(polys), len(vertices[0]), *[0] * 21) # header
   
   for poly in processed_polys:
      try:
         data.write_binary(
            True,
            "=3H2b6B2b",
            poly[0][0],
            poly[1][0],
            poly[2][0],
            1,
            127,
            texture_coords[poly[0][1]][0],
            texture_coords[poly[0][1]][1],
            texture_coords[poly[1][1]][0],
            texture_coords[poly[1][1]][1],
            texture_coords[poly[2][1]][0],
            texture_coords[poly[2][1]][1],
            1,
            0,
         )
         
      except IndexError:
         continue
      
# Start it!
if __name__ == "__main__":
   export_unreal(sys.argv[1], sys.argv[2])


All you must do in command-line is to provide the following arguments:

Code: Select all

python unreal_conv.py <folder where all Wavefront frames reside> <filename of result .3d file (NOT INCLUDING THE ANIV/DATA SUFFIX OR EXTENSION!)>


And done! There is your completely skewed and chewed-on mesh. Courtesy of some fungus...Anyways, if you have any good ideas for this, please post! :)
This is the 700th member!

Half-veteran modeller. Sucker at gaming. Quite nice at coding. O.K. at texturing. Good at mapping in general.

What else do you need? :)

User avatar nikosv
Skaarj Berserker Skaarj Berserker
Posts: 278
Joined: 03 Aug 2008, 23:07
Contact:

Subject: Re: Python | Wavefront to Unreal Mesh!

Post Posted: 16 Sep 2016, 06:48

Heyyyyyy this is unbelievably weird and cool! So this makes meshes? And... can support vertex animation if you set it up right? Righteous! So much so
Current Project: Shiv and I are putting some finishing touches on WTFs2. Done soon :)
B.A. in mathematics, living out of my car in Canada right now. I don't want to talk about it.

User avatar Gustavo6046
Skaarj Scout Skaarj Scout
Posts: 20
Joined: 09 Apr 2016, 14:35
Location: Porto Alegre, Rio Grande do Sul, Brazil
Contact:

Subject: Re: Python | Wavefront to Unreal Mesh!

Post Posted: 16 Sep 2016, 17:44

nikosv wrote:Heyyyyyy this is unbelievably weird and cool! So this makes meshes? And... can support vertex animation if you set it up right? Righteous! So much so


Yes, but currently they are distorted. I plan to use a C integration module to make it possible. Er, it seems not even the `ctypes` module is working!

Code: Select all

import struct_helper
import glob
import sys
import struct

import ctypes


def unreal_vertex(vertex):
   """
   Returns a long int that represents the vertex
   in Unreal Engine 1 (1998/1999)'s aniv data format.
   """
   (x, y, z) = vertex
   
   return ctypes.c_ulong(
      (  ctypes.c_ulong(int(   ctypes.c_int(int(x * 8.0)).value & 0x7ff)       ).value   )
      | (ctypes.c_ulong(int((   ctypes.c_int(int(y * 8.0)).value & 0x7ff) << 11   )).value   )
      | (ctypes.c_ulong(int((   ctypes.c_int(int(z * 4.0)).value & 0x3ff) << 22   )).value   )
   ).value

def export_unreal(obj_folder, export_name, frame_sort=sorted):
   frames = [open(path).readlines() for path in frame_sort(glob.glob(obj_folder + "\*.obj"))]
   
   vertices = []
   texture_coords = []
   polys = []
   processed_polys = []
         
   # Reads per-frame vertex data.
   for i, frame in enumerate(frames):
      vertices.append([])
   
      for line in frame:
         if line.startswith("v "):
            vertices[-1].append([float(x) for x in line.split(" ")[1:4]])
            
         elif line.startswith("vt ") and i == 0:
            texture_coords.append([float(x) for x in line.split(" ")[1:3]])
               
         elif line.startswith("f ") and i == 0:
            polys.append(line.split(" ")[1:4])
            
   # Processes the poly strings.
   for poly in polys:
      processed_polys.append([])
   
      for indexes in poly:
         processed_polys[-1].append([int(x) for x in indexes.split("/")[:2]])
         
   aniv = struct_helper.BinaryFile(export_name + "_a.3d")
   data = struct_helper.BinaryFile(export_name + "_d.3d")
   
   # Write aniv file
   aniv.write_binary(True, "=hL", len(frames), len(vertices[0]) * struct.calcsize("=L")) # header
   
   for frame in vertices:
      for vertex in frame:
         aniv.write_binary(True, "=L", unreal_vertex(vertex))
      
   del aniv
      
   # Write data file
   data.write_binary(True, "=4H7L12B", len(polys), len(vertices[0]), *[0] * 21) # header
   
   for poly in processed_polys:
      try:
         data.write_binary(
            True,
            "=3H2b6B2b",
            poly[0][0],
            poly[1][0],
            poly[2][0],
            1,
            127,
            texture_coords[poly[0][1]][0],
            texture_coords[poly[0][1]][1],
            texture_coords[poly[1][1]][0],
            texture_coords[poly[1][1]][1],
            texture_coords[poly[2][1]][0],
            texture_coords[poly[2][1]][1],
            1,
            0,
         )
         
      except IndexError:
         continue
         
   print "Success: Exported {v} vertices for each {f} frames, with {p} polygons!".format(v=len(vertices[0]), f=len(frames), p=len(processed_polys))
      
# Start it!
if __name__ == "__main__":
   export_unreal(sys.argv[1], sys.argv[2])


Vertices are same distortion. Should probably look elsewhere...
This is the 700th member!

Half-veteran modeller. Sucker at gaming. Quite nice at coding. O.K. at texturing. Good at mapping in general.

What else do you need? :)

User avatar Jet v4.3.5
Skaarj Elder Skaarj Elder
Posts: 1237
Joined: 24 Dec 2007, 17:40
Contact:

Subject: Re: Python | Wavefront to Unreal Mesh!

Post Posted: 17 Sep 2016, 06:38

I haven't really looked into it in depth, but perusing Python's library documentation brought up the option of structs to pack abstract python values into a fixed-size data package.

You might find the information you're looking for by checking out this page.
Image
ModDb Portfolio
"Bear," she cried. "I love you. Pull my head off."

User avatar Gustavo6046
Skaarj Scout Skaarj Scout
Posts: 20
Joined: 09 Apr 2016, 14:35
Location: Porto Alegre, Rio Grande do Sul, Brazil
Contact:

Subject: Re: Python | Wavefront to Unreal Mesh!

Post Posted: 17 Sep 2016, 21:46

Jet v4.3.5 wrote:I haven't really looked into it in depth, but perusing Python's library documentation brought up the option of structs to pack abstract python values into a fixed-size data package.

You might find the information you're looking for by checking out this page.


I already use structs :P

The function `write_binary` I coded works with structs. I forgot to attach the module I made with it.
This is the 700th member!

Half-veteran modeller. Sucker at gaming. Quite nice at coding. O.K. at texturing. Good at mapping in general.

What else do you need? :)


Who is online

Users browsing this forum: No registered users and 1 guest