Array: read out the depth buffer; show it in the readout §05
igc_array.py gains readout_depth() -> the 24-bit Z stored in pixel memory as a depth image (near=bright), i.e. the plane the decoded SENDE z-sweep interpolates. Readout §05 now shows the depth buffer next to the tile footprint, ties the z-decode to a visible array output, and reframes the "remaining work" as numeric reconstruction across regions (the coefficients are already cross-validated). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -161,6 +161,44 @@ class IGCArray:
|
||||
_wword(pix, G_BIT0, C_BITS, gv)
|
||||
_wword(pix, B_BIT0, C_BITS, bv)
|
||||
|
||||
def readout_depth(self, bg=(7, 11, 17)):
|
||||
"""Read the 24-bit z stored in pixel memory back into a depth image (near=bright).
|
||||
This is the plane the SENDE z-sweep interpolates, straight out of pixel memory."""
|
||||
img = bytearray(self.W * self.H * 3)
|
||||
for y in range(self.H):
|
||||
o = y * self.W * 3
|
||||
for x in range(self.W):
|
||||
img[o] = bg[0]; img[o + 1] = bg[1]; img[o + 2] = bg[2]; o += 3
|
||||
# gather the touched z range for contrast
|
||||
zmin, zmax = Z_FAR, 0
|
||||
for t in self.tiles.values():
|
||||
if not t.touched:
|
||||
continue
|
||||
for pix in t.mem:
|
||||
z = _rword(pix, Z_BIT0, Z_BITS)
|
||||
if z != Z_FAR:
|
||||
zmin = min(zmin, z); zmax = max(zmax, z)
|
||||
span = (zmax - zmin) or 1
|
||||
for (tx, ty), t in self.tiles.items():
|
||||
if not t.touched:
|
||||
continue
|
||||
for ly in range(TILE_Y):
|
||||
gy = t.y0 + ly
|
||||
if gy >= self.H:
|
||||
break
|
||||
base = ly << TILE_X_BITS
|
||||
for lx in range(TILE_X):
|
||||
gx = t.x0 + lx
|
||||
if gx >= self.W:
|
||||
break
|
||||
z = _rword(t.mem[base + lx], Z_BIT0, Z_BITS)
|
||||
if z == Z_FAR:
|
||||
continue
|
||||
v = 1.0 - (z - zmin) / span # near = bright
|
||||
o = (gy * self.W + gx) * 3
|
||||
img[o] = int(30 + v * 120); img[o + 1] = int(90 + v * 150); img[o + 2] = int(120 + v * 130)
|
||||
return img
|
||||
|
||||
def readout(self, bg=(7, 11, 17)):
|
||||
"""Read pixel memory back out into an RGB framebuffer (row-major, RGB bytes)."""
|
||||
img = bytearray(self.W * self.H * 3)
|
||||
|
||||
@@ -323,32 +323,37 @@
|
||||
reference rasteriser to within edge anti-aliasing — the array reproduced faithfully.</p>
|
||||
<div class="arr">
|
||||
<figure>
|
||||
<canvas id="tiles" width="500" height="360" aria-label="the object's footprint across the 64x128 tile array"></canvas>
|
||||
<figcaption><b>the object's footprint across the array</b> — 18 of 50 tiles lit,
|
||||
each a 64×128 region of pixel processors</figcaption>
|
||||
<canvas id="depth" width="560" height="500" aria-label="the depth buffer the array computes"></canvas>
|
||||
<figcaption><b>the depth buffer</b>, read straight out of pixel memory — the 24-bit
|
||||
Z plane the <span class="mono">SENDE</span> z-sweep interpolates (near = bright)</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<canvas id="tiles" width="500" height="360" aria-label="the object's footprint across the 64x128 tile array"></canvas>
|
||||
<figcaption><b>the object's footprint</b> — 18 of 50 <b>64×128</b> tiles lit,
|
||||
each a region of pixel processors</figcaption>
|
||||
</figure>
|
||||
<div class="arrinfo">
|
||||
<div class="pmlab">pixel memory · 26 bytes = 208 bits</div>
|
||||
<div class="pmbar">
|
||||
<span class="z">Z · 24b</span><span class="r">R·8</span><span class="g">G·8</span>
|
||||
<span class="b">B·8</span><span class="free">enable + working bits</span>
|
||||
</div>
|
||||
<ul class="mini">
|
||||
<li>three edge trees → the <b>enable register</b> (the inside test)</li>
|
||||
<li>Z / R / G / B are <b>planes</b>, evaluated per pixel by the linear tree</li>
|
||||
<li>z-buffer via <span class="mono">MEM2geMEM2</span>; every write gated by enable</li>
|
||||
<li>output read back out of pixel memory → framebuffer</li>
|
||||
<li><b>validated</b> pixel-faithful to the reference — ~1%, at edges only</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<p class="sub" style="margin-top:16px">What this is <b>not</b>, yet: execution of the compiled
|
||||
<b>micro-code</b> the DMA actually ships (§02, right) — the form the ground and sky take, since
|
||||
they carry no stored vertices. That stream is now partly decoded: the per-region command lists
|
||||
read cleanly, and the SEND payloads turn out to carry the real <b>float coefficients</b>
|
||||
interleaved with a regular bit-serial sweep — so what remains is pinning the control-word fields
|
||||
and running that sweep, not reversing an opaque binary. This section is the array's
|
||||
<b>computational</b> model: the pixels that micro-code produces.</p>
|
||||
<div class="arrinfo" style="margin-top:16px">
|
||||
<div class="pmlab">pixel memory · 26 bytes = 208 bits</div>
|
||||
<div class="pmbar">
|
||||
<span class="z">Z · 24b</span><span class="r">R·8</span><span class="g">G·8</span>
|
||||
<span class="b">B·8</span><span class="free">enable + working bits</span>
|
||||
</div>
|
||||
<ul class="mini">
|
||||
<li>three edge trees → the <b>enable register</b> (the inside test)</li>
|
||||
<li>Z / R / G / B are <b>planes</b>, evaluated per pixel by the linear tree</li>
|
||||
<li>z-buffer via <span class="mono">MEM2geMEM2</span>; every write gated by enable</li>
|
||||
<li>the depth image (left) is that Z plane, read back out of pixel memory</li>
|
||||
<li><b>validated</b> pixel-faithful to the reference — ~1%, at edges only</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p class="sub" style="margin-top:16px">What this is <b>not</b>, yet: a full from-scratch run of
|
||||
the compiled <b>micro-code</b> the DMA ships (§02) — the form the ground and sky take, since they
|
||||
carry no stored vertices. But that stream is now largely decoded: the command lists read cleanly,
|
||||
the <span class="mono">SENDE</span> z-sweep resolves into a regular 4-word instruction, and its
|
||||
coefficients are the same ones driving this depth buffer — the array's inputs are
|
||||
<b>cross-validated against the hardware's own compiled stream</b>. What remains is numeric
|
||||
reconstruction across every region, not reversing an opaque binary.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -636,6 +641,58 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- depth buffer: the same surface, coloured by camera Z (the array's z-plane) ---- */
|
||||
(function(){
|
||||
var sc=document.getElementById('depth'); if(!sc) return;
|
||||
var dx=sc.getContext('2d');
|
||||
var CW=sc.width, CH=sc.height, SS=2, W=CW*SS, H=CH*SS;
|
||||
var XS=GRID.xs, ZS=GRID.zs, R=GRID.rows, NX=XS.length, NZ=ZS.length;
|
||||
var cx=8, cz=-4, cy=0;
|
||||
(function(){var s=0,n=0;for(var j=0;j<NZ;j++)for(var i=0;i<NX;i++){s+=R[j][i][0];n++;}cy=s/n;})();
|
||||
var YAW=40*Math.PI/180, PIT=27*Math.PI/180;
|
||||
var cyw=Math.cos(YAW),syw=Math.sin(YAW),cp=Math.cos(PIT),sp=Math.sin(PIT);
|
||||
function rot(x,y,z){var x2=x*cyw+z*syw,z2=-x*syw+z*cyw;var y2=y*cp-z2*sp,z3=y*sp+z2*cp;return [x2,y2,z3];}
|
||||
var P=[];
|
||||
for(var j=0;j<NZ;j++){P[j]=[];for(var i=0;i<NX;i++){
|
||||
var c=R[j][i]; var p=rot(XS[i]-cx,(c[0]-cy)*1.8,ZS[j]-cz);
|
||||
P[j][i]={X:p[0],Y:p[1],Z:p[2]};
|
||||
}}
|
||||
var mnx=1e9,mxx=-1e9,mny=1e9,mxy=-1e9,mnz=1e9,mxz=-1e9;
|
||||
for(var j=0;j<NZ;j++)for(var i=0;i<NX;i++){var p=P[j][i];
|
||||
if(p.X<mnx)mnx=p.X;if(p.X>mxx)mxx=p.X;if(p.Y<mny)mny=p.Y;if(p.Y>mxy)mxy=p.Y;
|
||||
if(p.Z<mnz)mnz=p.Z;if(p.Z>mxz)mxz=p.Z;}
|
||||
var pad=0.1*W, s=Math.min((W-2*pad)/(mxx-mnx),(H-2*pad)/(mxy-mny));
|
||||
var ox=(W-(mxx-mnx)*s)/2, oy=(H-(mxy-mny)*s)/2, zsp=(mxz-mnz)||1;
|
||||
function SXp(p){return (p.X-mnx)*s+ox;} function SYp(p){return (mxy-p.Y)*s+oy;}
|
||||
var dep=new Float32Array(W*H); dep.fill(-2); var zb=new Float32Array(W*H); for(var k=0;k<W*H;k++)zb[k]=-1e9;
|
||||
function tri(a,b,c){
|
||||
var ax=SXp(a),ay=SYp(a),bx=SXp(b),by=SYp(b),cx2=SXp(c),cy2=SYp(c);
|
||||
var area=(bx-ax)*(cy2-ay)-(cx2-ax)*(by-ay); if(Math.abs(area)<1e-6)return;
|
||||
var x0=Math.max(0,Math.floor(Math.min(ax,bx,cx2))),x1=Math.min(W-1,Math.ceil(Math.max(ax,bx,cx2)));
|
||||
var y0=Math.max(0,Math.floor(Math.min(ay,by,cy2))),y1=Math.min(H-1,Math.ceil(Math.max(ay,by,cy2)));
|
||||
for(var py=y0;py<=y1;py++)for(var px=x0;px<=x1;px++){
|
||||
var w0=((bx-px)*(cy2-py)-(cx2-px)*(by-py))/area;
|
||||
var w1=((cx2-px)*(ay-py)-(ax-px)*(cy2-py))/area; var w2=1-w0-w1;
|
||||
if(w0<-0.004||w1<-0.004||w2<-0.004)continue;
|
||||
var z=w0*a.Z+w1*b.Z+w2*c.Z, idx=py*W+px;
|
||||
if(z>zb[idx]){zb[idx]=z; dep[idx]=(z-mnz)/zsp;}
|
||||
}
|
||||
}
|
||||
for(var j=0;j<NZ-1;j++)for(var i=0;i<NX-1;i++){
|
||||
var a=P[j][i],b=P[j][i+1],c=P[j+1][i],d=P[j+1][i+1]; tri(a,b,c); tri(b,d,c);
|
||||
}
|
||||
var img=dx.createImageData(CW,CH), dd=img.data;
|
||||
for(var y=0;y<CH;y++)for(var xx=0;xx<CW;xx++){
|
||||
var acc=0,cnt=0;
|
||||
for(var yy=0;yy<SS;yy++)for(var xs2=0;xs2<SS;xs2++){var v=dep[(y*SS+yy)*W+(xx*SS+xs2)];if(v>=0){acc+=v;cnt++;}}
|
||||
var o=(y*CW+xx)*4;
|
||||
if(cnt>0){var vv=1-acc/cnt,cov=cnt/(SS*SS); // near = bright
|
||||
dd[o]=30+vv*120; dd[o+1]=90+vv*150; dd[o+2]=120+vv*130; dd[o+3]=Math.round(cov*255);}
|
||||
else dd[o+3]=0;
|
||||
}
|
||||
dx.putImageData(img,0,0);
|
||||
})();
|
||||
|
||||
/* ---- IGC tile footprint: which 64x128 tiles the array lit for the object ---- */
|
||||
var TILES={ntx:10,nty:5,touched:[[0,2],[1,1],[1,2],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3],[4,1],[4,2],[4,3],[5,1],[5,2],[6,1],[6,2],[7,1],[8,1]]};
|
||||
(function(){
|
||||
|
||||
Reference in New Issue
Block a user