"""Finishing pass for the photo study, executed once in Blender through MCP.""" import bpy, bmesh, math from mathutils import Vector, noise ns=bpy.app.driver_namespace['photo_rocks'] for obj in ns['rocks'].objects: if obj.get('joint_pass'): continue bm=bmesh.new();bm.from_mesh(obj.data) bmesh.ops.remove_doubles(bm,verts=list(bm.verts),dist=.001) # Sample the joints closely enough to avoid a texture-only crack on a flat wall. for _ in range(3): long=[edge for edge in bm.edges if edge.calc_length()>.7] if not long:break bmesh.ops.subdivide_edges(bm,edges=long,cuts=1,use_grid_fill=True) bm.normal_update() for v in bm.verts: p=v.co.copy() if p.z < -28:continue bedding=min(abs(p.z+.13*p.x-h) for h in [-22,-15,-9,-3,3]) vertical=min(abs(p.x+.16*p.y+.09*p.z-h) for h in [-24,-20,-16,-12,-5,1,6]) cut=.42*math.exp(-(bedding/.23)**2)+.29*math.exp(-(vertical/.2)**2) weather=.065*noise.noise_vector(p*2.1).x v.co+=v.normal*(weather-cut) bmesh.ops.recalc_face_normals(bm,faces=list(bm.faces)) bm.to_mesh(obj.data);bm.free();obj.data.update() # Restore projected UVs after subdivisions; color layers interpolate in bmesh. uv=obj.data.uv_layers.active for face in obj.data.polygons: axis=max(range(3),key=lambda a:abs(face.normal[a])) for li in face.loop_indices: p=obj.data.vertices[obj.data.loops[li].vertex_index].co uv.data[li].uv=Vector((p.y,p.z) if axis==0 else (p.x,p.z) if axis==1 else (p.x,p.y))/3 obj['joint_pass']=True print('Finished joints:',sum(len(o.data.polygons) for o in ns['rocks'].objects),'faces')