From 556054cd9efc67022ad77429364d61b4e9bd6b51 Mon Sep 17 00:00:00 2001 From: Thomas FORGIONE Date: Thu, 19 Jan 2017 11:23:48 +0100 Subject: [PATCH] Export ply supports texture --- assets/models/cube/cube.mtl | 3 --- d3/model/basemodel.py | 8 ++++++++ d3/model/formats/obj.py | 20 ++++++++++---------- d3/model/formats/ply.py | 34 +++++++++++++++++++++++++--------- d3/model/mesh.py | 22 ++++++++++++++++------ 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/assets/models/cube/cube.mtl b/assets/models/cube/cube.mtl index 5473cb4..5a4b37f 100644 --- a/assets/models/cube/cube.mtl +++ b/assets/models/cube/cube.mtl @@ -8,6 +8,3 @@ Ka 0.5 0.5 0. Kd 0.9 0.9 0.9 Ks 0.0 0.0 0.0 map_Kd cube.png - -newmtl fuckyou -Ka 1 1 1 diff --git a/d3/model/basemodel.py b/d3/model/basemodel.py index d8a9b52..cd0cc3e 100644 --- a/d3/model/basemodel.py +++ b/d3/model/basemodel.py @@ -97,6 +97,7 @@ class ModelParser: self.normals = [] self.tex_coords = [] self.parts = [] + self.materials = [] self.current_part = None self.bounding_box = BoundingBox() self.center_and_scale = True @@ -252,6 +253,13 @@ class ModelParser: face.b.normal = index face.c.normal = index + def get_material_index(self, material): + """Finds the index of the given material + + :param material: Material you want the index of + """ + return [i for (i,m) in enumerate(self.materials) if m.name == material.name][0] + class TextModelParser(ModelParser): def parse_file(self, path): """Sets the path of the model and parse each line diff --git a/d3/model/formats/obj.py b/d3/model/formats/obj.py index 843131f..6ff38ff 100644 --- a/d3/model/formats/obj.py +++ b/d3/model/formats/obj.py @@ -42,7 +42,7 @@ class OBJParser(TextModelParser): self.mtl = MTLParser(self) self.mtl.parse_file(path) else: - print('Warning : ' + path + 'not found ', file=sys.stderr) + print('Warning : ' + path + ' not found ', file=sys.stderr) elif first == 'v': self.add_vertex(Vertex().from_array(split)) elif first == 'vn': @@ -55,7 +55,11 @@ class OBJParser(TextModelParser): for i in range(len(splits)): for j in range(len(splits[i])): if splits[i][j] is not '': - splits[i][j] = int(splits[i][j]) - 1 + splits[i][j] = int(splits[i][j]) + if splits[i][j] > 0: + splits[i][j] -= 1 + else: + splits[i][j] = len(self.vertices) + splits[i][j] # if Face3 if len(split) == 3: @@ -83,7 +87,6 @@ class MTLParser: :param parent: the OBJParser this MTLParser refers to """ self.parent = parent - self.materials = [] self.current_mtl = None def parse_line(self, string): @@ -101,7 +104,7 @@ class MTLParser: if first == 'newmtl': self.current_mtl = Material(split[0]) - self.materials.append(self.current_mtl) + self.parent.materials.append(self.current_mtl) elif first == 'Ka': self.current_mtl.Ka = Vertex().from_array(split) elif first == 'Kd': @@ -109,11 +112,8 @@ class MTLParser: elif first == 'Ks': self.current_mtl.Ks = Vertex().from_array(split) elif first == 'map_Kd': - try: - import PIL.Image - self.current_mtl.map_Kd = PIL.Image.open(os.path.join(os.path.dirname(self.parent.path), split[0])) - except: - pass + self.current_mtl.relative_path_to_texture = split[0] + self.current_mtl.absolute_path_to_texture = os.path.join(os.path.dirname(self.parent.path), split[0]) def parse_file(self, path): @@ -123,7 +123,7 @@ class MTLParser: self.parse_line(line) def __getitem__(self, key): - for material in self.materials: + for material in self.parent.materials: if material.name == key: return material diff --git a/d3/model/formats/ply.py b/d3/model/formats/ply.py index cfa4d04..c9c8cee 100644 --- a/d3/model/formats/ply.py +++ b/d3/model/formats/ply.py @@ -21,7 +21,7 @@ def _ply_type_size(type): """Returns the size of a ply property :param type: a string that is in a ply element - """" + """ if type == 'char' or type == 'uchar': return 1 elif type == 'short' or type == 'ushort': @@ -86,7 +86,6 @@ class PLYParser(ModelParser): super().__init__(up_conversion) self.counter = 0 self.elements = [] - self.materials = [] self.inner_parser = PLYHeaderParser(self) self.beginning_of_line = '' self.header_finished = False @@ -156,11 +155,8 @@ class PLYHeaderParser: elif split[0] == 'comment' and split[1] == 'TextureFile': material = Material('mat' + str(len(self.parent.materials))) self.parent.materials.append(material) - - try: - material.map_Kd = PIL.Image.open(os.path.join(os.path.dirname(self.parent.path), split[2])) - except ImportError: - pass + material.relative_path_to_texture = split[2] + material.absolute_path_to_texture = os.path.join(os.path.dirname(self.parent.path), split[2]) class PLYElement: def __init__(self, name, number): @@ -258,6 +254,7 @@ class PLY_ASCII_ContentParser: elif property[0] == 'texnumber': current_material = self.parent.materials[int(split[offset])] + offset += 1 face = Face(*faceVertexArray) face.material = current_material @@ -454,13 +451,20 @@ class PLYExporter(Exporter): # Header string = "ply\nformat ascii 1.0\ncomment Automatically gnerated by model-converter\n" + for material in self.model.materials: + string += "comment TextureFile " + material.relative_path_to_texture + "\n" + # Types : vertices string += "element vertex " + str(len(self.model.vertices)) +"\n" string += "property float x\nproperty float y\nproperty float z\n" # Types : faces string += "element face " + str(len(faces)) + "\n" - string += "property list uint8 int32 vertex_indices\n" + string += "property list uchar int vertex_indices\n" + + if len(self.model.tex_coords) > 0: + string += "property list uchar float texcoord\n" + string += "property int texnumber\n" # End header string += "end_header\n" @@ -470,7 +474,19 @@ class PLYExporter(Exporter): string += str(vertex.x) + " " + str(vertex.y) + " " + str(vertex.z) + "\n" for face in faces: - string += "3 " + str(face.a.vertex) + " " + str(face.b.vertex) + " " + str(face.c.vertex) + "\n" + string += "3 " + str(face.a.vertex) + " " + str(face.b.vertex) + " " + str(face.c.vertex) + + if len(self.model.tex_coords) > 0: + string += " 6 " \ + + str(self.model.tex_coords[face.a.tex_coord].x) + " " \ + + str(self.model.tex_coords[face.a.tex_coord].y) + " " \ + + str(self.model.tex_coords[face.b.tex_coord].x) + " " \ + + str(self.model.tex_coords[face.b.tex_coord].y) + " " \ + + str(self.model.tex_coords[face.c.tex_coord].x) + " " \ + + str(self.model.tex_coords[face.c.tex_coord].y) + " " \ + + str(self.model.get_material_index(face.material)) + + string += "\n" return string diff --git a/d3/model/mesh.py b/d3/model/mesh.py index ba14b23..c47f36f 100644 --- a/d3/model/mesh.py +++ b/d3/model/mesh.py @@ -12,7 +12,9 @@ class Material: self.Ka = None self.Kd = None self.Ks = None - self.map_Kd = None + self.relative_path_to_texture = None + self.absolute_path_to_texture = None + self.im = None self.id = None def init_texture(self): @@ -28,13 +30,21 @@ class Material: return # If no map_Kd, nothing to do - if self.map_Kd is None: - return + if self.im is None: + + if self.absolute_path_to_texture is None: + return + + try: + import PIL.Image + self.im = PIL.Image.open(self.absolute_path_to_texture) + except ImportError: + return try: - ix, iy, image = self.map_Kd.size[0], self.map_Kd.size[1], self.map_Kd.tobytes("raw", "RGBA", 0, -1) + ix, iy, image = self.im.size[0], self.im.size[1], self.im.tobytes("raw", "RGBA", 0, -1) except: - ix, iy, image = self.map_Kd.size[0], self.map_Kd.size[1], self.map_Kd.tobytes("raw", "RGBX", 0, -1) + ix, iy, image = self.im.size[0], self.im.size[1], self.im.tobytes("raw", "RGBX", 0, -1) self.id = gl.glGenTextures(1) @@ -73,7 +83,7 @@ Material.DEFAULT_MATERIAL.Ks = 0.0 try: import PIL.Image - Material.DEFAULT_MATERIAL.map_Kd = PIL.Image.new("RGBA", (1,1), "white") + Material.DEFAULT_MATERIAL.im = PIL.Image.new("RGBA", (1,1), "white") except ImportError: pass