Files
samford-valley-home/source/samford-retreat-garage/finish_and_render.py

61 lines
4.3 KiB
Python

import bpy, bmesh, math, json, os
from mathutils import Vector
OUT=os.path.dirname(os.path.abspath(__file__)); s=bpy.context.scene
# Clear grass from the new vehicle surfaces and garage interior.
route=[(36,-40),(28,-33),(22,-27),(8,-26),(5,-22),(5,-13),(1,-12),(-3,-12)]
segments=[]
for a,b in zip(route,route[1:]):
dx,dy=b[0]-a[0],b[1]-a[1]; segments.append((a[0],a[1],dx,dy,dx*dx+dy*dy))
def clear(x,y):
if -7.2<x<1.2 and -22.7<y<-15.3:return True
if -7.05<x<5.05 and -15.55<y<-9.45:return True
for ax,ay,dx,dy,l2 in segments:
t=max(0,min(1,((x-ax)*dx+(y-ay)*dy)/l2))
if (x-ax-t*dx)**2+(y-ay-t*dy)**2<2.08**2:return True
return False
removed=0
for o in s.objects:
if o.type=='MESH' and o.name.startswith('Native grasses'):
bm=bmesh.new(); bm.from_mesh(o.data); faces=[]
for f in bm.faces:
p=o.matrix_world@f.calc_center_median()
if clear(p.x,p.y):faces.append(f)
removed+=len(faces); bmesh.ops.delete(bm,geom=faces,context='FACES'); bm.to_mesh(o.data); bm.free()
# This broad panel is the vehicle entrance, not a permanent wall across the car bay.
o=bpy.data.objects.get('Garage north front panel')
if o:o.name='Garage 3.7m wide sectional vehicle door'; o['Operation']='Concept upward-opening vehicle door; transparent for presentation.'
o=bpy.data.objects.get('Garage roller door concept')
if o:o.name='Garage north service infill panel'
# Distinct static overview for inspecting the driveway without changing the Play camera.
camdata=bpy.data.cameras.new('VIEW - Road garage and retreat'); cam=bpy.data.objects.new(camdata.name,camdata); s.collection.objects.link(cam)
cam.location=(47,40,47); cam.rotation_euler=(Vector((0,-7,1))-cam.location).to_track_quat('-Z','Y').to_euler(); camdata.lens=38; camdata.clip_end=450
tour=bpy.data.objects['PLAY TOUR camera']; s.camera=tour; s.frame_set(1)
report=json.load(open(os.path.join(OUT,'design-checks.json'))); report['grass_faces_cleared_from_vehicle_surfaces']=removed
report['retained_child_beds']=sum(o.name.startswith('Child') and ('bed' in o.name or 'mattress' in o.name) for o in s.objects)
report['transparent_buildings']=['Living pavilion','Parents bedroom wing','Short corridor','Meditation room','Sauna','Greenhouse','Garage']
assert report['retained_child_beds']==0 and report['candles']==3
chapters=json.load(open(os.path.join(OUT,'tour-chapters.json')))
for ch in chapters:
s.frame_set(ch['start']); a=tour.location.copy(); s.frame_set(ch['end']); b=tour.location.copy(); assert (b-a).length>.01
report['all_23_chapters_animate']=True; json.dump(report,open(os.path.join(OUT,'design-checks.json'),'w'),indent=2)
s.camera=tour; s.frame_set(1)
for screen in bpy.data.screens:
for area in screen.areas:
if area.type=='VIEW_3D':
area.spaces.active.region_3d.view_perspective='CAMERA'; area.spaces.active.shading.type='SOLID'; area.spaces.active.shading.color_type='MATERIAL'; area.spaces.active.overlay.show_overlays=False
s.render.engine='CYCLES'; s.render.resolution_percentage=100; s.cycles.samples=48; s.cycles.use_denoising=True; s.cycles.adaptive_threshold=.035
prefs=bpy.context.preferences.addons['cycles'].preferences; prefs.compute_device_type='METAL'; prefs.get_devices()
for d in prefs.devices:d.use=d.type=='METAL'
s.cycles.device='GPU'; s.render.filepath=os.path.join(OUT,'retreat-garage-overview.png')
bpy.ops.wm.save_as_mainfile(filepath=os.path.join(OUT,'samford-retreat-garage-tour.blend'))
# Captions are useful during playback, but photographs use clean architectural views.
titles=[o for o in bpy.data.collections['22 PLAY - guided camera tour'].objects if o.type=='FONT']
for o in titles:o.hide_render=True
s.camera=cam; bpy.ops.render.render(write_still=True); print('OVERVIEW_RENDERED',flush=True)
s.camera=tour; s.frame_set(2220); s.render.filepath=os.path.join(OUT,'meditation-room.png'); bpy.ops.render.render(write_still=True); print('MEDITATION_RENDERED',flush=True)
s.frame_set(2460); s.render.filepath=os.path.join(OUT,'garage-workstation-bikes.png'); bpy.ops.render.render(write_still=True); print('GARAGE_RENDERED',flush=True)
for o in titles:o.hide_render=False
s.camera=tour; s.frame_set(1); s.render.filepath=os.path.join(OUT,'retreat-garage-overview.png')
bpy.ops.wm.save_as_mainfile(filepath=os.path.join(OUT,'samford-retreat-garage-tour.blend'))
print('FINAL_RETREAT_READY_TO_PLAY',flush=True)