Last active
March 8, 2020 06:25
-
-
Save ohAitch/187fd864cd9976b230e7c123a724ac10 to your computer and use it in GitHub Desktop.
Mildly incremental ray tracer; run at https://tbfleming.github.io/cib/#gist=187fd864cd9976b230e7c123a724ac10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Adapted from https://fabiensanglard.net/rayTracing_back_of_business_card/ | |
#include <stdlib.h> // card > aek.ppm | |
#include <stdio.h> | |
#include <math.h> | |
#include <time.h> | |
typedef int i;typedef float f;struct v{ | |
f x,y,z;v operator+(v r){return v(x+r.x | |
,y+r.y,z+r.z);}v operator*(v r){return | |
v(x*r.x,y*r.y,z*r.z);}v operator*(f r){return | |
v(x*r,y*r,z*r);}f operator%(v r){return | |
x*r.x+y*r.y+z*r.z;}v(){}v operator^(v r | |
){return v(y*r.z-z*r.y,z*r.x-x*r.z,x*r. | |
y-y*r.x);}v(f a,f b,f c){x=a;y=b;z=c;}v | |
operator!(){return*this*(1/sqrt(*this%* | |
this));}};i G[]={247951,133265,67729,36623,18433,247809,2062}; | |
f R(){return(f)rand()/RAND_MAX;} | |
static i WH = 512; | |
static i GAP = 51; | |
static i RAYS = 1; | |
static i gap = 0; | |
static i iters = 0; | |
static v letr(0,0,4); | |
void regap(){GAP = | |
// WH*WH*RAYS <= 1<<16 ? 7 : | |
WH*WH*RAYS <= 1<<17 ? 21 : | |
WH*WH*RAYS <= 1<<20 ? 51 : | |
WH*WH*RAYS <= 1<<23 ? 171 : | |
/* else */ 667 ;} | |
extern "C" void scoot(f scoot){letr = v(0,0,scoot); iters=0;RAYS=1;regap();} | |
i T(v o,v d,f&t,v&n){t=1e9;i m=0;f p=-o.z/d.z; | |
if(.01<p)t=p,n=v(0,0,1),m=1; | |
for(i k=19;k--;)for(i j=7;j--;)if(G[j]&1<<k){ | |
v p=o+(v(k,0,j)+letr)*-1;f b=p%d,c=p%p-.9,q=b*b-c; | |
if(q>0){f s=-b-sqrt(q); | |
if(s<t&&s>.01)t=s,n=!(p+d*t),m=2+(1&(j^k));}} | |
return m;} | |
v S(v o,v d){f t;v n;i m=T(o,d,t,n);if(!m)return | |
v(.7,.6,1)*1*pow(1-d.z,4); | |
v h=o+d*t,l=!(v(9+R(),9+R(),16)+h*-1),r=d+n*(n%d*-2);f b=l%n; | |
if(b<0||T(h,l,t,n))b=0;f p=pow(l%r*(b>0),99); | |
if(m<2){h=h*.2;return( | |
(i)(ceil(h.x)+ceil(h.y))&1?v(3,1,1):v(3,3,3))*(b*.2+.1);} | |
return v(1,1,1)*p+S(h,r)*.5;} | |
extern "C" void reset(i wh){WH=wh;RAYS=1;regap(); iters=0;} | |
extern "C" i gaps(){return GAP;} | |
i main(){ | |
if(!iters) iters=GAP+1; | |
gap+=2*384+1; | |
printf("%d\t", gap); | |
// printf("%d\n", RAND_MAX); return 0; | |
// printf("P6 256 256 255 "); | |
v g=!v | |
(-6,-16,0),a=!(v(0,0,1)^g)*(1./WH),b=!(g^a | |
)*(1./WH),c=(a+b)*-(WH*.5)+g; | |
for(i y=WH;y--;)for(i x=WH;x--;){if(gap--) continue; gap = GAP; | |
v p(0,0,0); | |
for(i r=RAYS;r--;){v t=(a*(R()-.5)*99+b*(R()-.5)*99)*fmax(1.,log2(RAYS)/3.)*(WH/512.); | |
p=S(v(16,16,8)+t,!(t*-1+(a*(R()+x)+b*(y+R())+c)*16))*(64/RAYS)*3.5+p;} | |
printf("%d\t",(0xff&(i)p.x) + 0x100*(0xff&(i)p.y) + 0x10000*(0xff&(i)p.z)); | |
// printf("%d %d %d\t",0xff&(i)p.x,0xff&(i)p.y,0xff&(i)p.z); | |
}printf("\n"); | |
if(!--iters) { | |
if(RAYS>=64) puts("\n"); | |
else {printf("%d\n", RAYS); RAYS*=2; regap();} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%init-scripts% | |
<style> | |
html, | |
body { | |
width: 100%; | |
height: 100%; | |
overflow: hidden; | |
} | |
div { | |
position: absolute; | |
left: 10px; | |
right: 10px; | |
top: 10px; | |
bottom: 10px; | |
padding: 10px; | |
background-color: aliceblue; | |
overflow: auto; | |
} | |
pre { | |
margin: 0px; | |
} | |
</style> | |
<div> | |
<button onclick="window.rr()">go</button> | |
<button onclick="clearTimeout(window.todo)">stop</button> | |
<br>Size: | |
<input type=radio onchange="rr()" name=dim value=256>256</input> | |
<input type=radio onchange="rr()" name=dim value=384>384</input> | |
<input type=radio onchange="rr()" name=dim value=512 checked>512</input> | |
<input type=radio onchange="rr()" name=dim value=768>768</input> | |
<br> Letters up <input type=range id=letr min=-100 max=200 value=40 | |
oninput="rp({letter:this.value/10})" /> | |
<output id=letrOut>4.0</output> | |
<br> | |
<canvas id=out></canvas> | |
<pre id='consoole'><br></pre> | |
</div> | |
<script src=https://unpkg.com/osc-js@2.0.4/lib/osc.min.js ></script> | |
<!-- <script> | |
osc = new OSC() | |
osc.open() | |
osc.on("*",({address, args}) => { | |
// console.log(address, ...args) | |
window.rp({letter:30*args[0]-10}) | |
}) | |
</script> --> | |
<script> | |
'use strict'; | |
let n = 0; | |
let t0 = Date.now() | |
let t = t0 | |
let out = document.getElementById('out'); | |
out.width = out.height = 768 | |
let compose = out.getContext("2d"); | |
let scratch = new OffscreenCanvas(out.width, out.height) | |
let draw = scratch.getContext("2d"); | |
let raw = new OffscreenCanvas(out.width, out.height).getContext("2d"); | |
out.width = out.height = 512 | |
window.rp = ({letter})=> { | |
consoole.textContent = consoole.textContent.replace(/\n[.\n]*/g,'') | |
letr.value = letter*10; | |
letrOut.value = letter.toFixed(1) | |
let dim = out.width | |
if(Date.now()<window.rp.throttle){ | |
clearTimeout(window.rp.timeout) | |
return window.rp.timeout = setTimeout( | |
()=> window.rp({letter}), window.rp.throttle-Date.now() | |
) | |
} | |
window.rp.throttle = Date.now()+dim/15 | |
raw.save(); { | |
raw.globalCompositeOperation = "multiply" | |
raw.fillStyle = "#f3f3f3" | |
raw.fillRect(0,0,dim,dim) | |
}; raw.restore() | |
n=0, t0 = Date.now(), clearTimeout(window.todo) | |
wasmExports.scoot(letr.value/10) | |
wasmExports.main() | |
} | |
let $ = document.querySelector.bind(document) | |
window.rr = ()=> { | |
consoole.textContent = '' | |
let dim = +$('[name="dim"]:checked').value | |
n=0, t0 = Date.now(), clearTimeout(window.todo) | |
let ddim = out.width | |
out.width = out.height = dim | |
raw.width = raw.height = scratch.width = scratch.height = out.width | |
if(dim!=ddim) raw.clearRect(0,0,dim,dim) | |
wasmExports.reset(dim) | |
wasmExports.main() | |
} | |
let premultiply = new OffscreenCanvas(out.width, out.height).getContext("2d") | |
let consoole = document.getElementById('consoole'); | |
emModule.printErr = emModule.print = msg => { | |
try { | |
if(!msg) return clearTimeout(window.todo) | |
if(msg.length<100){ | |
if(msg==+msg){consoole.textContent += ` ${msg}rpp\n`; n=0} | |
else { console.warn(msg)} | |
return | |
} | |
let tt = Date.now() | |
consoole.textContent = consoole.textContent.replace( | |
/.*$/, `${(1000/(tt-t))|0}fps ${n++} ${(t-t0)/1000}s` | |
) | |
t=tt | |
// console.log(msg) | |
draw.globalCompositeOperation = 'copy' | |
draw.fillStyle = `#131313` | |
draw.fillRect(0,0,out.width,out.height) | |
let buf = new Uint32Array( | |
raw.getImageData(0,0,out.width,out.height).data.buffer | |
) | |
let i = null; | |
let gap = wasmExports.gaps() | |
msg.split('\t').forEach(s => { | |
if(i==null) return i=+s | |
buf[i]=0xff*0x1000000+(+s); i+=1+gap | |
// let [r,g,b]= s.split(' ').map(n=>+n) | |
// buf[i]=0xff*0x1000000+(b*0x10000+g*0x100+r); i+=1+gap | |
}) | |
raw.putImageData( | |
new ImageData( | |
new Uint8ClampedArray(buf.buffer) | |
,out.width,out.height) | |
,0,0) | |
draw.globalCompositeOperation = 'lighter' | |
draw.drawImage(raw.canvas,0,0) | |
draw.globalCompositeOperation = 'destination-in' | |
draw.drawImage(raw.canvas,0,0) | |
{ | |
let empty = (gap-n)/gap | |
compose.filter = `blur(${(1+8*empty)*(out.height/256)}px)` | |
compose.globalCompositeOperation = 'lighten' | |
{ | |
compose.globalCompositeOperation = 'multiply' | |
compose.fillStyle = `#444` | |
compose.fillRect(0,0,out.width,out.height) | |
} | |
compose.globalCompositeOperation = 'lighten' | |
compose.drawImage(draw.canvas,0,0) | |
compose.filter = "none" | |
} | |
compose.globalCompositeOperation = 'source-over' | |
compose.drawImage(scratch,0,0) | |
clearTimeout(window.todo) | |
window.todo=setTimeout(()=> wasmExports.main(), 2) | |
} catch(e){ | |
console.warn(e) | |
debugger | |
} | |
}; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment