import bpy, sys, importlib.util, os, tempfile spec=importlib.util.spec_from_file_location("sgg", r"A:\eco\stylized_rock_generator\stylized_grass_generator.py") g=importlib.util.module_from_spec(spec); sys.modules["sgg"]=g; spec.loader.exec_module(g) try: g.unregister() except Exception: pass g.register() fails=[] for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True) s=bpy.context.scene.grass_gen_settings s.preset='gras'; bpy.ops.grassgen.apply_preset() s.art_name="Gras"; s.variant=1; s.batch_count=1 bpy.ops.object.grassgen_create() ob=[o for o in bpy.context.scene.objects if o.type=='MESH'][0] me=ob.data tris=sum(len(p.vertices)-2 for p in me.polygons) print("OBJEKT %s Tris=%d (Budget %d)" % (ob.name, tris, s.tri_budget)) if tris > s.tri_budget: fails.append("budget") # --- Kernpruefung: UV.V muss mit der HOEHE korrelieren --- uv=me.uv_layers[0].data zs=[]; vs=[] for poly in me.polygons: for li in poly.loop_indices: zs.append(me.vertices[me.loops[li].vertex_index].co.z) vs.append(uv[li].uv[1]) zmin,zmax=min(zs),max(zs) wurzel=[vs[i] for i in range(len(vs)) if zs[i] < zmin + (zmax-zmin)*0.05] spitze=[vs[i] for i in range(len(vs)) if zs[i] > zmin + (zmax-zmin)*0.95] print("UV.V an der WURZEL: %.3f an der SPITZE: %.3f (Bereich %.2f..%.2f)" % (sum(wurzel)/len(wurzel), sum(spitze)/len(spitze), min(vs), max(vs))) if sum(wurzel)/len(wurzel) > 0.12: fails.append("V_wurzel_nicht_0") if sum(spitze)/len(spitze) < 0.80: fails.append("V_spitze_nicht_1") if min(vs) < -0.001 or max(vs) > 1.001: fails.append("V_ausserhalb_0_1") # U ueber die Breite us=[uv[li].uv[0] for poly in me.polygons for li in poly.loop_indices] print("UV.U Bereich: %.2f..%.2f" % (min(us),max(us))) # --- Vertex-Farben als Zusatzebene --- ca=me.color_attributes[0] if me.color_attributes else None if ca is None: fails.append("keine_vcol") else: R=[d.color[0] for d in ca.data]; G=[d.color[1] for d in ca.data]; B=[d.color[2] for d in ca.data] print("VCol R %.2f..%.2f | G %.2f..%.2f | B %.2f..%.2f" % (min(R),max(R),min(G),max(G),min(B),max(B))) if max(G)-min(G) < 0.2: fails.append("G_keine_halmvariation") # G muss PRO HALM konstant sein -> Anzahl unterschiedlicher Werte ~ Halmzahl uniq=len({round(x,4) for x in G}) print("G unterschiedliche Werte: %d (Halme: %d)" % (uniq, s.blades)) if uniq > s.blades*1.5: fails.append("G_nicht_pro_halm") # Ursprung unten print("min_z = %.4f (soll ~0)" % zmin) if abs(zmin) > 0.01: fails.append("ursprung") # FBX-Roundtrip tmp=tempfile.mkdtemp(); fp=os.path.join(tmp,"g.fbx") ob.select_set(True); bpy.context.view_layer.objects.active=ob bpy.ops.export_scene.fbx(filepath=fp, use_selection=True, colors_type='SRGB', use_triangles=True) for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True) bpy.ops.import_scene.fbx(filepath=fp) imp=[o for o in bpy.data.objects if o.type=='MESH'][0] iuv=[d.uv[1] for d in imp.data.uv_layers[0].data] ica=[a.name for a in imp.data.color_attributes] print("NACH FBX: UV.V %.2f..%.2f VCol=%s" % (min(iuv),max(iuv), ica)) if max(iuv) < 0.9: fails.append("fbx_uv_verloren") g.unregister() print("ERGEBNIS:", "ALLE CHECKS OK" if not fails else "FEHLER: "+", ".join(fails))