diff --git a/fast64_internal/z64/collision/operators.py b/fast64_internal/z64/collision/operators.py index 48321d093..0ae7a2f5a 100644 --- a/fast64_internal/z64/collision/operators.py +++ b/fast64_internal/z64/collision/operators.py @@ -29,9 +29,13 @@ def execute(self, context): try: transform = Matrix.Scale(getOOTScale(obj.ootActorScale), 4) settings: OOTCollisionExportSettings = context.scene.fast64.oot.collisionExportSettings - CollisionHeader.export(obj, transform, settings) + degen_tris_found_in = CollisionHeader.export(obj, transform, settings) - self.report({"INFO"}, "Success!") + if degen_tris_found_in: + details = ", ".join(f"{mesh} (material {material})" for mesh, material in degen_tris_found_in) + self.report({"WARNING"}, "Success, but skipped degenerate tris in meshes " + details) + else: + self.report({"INFO"}, "Success!") return {"FINISHED"} except Exception as e: if context.mode != "OBJECT": diff --git a/fast64_internal/z64/exporter/__init__.py b/fast64_internal/z64/exporter/__init__.py index f88205c18..e7348f419 100644 --- a/fast64_internal/z64/exporter/__init__.py +++ b/fast64_internal/z64/exporter/__init__.py @@ -53,7 +53,7 @@ class SceneExport: """This class is the main exporter class, it handles generating the C data and writing the files""" @staticmethod - def create_scene(originalSceneObj: Object, transform: Matrix, exportInfo: ExportInfo) -> Scene: + def create_scene(originalSceneObj: Object, transform: Matrix, exportInfo: ExportInfo): """Returns and creates scene data""" # init if originalSceneObj.type != "EMPTY" or originalSceneObj.ootEmptyType != "Scene": @@ -70,7 +70,7 @@ def create_scene(originalSceneObj: Object, transform: Matrix, exportInfo: Export try: sceneName = f"{toAlnum(exportInfo.name)}_scene" - newScene = Scene.new( + newScene, degen_tris_found_in = Scene.new( sceneName, originalSceneObj, sceneObj, @@ -85,7 +85,7 @@ def create_scene(originalSceneObj: Object, transform: Matrix, exportInfo: Export finally: ootCleanupScene(originalSceneObj, allObjs) - return newScene + return newScene, degen_tris_found_in @staticmethod def export(originalSceneObj: Object, transform: Matrix, exportInfo: ExportInfo): @@ -94,7 +94,7 @@ def export(originalSceneObj: Object, transform: Matrix, exportInfo: ExportInfo): from .decomp_edit.config import Config checkObjectReference(originalSceneObj, "Scene object") - scene = SceneExport.create_scene(originalSceneObj, transform, exportInfo) + scene, degen_tris_found_in = SceneExport.create_scene(originalSceneObj, transform, exportInfo) isCustomExport = exportInfo.isCustomExportPath exportPath = exportInfo.exportPath @@ -135,3 +135,5 @@ def export(originalSceneObj: Object, transform: Matrix, exportInfo: ExportInfo): f"ENTR_{sceneName.upper()}_{hackerootBootOption.spawnIndex}", hackerootBootOption, ) + + return degen_tris_found_in diff --git a/fast64_internal/z64/exporter/collision/__init__.py b/fast64_internal/z64/exporter/collision/__init__.py index 39317aab6..c0b6ae453 100644 --- a/fast64_internal/z64/exporter/collision/__init__.py +++ b/fast64_internal/z64/exporter/collision/__init__.py @@ -97,6 +97,8 @@ def getCollisionData(dataHolder: Optional[Object], transform: Matrix, useMacros: vertexList: list[CollisionVertex] = [] colBounds: list[tuple[int, int, int]] = [] + degen_tris_found_in: set[tuple[str, str]] = set() + transformFromMeshObj: dict[Object, Matrix] = {} if dataHolder.type == "MESH" and not dataHolder.ignore_collision: transformFromMeshObj[dataHolder] = transform @@ -113,7 +115,7 @@ def getCollisionData(dataHolder: Optional[Object], transform: Matrix, useMacros: for i, face in enumerate(meshObj.data.loop_triangles): material = meshObj.material_slots[face.material_index].material colProp = material.ootCollisionProperty - raise_error = False + is_degen_tri = False # get bounds and vertices data planePoint = transform @ meshObj.data.vertices[face.vertices[0]].co @@ -138,18 +140,17 @@ def sq(val): nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2) magSqr = sq(nx) + sq(ny) + sq(nz) if magSqr <= 0: - raise_error = True + is_degen_tri = True # for walls only, see https://github.com/zeldaret/oot/blob/eb5dac74d6435baf85ced9158d3ff915ba8872ca/src/code/z_bgcheck.c#L751 if normal[1] >= -0.8 and normal[1] <= 0.5: normal_xz = math.sqrt(sq(normal[0]) + sq(normal[2])) if math.fabs(normal_xz) < 0.008: - raise_error = True + is_degen_tri = True - if raise_error: - raise PluginError( - f"degenerate triangle detected on mesh object '{meshObj.name}' (material name is '{material.name}')" - ) + if is_degen_tri: + degen_tris_found_in.add((meshObj.name, material.name)) + continue indices: list[int] = [] for pos in [(x1, y1, z1), (x2, y2, z2), (x3, y3, z3)]: @@ -212,7 +213,7 @@ def sq(val): surfaceList.append(surface) count += 1 - return colBounds, vertexList, polyList, surfaceList + return colBounds, vertexList, polyList, surfaceList, degen_tris_found_in @dataclass @@ -242,11 +243,11 @@ def new( settings: Optional[OOTCollisionExportSettings] = None, ): # Ideally everything would be separated but this is complicated since it's all tied together - colBounds, vertexList, polyList, surfaceTypeList = CollisionUtility.getCollisionData( + colBounds, vertexList, polyList, surfaceTypeList, degen_tris_found_in = CollisionUtility.getCollisionData( dataHolder, transform, useMacros, includeChildren ) - return CollisionHeader( + col_header = CollisionHeader( name, colBounds[0], colBounds[1], @@ -259,6 +260,8 @@ def new( WaterBoxes.new(f"{sceneName}_waterBoxes", dataHolder, transform, useMacros), ) + return col_header, degen_tris_found_in + @staticmethod def export(original_obj: Object, transform: Matrix, settings: OOTCollisionExportSettings): """Exports collision data as C files, this should be called to do a separate export from the scene.""" @@ -280,7 +283,7 @@ def export(original_obj: Object, transform: Matrix, settings: OOTCollisionExport # write file if not obj.ignore_collision: # create the collision header - col_header = CollisionHeader.new( + col_header, degen_tris_found_in = CollisionHeader.new( f"{name}_collisionHeader", name, obj, @@ -304,6 +307,8 @@ def export(original_obj: Object, transform: Matrix, settings: OOTCollisionExport cleanupDuplicatedObjects([obj]) + return degen_tris_found_in + def getCmd(self): """Returns the collision header scene command""" diff --git a/fast64_internal/z64/exporter/scene/__init__.py b/fast64_internal/z64/exporter/scene/__init__.py index c9a576dcc..38cbcbf4a 100644 --- a/fast64_internal/z64/exporter/scene/__init__.py +++ b/fast64_internal/z64/exporter/scene/__init__.py @@ -112,7 +112,7 @@ def new( ) # process collisions first so we can use it for animated materials (dumb but works!) - colHeader = CollisionHeader.new( + colHeader, degen_tris_found_in = CollisionHeader.new( f"{name}_collisionHeader", name, sceneObj, @@ -204,7 +204,7 @@ def new( hasAlternateHeaders = True if len(altHeader.cutscenes) > 0 else hasAlternateHeaders altHeader = altHeader if hasAlternateHeaders else None - return Scene(name, model, mainHeader, altHeader, rooms, colHeader, hasAlternateHeaders) + return Scene(name, model, mainHeader, altHeader, rooms, colHeader, hasAlternateHeaders), degen_tris_found_in def validateRoomIndices(self): """Checks if there are multiple rooms with the same room index""" diff --git a/fast64_internal/z64/scene/operators.py b/fast64_internal/z64/scene/operators.py index 83c0968f1..0f8a68aec 100644 --- a/fast64_internal/z64/scene/operators.py +++ b/fast64_internal/z64/scene/operators.py @@ -172,13 +172,17 @@ def execute(self, context): settings.auto_add_room_objects, ) - SceneExport.export( + degen_tris_found_in = SceneExport.export( obj, finalTransform, exportInfo, ) - self.report({"INFO"}, "Success!") + if degen_tris_found_in: + details = ", ".join(f"{mesh} (material {material})" for mesh, material in degen_tris_found_in) + self.report({"WARNING"}, "Success, but skipped degenerate tris in meshes " + details) + else: + self.report({"INFO"}, "Success!") # don't select the scene for elem in context.selectable_objects: