78 lines
5.4 KiB
Python
78 lines
5.4 KiB
Python
"""승인된 31컷에서 정식 요청만 작성한다. 실제 결과는 실행 후 채운다."""
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
ROOT=Path(__file__).resolve().parents[3]
|
|
PROJECT=ROOT/'projects/water-hydrogen-bond-surface-tension'
|
|
PROFILE=dict(engine='BLENDER_EEVEE',device='GPU',fps=50,width=1080,height=1920,samples=64,seed=0)
|
|
REFERENCE_PLAN=[
|
|
('style-3d','style',None,'BondPair','StyleAssets',1017),
|
|
('background-droplet','background','bg-droplet','OpeningDroplet','DropletStudioAssets',0),
|
|
('background-molecules','background','bg-molecules','BondPair','MoleculeStudioAssets',1017),
|
|
('background-interface','background','bg-interface','Interface','InterfaceAssets',3050),
|
|
('background-comparison','background','bg-comparison','EqualVolumeComparison','ComparisonStudioAssets',4076),
|
|
('object-molecule','object',None,'SingleMolecule','MoleculeAssets',396),
|
|
('object-droplet','object',None,'OpeningDroplet','DropletAssets',0)]
|
|
|
|
|
|
def read(stage,revision):
|
|
return json.loads((PROJECT/f'stages/{stage}/r{revision}/artifact.json').read_text(encoding='utf-8'))
|
|
|
|
|
|
def write(stage,request,inputs):
|
|
path=PROJECT/f'stages/{stage}/r2/artifact.json'
|
|
existing=json.loads(path.read_text(encoding='utf-8')) if path.exists() else None
|
|
assert not existing or not existing['payload']['result'], '완료 또는 부분 실제 결과 덮어쓰기 금지'
|
|
value=dict(schema_version='1.1',project_id=PROJECT.name,stage_id=stage,revision=2,inputs=[dict(stage_id=s,revision=r) for s,r in inputs],payload=dict(request=request,result=None))
|
|
path.write_text(json.dumps(value,ensure_ascii=False,indent=2)+'\n',encoding='utf-8')
|
|
|
|
|
|
if __name__=='__main__':
|
|
parser=argparse.ArgumentParser()
|
|
parser.add_argument('--stage',choices=['10-references','11-images','12-motion'],required=True)
|
|
args=parser.parse_args()
|
|
plans=read('08-scenes',3)['payload']['scenes']
|
|
if args.stage!='12-motion':
|
|
entities=read('09-entities',3)['payload']
|
|
read('02-research',1)
|
|
if args.stage=='10-references':
|
|
backgrounds={b['id']:b for b in entities['backgrounds']}
|
|
items=[]
|
|
for id,kind,entity,scene,obj,frame in REFERENCE_PLAN:
|
|
prompt='승인 08 r3의 '+scene+' 상태와 교육용 3D 고정 특징. 실제 '+obj+' 자산. '
|
|
if entity:
|
|
prompt+=' '.join(backgrounds[entity]['fixed_features'])
|
|
elif kind=='object':
|
|
prompt+='O1H2·V자·내부 남색 실선과 금색 분자간 H···O의 구별을 유지한다.' if id=='object-molecule' else '매끈한 청색 닫힌 mesh와 같은 물의 양을 유지하며 별도 껍질이 없다.'
|
|
else:
|
|
prompt+='references/1.png를 보존하고 단순 형태·정돈된 색·부드러운 조명·크림 배경으로 해석한다. 글자는 합성한다.'
|
|
items.append(dict(id=id,kind=kind,entity_id=entity,prompt=prompt))
|
|
write(args.stage,dict(style_reference='references/1.png',items=items,engine='Blender',render_profile=PROFILE),[('02-research',1),('08-scenes',3),('09-entities',3)])
|
|
elif args.stage=='11-images':
|
|
read('03-script',1)
|
|
cuts=read('07-cuts',1)['payload']['cuts']
|
|
reference=read('10-references',2)
|
|
assert reference['payload']['result'] and len(reference['payload']['result']['items'])==7
|
|
appearances={p['cut_id']:p for p in entities['appearances']}
|
|
mapping={'bg-droplet':'background-droplet','bg-molecules':'background-molecules','bg-interface':'background-interface','bg-comparison':'background-comparison'}
|
|
frames=[]
|
|
for cut,plan in zip(cuts,plans):
|
|
scene=plan['start_state'].split(';')[0].split('=')[1]
|
|
refs=['style-3d']+[mapping[b] for b in appearances[cut['id']]['background_ids']]
|
|
refs+=['object-molecule'] if scene in ['SingleMolecule','BondPair','LiquidNetwork','Interface'] else ['object-droplet']
|
|
if scene=='AnswerDroplet':
|
|
refs.append('object-molecule')
|
|
for position,key in [('start','start_ms'),('end','end_ms')]:
|
|
frames.append(dict(id=cut['id']+'-'+position,cut_id=cut['id'],position=position,prompt=plan['description']+' '+plan[position+'_state']+' '+plan['camera'],reference_ids=refs,scene_name=scene,frame_index=cut[key]//20))
|
|
write(args.stage,dict(frames=frames,engine='Blender',render_profile=PROFILE,scene_path='projects/'+PROJECT.name+'/stages/11-images/r2/generated-source/animation.blend'),[('02-research',1),('03-script',1),('07-cuts',1),('08-scenes',3),('09-entities',3),('10-references',2)])
|
|
else:
|
|
cuts=read('07-cuts',1)['payload']['cuts']
|
|
images=read('11-images',2)
|
|
assert images['payload']['result'] and len(images['payload']['result']['frames'])==62
|
|
frames={f['id']:f for f in images['payload']['request']['frames']}
|
|
clips=[]
|
|
for cut,plan in zip(cuts,plans):
|
|
start,end=frames[cut['id']+'-start'],frames[cut['id']+'-end']
|
|
clips.append(dict(cut_id=cut['id'],start_frame_id=start['id'],end_frame_id=end['id'],duration_ms=cut['end_ms']-cut['start_ms'],motion_prompt=plan['description']+' '+plan['start_state']+' → '+plan['end_state']+' '+plan['camera'],scene_name=start['scene_name'],start_frame=start['frame_index'],end_frame=end['frame_index']))
|
|
write(args.stage,dict(clips=clips,engine='Blender',render_profile=PROFILE,scene_path=images['payload']['result']['scene_file']['path']),[('07-cuts',1),('08-scenes',3),('11-images',2)])
|