Files
sunrise/scripts/sculpt-asymmetric-marker.py

60 lines
2.9 KiB
Python

"""Shape the left hollow and deep cleft from the supplied oblique photos.
Restores a saved mesh baseline before every run so edits never accumulate.
The front UV atlas and inscription remain attached to their original vertices.
"""
import bpy, math, json
from mathutils import Vector
from pathlib import Path
ROOT = Path('D:/project/sunrise')
spec = json.loads((ROOT/'scripts/constants/marker-shape.json').read_text())
scene = bpy.data.scenes['Summit slab and marker']
bpy.context.window.scene = scene
body = bpy.data.objects['Photo matched summit boulder']
root = bpy.data.objects['summit-marker']
baseline = bpy.data.meshes.get('Marker before asymmetric hollow')
if baseline is None:
baseline = body.data.copy()
baseline.name = 'Marker before asymmetric hollow'
baseline.use_fake_user = True
mesh = body.data
for vertex, source in zip(mesh.vertices,baseline.vertices):
x,y,z = source.co
front = max(0,min(1,(.15-y)/.5))
bowl = math.exp(-((x+.55)/.34)**2-((z-.86)/.67)**4)
# A narrow, slanting cleft between the sunken left bowl and inscribed slab.
cleft = math.exp(-((x+.18-.12*z)/.065)**2)*math.exp(-((z-.86)/.88)**4)
shoulder = math.exp(-((x+.44)/.48)**2)*max(0,min(1,(z-.8)/.7))
vertex.co = (x-.13*shoulder+spec['rightFaceOffset']*max(0,min(1,(x+.12)/.6)),
y+front*(spec['leftBowlDepth']*bowl+spec['cleftDepth']*cleft),
z+spec['leftShoulderLift']*shoulder)
mesh.update()
root.scale = spec['scale']
root['blockedRadius'] = round(max(math.hypot(v.co.x*root.scale.x,v.co.y*root.scale.y) for v in mesh.vertices)+.12,2)
body['asymmetricHollow'] = True
# Close the local fissure under the enlarged stone using the shared terrain mesh.
# This surface is exported for both rendering and walking; no separate pedestal.
bpy.context.view_layer.update()
slab = bpy.data.objects['SLAB_SURFACE']
ground_baseline = bpy.data.meshes.get('Slab before marker seating')
if ground_baseline is None:
ground_baseline = slab.data.copy()
ground_baseline.name = 'Slab before marker seating'
ground_baseline.use_fake_user = True
base = min((body.matrix_world@v.co).z for v in mesh.vertices)
for vertex,source in zip(slab.data.vertices,ground_baseline.vertices):
vertex.co = source.co
d = math.hypot(vertex.co.x-root.location.x,vertex.co.y-root.location.y)
if d >= spec['bedrockRadius']+spec['bedrockBlend']:
continue
t = max(0,min(1,(d-spec['bedrockRadius'])/spec['bedrockBlend']))
weight = 1-t*t*(3-2*t)
target = base+spec['bedrockOverlap']+.025*math.sin(vertex.co.x*3+vertex.co.y*2)
if vertex.co.z < target:
vertex.co.z += (target-vertex.co.z)*weight
slab.data.update()
scene.camera.location = root.location+Vector((1.7,-10,3.5))
scene.camera.rotation_euler = (root.location+Vector((0,0,1.5))-scene.camera.location).to_track_quat('-Z','Y').to_euler()
scene.camera.data.lens = 55
print('Asymmetric left hollow sculpted; scale',spec['scale'],'blocked radius',root['blockedRadius'])