60 lines
2.9 KiB
Python
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'])
|