Python .OBJ to .REO Converter

Anything to do with Drakan level editing and modifications, post it here! Also this is the place to tell us about your new levels and get player feedback.

Moderators: Mechanist, Arokhs Twin, yangez93

unterbuchse
Whelp
Posts: 17
Joined: Thu Feb 27, 2014 2:46 am

Python .OBJ to .REO Converter

Postby unterbuchse » Wed Aug 10, 2016 11:12 pm

Heyho,
Just finished the .obj to .reo converter. As always, it is not perfect but it works. It uses .obj and .mtl files to generate a textured model in .reo format.

Main problems:
- Of course there is no 1:1 conversion possible (bspheres, bboxes, lighting etc are not used in .obj definitions)
- Biggest problem so far: we have no normals! Or let me rephrase this: .reo files do not have explicit normals. This means that the definition that a face is directing in one or the other direction is depending on the order of the vertices during face definition. In an .obj file we have explicit normals, but they cannot be used in the .reo files. Of course one could interprete the normals and then try to find out the correct order of the vertices and then put that in the .reo file but seriously, that would just blow things up.
=> Right now, I used the blender obj exporter and found that without using the vn entries (explicit .obj normals) the vertex order of the faces always generates flipped (meaning: the normals pointed in the "wrong" direction) normals. So the current solution is that the converter just inverts the order of the vertices and hopes for the best.

Some eye candy (Look whos your new best buddy,... Spyro!)
OBJtoREOMonkey.jpg
(230.24 KiB) Downloaded 2095 times
Spyro.jpg
(249.7 KiB) Downloaded 2080 times
IngameSpyro.jpg
IngameSpyro.jpg (165.87 KiB) Viewed 3546 times
Heres the code:
OBJClass.py

Code: Select all

''' Created on 11.08.2016 @author: BuXXe ''' import time class OBJ(object): ''' classdocs ''' def __init__(self): ''' Constructor ''' # Format: Dictionary of meterialname -> filename self.materials = {} self.vertices = [] self.vertexTexcoord = [] # keys are material names and values are lists of face definitions self.faces = {} self.facecount = 0 self.version = "2.2" self.name = "Unnamed Model" self.author = "Anonymous" self.creationDate = time.strftime("%d.%m.%Y") self.lighting = 1 self.transform = [[1,0,0,0],[0,1,0,0],[0,0,1,0]] # bounding data self.bspheres = [] self.bboxes = []
OBJConverter.py

Code: Select all

''' Created on 11.08.2016 @author: BuXXe ''' import OBJClass import os if __name__ == '__main__': # Filename without extension! (.reo .obj and .mtl will be appended in code) # TODO: Right now we assume the obj file is in the same directory as the OBJConverter.py filename="monkey" # read the obj file with open(filename+".obj", 'r') as f: read_data = f.readlines() f.close() # TODO: perhaps use only regex in future but for now keep it simple # TODO: perhaps we should use some kind of grammar or state machine to parse the file # iterate through the read_data linecounter = 0 # create new object OBJ = OBJClass.OBJ() # set filename as model name # Change this if you want a different name OBJ.name = filename # INFO: Comments and empty lines will be ignored as for now while(linecounter < len(read_data)): if(read_data[linecounter][0] == '#' or read_data[linecounter][0] == '\n'): linecounter += 1 continue # Build material dictionary elif(read_data[linecounter].startswith("mtllib")): mtlfile = read_data[linecounter].replace("mtllib ","",1).replace("\n","") # read the mtl file with open(mtlfile, 'r') as f: mtl_data = f.readlines() f.close() mtl_linecounter = 0 while(mtl_linecounter < len(mtl_data)): if(mtl_data[mtl_linecounter].startswith("newmtl")): # get material name materialname = mtl_data[mtl_linecounter].replace("newmtl ","",1).replace("\n","") # search for a map_Kd entry to get the texture if(mtl_data[mtl_linecounter].startswith("map_Kd")): # set only filename as texture entry print "happens" OBJ.materials[materialname] = os.path.basename(mtl_data[mtl_linecounter].replace("map_Kd ","",1).replace("\n","")) mtl_linecounter+=1 # Build up lists of vertices vt and faces elif(read_data[linecounter].startswith("v ")): OBJ.vertices.append(read_data[linecounter].replace("v ","",1).replace("\n","")) elif(read_data[linecounter].startswith("vt ")): OBJ.vertexTexcoord.append(read_data[linecounter].replace("vt ","",1).replace("\n","")) elif(read_data[linecounter].startswith("usemtl")): # set active material which will be used by the following faces activeMaterial = read_data[linecounter].replace("usemtl ","",1).replace("\n","") # add entry to faces dictionary if not yet existing and initialize empty list if not activeMaterial in OBJ.faces: OBJ.faces[activeMaterial] = [] elif(read_data[linecounter].startswith("f ")): OBJ.faces[activeMaterial].append(read_data[linecounter].replace("f ","",1).replace("\n","")) OBJ.facecount +=1 linecounter += 1 # Create the .reo file with open(filename+".reo", 'w') as f: f.write("# Riot Engine Object\n") f.write("# Created with the .obj to .reo converter by BuXXe\n\n") f.write("version " + OBJ.version + "\n") f.write("name "+ OBJ.name +"\n") f.write("created by "+ OBJ.author+ " on " + OBJ.creationDate + "\n\n") f.write("Lighting " + str(OBJ.lighting) + "\n\n") #write materials f.write("materials " + str(len(OBJ.materials)) + "\n") for index,entry in enumerate(sorted(OBJ.materials)): f.write(str(index)+ " texture " + OBJ.materials[entry] + "\n") f.write("\n") f.write("transform\n") for en in OBJ.transform: f.write(" ".join([str(d) for d in en])+"\n") f.write("\n") f.write("vertices "+ str(len(OBJ.vertices)) +"\n") for index, vert in enumerate(OBJ.vertices): f.write(str(index) +" " + vert + "\n") f.write("\n") f.write("faces " +str(OBJ.facecount)+ "\n") f.write("\n") # create blocks and print them facecounter = 0 for material in sorted(OBJ.faces): for face in OBJ.faces[material]: f.write("polygon "+str(facecounter)+"\n") facecounter+=1 fparts = face.split(" ") f.write("vt "+str(len(fparts))+":" + " ".join([str(int(d.split("/")[0]) - 1) for d in reversed(fparts)]) + "\n") f.write("ma " + str(sorted(OBJ.materials).index(material)) + "\n") f.write("tu "+ " ".join( [ OBJ.vertexTexcoord[(int(d.split("/")[1]) - 1)].split(" ")[0] for d in reversed(fparts)]) + "\n") f.write("tv "+ " ".join( [ OBJ.vertexTexcoord[(int(d.split("/")[1]) - 1)].split(" ")[1] for d in reversed(fparts)]) + "\n") f.write("\n") f.close()
Last edited by unterbuchse on Thu Aug 11, 2016 4:31 am, edited 1 time in total.

UCyborg
Dragon
Posts: 424
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Python .OBJ to .REO Converter

Postby UCyborg » Thu Aug 11, 2016 12:52 am

Nice work! So to put it simply, REO format is a bit inconvenient in practice, but it's a necessary evil to get custom models in the game and be able to have properly working collision detection? Well, as "properly" as it works anyway, you know how easy it is to get through some locked doors due to collision detection bugs.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

unterbuchse
Whelp
Posts: 17
Joined: Thu Feb 27, 2014 2:46 am

Re: Python .OBJ to .REO Converter

Postby unterbuchse » Thu Aug 11, 2016 4:37 am

I just added some more screenshots from a little test. Perhaps my skills using the editor are just bad but I think there might be a bug. As you can see I positioned Spyro with custom rotation and scale parameters (Instance Properties) and these changes were also correctly displayed in the 3D View. But in the game, the model appears with the standard parameters without any rotation and scaling.

The boundings for the collision detection could be created using blender as well but then we need some special converter which interleaves the pure model data with the defined bounding spheres/boxes. But this would be a really complex thing so right now i would stick to the modeler as you have to use it anyway to ensure everything is working fine.

UCyborg
Dragon
Posts: 424
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Python .OBJ to .REO Converter

Postby UCyborg » Thu Aug 11, 2016 1:04 pm

I'm not the expert on the editor neither, but does changing scale/rotation work at least if you work with original files? I can change it for the stock model and it shows both in 3D and game.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe


Return to “Drakan Level Editing and Game Mods”

Who is online

Users browsing this forum: No registered users and 3 guests

cron