From bf0e940a57cb46ba75e0364c5186da8f18993af7 Mon Sep 17 00:00:00 2001 From: TigerKat Date: Sat, 27 Mar 2021 14:47:24 +0930 Subject: [PATCH] Added .geo import support for blender 2.80 . --- __init__.py | 3 +- geo.py | 22 +++++++++--- geomesh.py | 5 +-- import_geo.py | 99 +++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 106 insertions(+), 23 deletions(-) diff --git a/__init__.py b/__init__.py index 182e2ce..8836d51 100644 --- a/__init__.py +++ b/__init__.py @@ -2,7 +2,7 @@ bl_info = { "name": "City of Heroes (.geo)", "author": "TigerKat", - "version": (0, 2, 0), + "version": (0, 2, 1), "blender": (2, 80, 0), "location": "File > Import/Export,", "description": "City of Heroes (.geo)", @@ -94,7 +94,6 @@ class ExportGeoMetric(bpy.types.Operator, ExportHelper): )) return export_geo.save(self, context, 1.0 / 0.30480000376701355, **keywords) - def menu_func_import(self, context): self.layout.operator(ImportGeo.bl_idname, text="City of Heroes (Feet) (.geo)") diff --git a/geo.py b/geo.py index ad923e3..0b1b67e 100755 --- a/geo.py +++ b/geo.py @@ -9,10 +9,12 @@ try: from .bones import * from .polygrid import PolyCell, PolyGrid from .util import Data + from .geomesh import GeoMesh, GeoFace, GeoVertex except: from bones import * from polygrid import PolyCell, PolyGrid from util import Data + from geomesh import GeoMesh, GeoFace, GeoVertex #Ver 0 .geo pre-header: #Offset Size Description @@ -914,17 +916,29 @@ class Model: uv = (0, 0) if geomesh.have_weights: weights = [] - for i, w in enumerate(self.weights): - weights.append([self.weight_bones[i], w]) + #print("verts #: %s weights #: %s weight bones #: %s" % (len(self.verts), len(self.weights), len(self.weight_bones))) + #for k, w in enumerate(self.weights): + w = self.weights[i] + w_bones = self.weight_bones[i] + for j, b in enumerate(w_bones): + if w[j] == 0: + continue + #print("vertex_idx: %s weight_bones: %s" % (i, b, )) + #print(" bone_id: %s" % (self.bone_ids[b], )) + w_name = BONES_LIST[b] + #weights.append((geomesh.getWeightIndex(w_name), w[j])) + geomesh.getWeightIndex(w_name) + weights.append([w_name, w[j]]) else: weights = [] - v = GeoVertex(coord, normal, uv, self.weights) + #print(" weights: %s" % (weights, )) + v = GeoVertex(coord, normal, uv, weights) geomesh.getGeoVertexIndex(v) texture_indexes = [] for t in self.tex_idx: texture_indexes += [geomesh.getTextureIndex(self.geo.header_texnames[t[0]])] * t[1] for i, t in enumerate(self.tris): - geomesh.addFace(geomesh.geovertex[t[0]], geomesh.geovertex[t[1]], geomesh.geovertex[t[2]], texture_indexes[i]) + geomesh.addFace([geomesh.geovertex[t[0]], geomesh.geovertex[t[1]], geomesh.geovertex[t[2]]], texture_indexes[i]) return geomesh def loadFromGeoMesh(self, geomesh): self.tris = [] #uncompressDeltas(self.tris_data, 3, self.tri_count, "I") diff --git a/geomesh.py b/geomesh.py index 2e4da08..52d846a 100644 --- a/geomesh.py +++ b/geomesh.py @@ -11,11 +11,12 @@ class GeoVertex: self.coord = coord self.normal = normal self.uv = uv - self.weights = weights + self.weights = tuple(weights) def __eq__(self, other): return self.coord == other.coord and self.normal == other.normal and self.uv == other.uv and self.weights == other.weights def __hash__(self): #print("__hash__: %s" % ((tuple(self.coord), tuple(self.normal), tuple(self.uv), tuple(self.weights)), )) + #self.dump() return hash((tuple(self.coord), tuple(self.normal), tuple(self.uv), tuple_weights(self.weights))) def selectWeights(self, count = None): """Returns the list of weights attached to this vertex. List is sorted by weight, with the strongest first. If 'count' is given, only 'count' strongest are return. The final list is normalized so the sum is 1.""" @@ -104,7 +105,7 @@ class GeoMesh: return for i in range(3): for w in geovertices[i].weights: - w[0] = self.getWeightIndex(w[0]) + # w_index = self.getWeightIndex(w[0]) self.have_weights = True geovertices_index = [self.getGeoVertexIndex(geovertices[0]), self.getGeoVertexIndex(geovertices[1]), diff --git a/import_geo.py b/import_geo.py index 42162fe..1d2faaa 100644 --- a/import_geo.py +++ b/import_geo.py @@ -1,13 +1,81 @@ +from .geo import Geo +from .geomesh import * +from .bones import * +import bpy.path +import bpy +import mathutils + +def import_scale_coord(v, scale): + return (v[0] * scale, v[1] * scale, v[2] * scale) +if 0: + def import_fix_coord(v): + return (v[0], v[2], -v[1]) + def import_fix_normal(v): + return (-v[0], -v[2], v[1]) + def import_fix_winding(l): + l = list(l) + l.reverse() + return l +else: + def import_fix_coord(v): + return (-v[0], v[2], -v[1]) + def import_fix_normal(v): + return ( v[0], -v[2], v[1]) + def import_fix_winding(l): + return l + +def convert_model(geo_model, mesh_data, obj, scale): + #Convert the geo_model into a GeoMesh. + geomesh = geo_model.saveToGeoMesh() + + indices = [i for face in geomesh.face for i in import_fix_winding(face.vert_indexes)] + texture_indices = [face.texture_index for face in geomesh.face] + + mesh_data.vertices.add(len(geomesh.geovertex)) + mesh_data.loops.add(len(indices)) + mesh_data.polygons.add(len(geomesh.face)) + + coords = [c for v in geomesh.geovertex for c in import_scale_coord(import_fix_coord(v.coord), scale)] + normals = [n for v in geomesh.geovertex for n in import_fix_normal(v.normal)] + loop_totals = [] + loop_starts = [] + i = 0 + for f in geomesh.face: + loop_totals.append(len(f.vert_indexes)) + loop_starts.append(i) + i += loop_totals[-1] + + + mesh_data.vertices.foreach_set("co", coords) + mesh_data.vertices.foreach_set("normal", normals) + mesh_data.loops.foreach_set("vertex_index", indices) + mesh_data.polygons.foreach_set("loop_start", loop_starts) + mesh_data.polygons.foreach_set("loop_total", loop_totals) + mesh_data.polygons.foreach_set("material_index", texture_indices) + #mesh_data.update() + + vgroup = {} + for w_name in geomesh.weights: + vgroup[w_name] = obj.vertex_groups.new(name=w_name) + for i, v in enumerate(geomesh.geovertex): + for w in v.weights: + #print("vertex idx: %s group: %s weight: %s" % (i, w[0], w[1])) + vgroup[w[0]].add([i], w[1], 'REPLACE') + #for v in ob.vertices: + # weight_values.append( v.groups[o.vertex_groups[vg_name].index].weight ) + #???mesh_data.validate(False) + + d = mesh_data.uv_layers.new().data + uvs = [c for f in geomesh.face for i in f.vert_indexes for c in geomesh.geovertex[i].uv] + d.foreach_set('uv', uvs) + + + + mesh_data.validate() + mesh_data.update() + mesh_data.vertices.foreach_set("normal", normals) + mesh_data.update() -def convert_model(geo_model, mesh, obj): - #Create vertices - #todo: populate coordinates - #todo: populate normals - #todo: create edges - #todo: create faces - #todo: populate uvs - mesh.validate() - mesh.update() #todo: attempt to load textures/images @@ -19,15 +87,16 @@ def load(operator, context, scale = 1.0, filepath = "", global_matrix = None, us fh_in.close() for geo_model in geo.models: #create object matching model's name (or next equivilant) - mesh = bpy.data.meshes.new(name = model.name.decode("utf-8")) + mesh = bpy.data.meshes.new(name = geo_model.name.decode("utf-8")) + obj = bpy.data.objects.new(geo_model.name.decode("utf-8"), mesh) #convert model to mesh - convert_mode(geo_model, mesh, None) + convert_model(geo_model, mesh, obj, scale) #Create object for this mesh scn = bpy.context.scene - obj = bpy.data.objects.new(ply_name, mesh) - scn.objects.link(obj) - scn.objects.active = obj - obj.select = True + bpy.context.collection.objects.link(obj) + bpy.context.view_layer.objects.active = obj + obj.select_set(True) pass pass + return {'FINISHED'}