File size: 3,390 Bytes
9d6c005
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
"""Run a small physical rendering demo with bundled weights; CPU, no account."""
from pathlib import Path
import argparse,json,sys
ROOT=Path(__file__).resolve().parents[1]
sys.path.insert(0,str(ROOT))
import numpy as np
from aureole import WorldMemory,freeze,draw,correct
from aureole.core import proposal_from_bound
from aureole.renderer import Scene,VisibilityPrior,receiver_grid,light_grid,unoccluded,physical_table


def run(output,frames=24,side=48):
    if frames<1 or side<2:raise ValueError("Need frames>=1, side>=2")
    output=Path(output);output.mkdir(parents=True,exist_ok=True)
    points=receiver_grid(side,side);lights=light_grid();scene=Scene.create(300)
    prior=VisibilityPrior(ROOT/"models/visibility_prior.npz")
    p=prior(scene.features(points[:,None,:],lights[None,:,:]))
    memory=WorldMemory(len(points),len(lights),"demo-scene-300")
    rng=np.random.default_rng(3101);ids=np.arange(len(points));b=unoccluded(points,lights)
    images={};events=[]
    for frame in range(frames):
        if frame==frames//2:
            scene=scene.changed()  # no notification to memory: deliberate surprise
        v=memory.predict(ids,p)
        s=freeze(b*v[...,None],proposal_from_bound(b,v,memory.trusted(ids),active=True))
        j=draw(s,2,rng);vis=scene.visibility(points[:,None,:],lights[j])
        values=b[np.arange(len(ids))[:,None],j]*vis[...,None]
        result=correct(s,j,values)
        conflicts=memory.commit(ids,j,vis,revise_on_conflict=True)
        events.append({"frame":frame,"conflicting_ray_entries":conflicts,"epoch_after":memory.epoch})
        if frame in {0,max(0,frames//2-1),frames//2,frames-1}:
            images[f"frame_{frame:03d}"]=result.reshape(side,side,3)
    # Reference is generated after online rendering and never supplied to it.
    images["reference_final"]=physical_table(scene,points,lights,b).sum(1).reshape(side,side,3)
    np.savez_compressed(output/"linear_frames.npz",**images)
    memory.save(output/"world_memory.npz")
    import matplotlib
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    fig,axes=plt.subplots(1,len(images),figsize=(3*len(images),3.6))
    for ax,(label,im) in zip(np.atleast_1d(axes),images.items()):
        ax.imshow(np.clip(im,0,1)**(1/2.2),origin="lower")
        ax.set_title(label.replace("_"," "),fontsize=10);ax.axis("off")
    fig.suptitle("AUREOLE-R CPU demo: two fresh shadow rays per receiver / frame",fontsize=13)
    fig.text(.5,.035,"Preview clips negative estimates and applies gamma. Statistical outputs remain linear in the NPZ.",ha="center",fontsize=9)
    fig.tight_layout(rect=(0,.08,1,.92));fig.savefig(output/"demo.png",dpi=160);plt.close(fig)
    report={"frames":frames,"receiver_count":len(points),"emitters":len(lights),"rays":frames*len(points)*2,
            "events":events,"final_mse":float(np.mean((images[f"frame_{frames-1:03d}"]-images["reference_final"])**2)),
            "scope":"small CPU direct-light demo; no SR/FG/game/GPU implementation"}
    (output/"demo.json").write_text(json.dumps(report,indent=2)+"\n")
    print(json.dumps(report,indent=2))

if __name__=="__main__":
    parser=argparse.ArgumentParser();parser.add_argument("--output",default="demo_output")
    parser.add_argument("--frames",type=int,default=24);parser.add_argument("--side",type=int,default=48)
    args=parser.parse_args();run(args.output,args.frames,args.side)