"""Original periodic reed texture, fine relief encoded in tangent normal, no geometry bake."""
from pathlib import Path
import json, numpy as np
from PIL import Image
ROOT=Path(__file__).parent
n=512; y,x=np.mgrid[0:n,0:n]/n; rng=np.random.default_rng(187)
# Exactly periodic longitudinal reeds: +V follows downslope; +U across bundles.
phase=x*96+.025*np.sin(y*2*np.pi*3)
reed=.5+.5*np.cos(phase*2*np.pi)
bundle=.5+.5*np.cos(x*2*np.pi*12+.2*np.sin(y*2*np.pi))
height=.0006*reed+.0006*bundle
variation=.86+.10*reed+.04*bundle+.015*np.sin(y*2*np.pi*2)
col=variation[:,:,None]*np.array([.46,.405,.30])[None,None,:]
dx=(np.roll(height,-1,1)-np.roll(height,1,1))*n/2;dy=(np.roll(height,-1,0)-np.roll(height,1,0))*n/2
normal=np.stack([-dx,-dy,np.ones_like(dx)],2);normal/=np.linalg.norm(normal,axis=2)[:,:,None]
normal=normal*.5+.5
orm=np.stack([.87+.13*reed,np.full_like(x,.96),np.zeros_like(x)],2)
p=ROOT/'materials'/'Thatch_reed';p.mkdir(parents=True,exist_ok=True)
for kind,a in [('BaseColor',col),('Normal',normal),('ORM',orm)]:
 Image.fromarray(np.uint8(np.clip(a,0,1)*255)).save(p/(kind+'.png'))
doc=json.loads((ROOT/'materials.json').read_text());doc['materials']['Thatch_reed']={'maps':{k:'materials/Thatch_reed/'+k+'.png' for k in ['BaseColor','Normal','ORM']},'resolution':n,'tile_size_metres':1,'wrap':'REPEAT','normal_convention':'OpenGL +Y','provenance':'Original deterministic periodic reed height/albedo; normal derived from same height; CC0','physical_repeat_metres':[1,1],'grain_axis':'V follows roof downslope'}
for d in doc['materials'].values():d.update(base=d['maps']['BaseColor'],normal=d['maps']['Normal'],orm=d['maps']['ORM'],tile=d.get('tile_size_metres',1),roughness=1,metalness=1)
(ROOT/'materials.json').write_text(json.dumps(doc,indent=2))
# Cut stalk ends for the exposed eaves/verges. Separate registered shelf avoids
# corrupting the longitudinal repeat on the top surface.
phase_x=(x*40+.28*np.sin(np.floor(y*40)*2.399))%1-.5
phase_y=(y*40)%1-.5
rad=np.sqrt((phase_x/.46)**2+(phase_y/.40)**2)
ends=.60+.23*np.exp(-((rad-.74)/.16)**2)-.24*np.exp(-(rad/.35)**2)
col=ends[:,:,None]*np.array([.64,.56,.42])[None,None,:]
h=.003*np.exp(-((rad-.74)/.17)**2)
dx=(np.roll(h,-1,1)-np.roll(h,1,1))*n/2;dy=(np.roll(h,-1,0)-np.roll(h,1,0))*n/2
normal=np.stack([-dx,-dy,np.ones_like(dx)],2);normal/=np.linalg.norm(normal,axis=2)[:,:,None];normal=normal*.5+.5
orm=np.stack([np.clip(ends+.20,0,1),np.full_like(x,.98),np.zeros_like(x)],2)
p=ROOT/'materials'/'Thatch_reed_cut';p.mkdir(parents=True,exist_ok=True)
for kind,a in [('BaseColor',col),('Normal',normal),('ORM',orm)]:Image.fromarray(np.uint8(np.clip(a,0,1)*255)).save(p/(kind+'.png'))
doc['materials']['Thatch_reed_cut']={'maps':{k:'materials/Thatch_reed_cut/'+k+'.png' for k in ['BaseColor','Normal','ORM']},'resolution':n,'tile_size_metres':.4,'wrap':'REPEAT','normal_convention':'OpenGL +Y','provenance':'Original deterministic bundled hollow reed cross-sections, CC0'}
for d in doc['materials'].values():d.update(base=d['maps']['BaseColor'],normal=d['maps']['Normal'],orm=d['maps']['ORM'],tile=d.get('tile_size_metres',1),roughness=1,metalness=1)
(ROOT/'materials.json').write_text(json.dumps(doc,indent=2))
