34 lines
1.6 KiB
Python
34 lines
1.6 KiB
Python
"""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')
|