import bpy, sys, importlib.util, os, tempfile, math spec=importlib.util.spec_from_file_location("sau", r"A:\eco\stylized_rock_generator\stylized_asset_utils.py") u=importlib.util.module_from_spec(spec); sys.modules["sau"]=u; spec.loader.exec_module(u) try: u.unregister() except Exception: pass u.register() fails=[] for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True) # Pilz wie beim User: Hut + Stiel getrennt, dann Join. Mit ABSICHT unangewendeter # Transform und Ursprung nicht unten - das soll der Check finden. bpy.ops.mesh.primitive_cylinder_add(vertices=10, radius=0.028, depth=0.126, location=(0,0,0.5)) st=bpy.context.active_object bpy.ops.mesh.primitive_uv_sphere_add(segments=14, ring_count=7, radius=0.042, location=(0,0,0.567)) hu=bpy.context.active_object; hu.scale=(1,1,0.5); bpy.ops.object.transform_apply(scale=True) for o in bpy.context.selected_objects: o.select_set(False) st.select_set(True); hu.select_set(True); bpy.context.view_layer.objects.active=st bpy.ops.object.join() p=bpy.context.active_object; p.name="Pilz_roh" p.rotation_euler=(0.16,0.11,-2.26); p.scale=(0.6,0.6,0.6) bpy.ops.mesh.primitive_uv_sphere_add(radius=0.05, location=(1,0,0)) # UV vorhanden p.select_set(True); bpy.context.view_layer.objects.active=p for o in bpy.context.selected_objects: if o is not p: o.select_set(False) s=bpy.context.scene.asset_utils_settings s.tri_budget=400; s.g_mode='SHELLS' print("--- Check VOR dem Vorbereiten (soll meckern) ---") bpy.ops.assetutils.check() print("Scale vorher: %s Rot: %s" % ([round(v,2) for v in p.scale], [round(math.degrees(v),1) for v in p.rotation_euler])) bpy.ops.assetutils.prepare() zs=[(p.matrix_world @ v.co).z - p.location.z for v in p.data.vertices] print("NACH prepare: Scale %s Rot %s min_z %.4f" % ([round(v,3) for v in p.scale], [round(math.degrees(v),1) for v in p.rotation_euler], min(zs))) if any(abs(v-1)>1e-4 for v in p.scale): fails.append("scale_nicht_angewendet") if any(abs(v)>1e-4 for v in p.rotation_euler): fails.append("rot_nicht_angewendet") if abs(min(zs))>0.01: fails.append("ursprung_nicht_unten") bpy.ops.assetutils.bake_vcol() ca=p.data.color_attributes.get("Cavity") if ca is None: fails.append("keine_vcol") else: shells=u._mesh_shells(p.data) infos=[] for sh in shells: vs={vi for pi in sh for vi in p.data.polygons[pi].vertices} infos.append((sh, max(p.data.vertices[v].co.z for v in vs))) infos.sort(key=lambda t:-t[1]) g_top={round(ca.data[li].color[1],3) for pi in infos[0][0] for li in p.data.polygons[pi].loop_indices} g_rest={round(ca.data[li].color[1],3) for sh,_ in infos[1:] for pi in sh for li in p.data.polygons[pi].loop_indices} R=[d.color[0] for d in ca.data]; B=[d.color[2] for d in ca.data]; A=[d.color[3] for d in ca.data] print("VCol: G_Hut=%s G_Stiel=%s | R %.2f..%.2f | B %.2f..%.2f | A %.2f" % (sorted(g_top), sorted(g_rest), min(R),max(R),min(B),max(B),min(A))) if g_top!={1.0}: fails.append("G_hut") if g_rest!={0.0}: fails.append("G_stiel") if max(B)-min(B)<0.8: fails.append("B_flach") if min(A)<0.99: fails.append("A") s.rename_base="Pilz_01"; s.rename_numbered=False bpy.ops.assetutils.rename() print("Umbenannt zu: %s (Mesh: %s)" % (p.name, p.data.name)) if p.name!="Pilz_01": fails.append("rename") print("--- Check NACH dem Vorbereiten (soll sauber sein) ---") bpy.ops.assetutils.check() out=tempfile.mkdtemp(); s.export_dir=out bpy.ops.assetutils.export() fbx=[f for f in os.listdir(out) if f.endswith(".fbx")] print("Export:", fbx) if not fbx: fails.append("export") else: for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True) bpy.ops.import_scene.fbx(filepath=os.path.join(out,fbx[0])) imp=[o for o in bpy.data.objects if o.type=='MESH'][0] ic=[a.name for a in imp.data.color_attributes] ig={round(d.color[1],2) for d in imp.data.color_attributes[0].data} if ic else set() print("Nach FBX: VCol=%s G-Werte=%s" % (ic, sorted(ig))) if not ic: fails.append("fbx_vcol_verloren") u.unregister() print("ERGEBNIS:", "ALLE CHECKS OK" if not fails else "FEHLER: "+", ".join(fails))