Last active
March 22, 2019 01:15
-
-
Save Flafla2/d2f44c9e5e5a0ff13e6071fb782daa38 to your computer and use it in GitHub Desktop.
Modified version of Pixar's postcard renderer. Runs 4 times faster and says "HIRE ME" instead of "PIXAR"
This file contains hidden or 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
// pixar.cpp | |
// Ran through clang-format, then commented | |
// Also changed text to "HIRE ME" and used fork() | |
// to have 4 child processes for easy multithreading | |
// | |
// Original by Andrew Kensler | |
// Edits by Adrian Biagioli | |
#include <stdlib.h> // card > pixar.ppm | |
#include <stdio.h> | |
#include <math.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
// Make return / operator / float / int shorter to type | |
#define R return | |
#define O operator | |
typedef float F; | |
typedef int I; | |
// Vector class | |
struct V { | |
F x, y, z; | |
// useful constructors | |
V(F v = 0) { x = y = z = v; } | |
V(F a, F b, F c = 0) { | |
x = a; | |
y = b; | |
z = c; | |
} | |
V O + (V r) { R V(x + r.x, y + r.y, z + r.z); } // add == + | |
V O *(V r) { R V(x * r.x, y * r.y, z * r.z); } // mul == * | |
F O % (V r) { R x *r.x + y *r.y + z *r.z; } // dot == % | |
V O !() { R *this *(1 / sqrtf(*this % *this)); }// 1/norm == ! | |
}; | |
// min | |
F L(F l, F r) { R l < r ? l : r; } | |
// rand float between 0 and 1 | |
F U() { R(F) rand() / RAND_MAX; } | |
// returns max(all coords of (p-l, h-p)) | |
F B(V p, V l, V h) { | |
l = p + l * -1; | |
h = h + p * -1; | |
R - L(L(L(l.x, h.x), L(l.y, h.y)), L(l.z, h.z)); | |
} | |
// Calculates scene distance field and material | |
F S(V p, I &m) { | |
F d = 1e9; | |
V f = p; | |
// clamp z value to zero, this is because the distance field for the text is done in 2D first | |
f.z = 0; | |
// This is a line representation. Points are encoded in each character pair in l[] (XYXYXY....) | |
// The encoding is: for i'th coordinate x, l[i] = 2 * x + 79 (in ASCII) | |
// The 79 is to make all chars readable on a card ;) | |
char l[] = "3O3_3W7W7O7_=O=_;O?O;_?_COC_CWGWC_G_EWKOOOO_OWSWOOSOO_S_YOY_Y_]O]Oa_aOa_eOe_eWiWeOiOe_i_"; | |
for (I i = 0; i < 88; i += 4) { | |
V b = V(l[i] - 79, l[i + 1] - 79) * .5, // point 1 | |
e = V(l[i + 2] - 79, l[i + 3] - 79) * .5 + b * -1, // vector point 2->1 | |
// Distance to a line in 2-space | |
// V = Project vector (point1 - f, ie vector f->point1) onto e | |
// V is clamped to 0 if in opposite directions | |
// Then, (f - V) is the closest point on the line. | |
// o is set to f - V, the vector from f to the closest point on the line | |
o = f + (b + e * L(-L((b + f * -1) % e / (e % e), 0), 1)) * -1; | |
d = L(d, o % o); // record smallest (squared) distance out of all lines, with eps | |
} | |
d = sqrtf(d); // square dist -> dist | |
// This is the semicircle representation, used here for the "R" | |
// Calculates the distance to a right facing cemicircle (backwards C) in 2-space | |
V o = f + V(-4, 6) * -1; // curve centered at (-4, 6) | |
d = L(d, o.x > 0 ? fabsf(sqrtf(o % o) - 2) /*radius 2*/ | |
// I think this to render "caps" at the end of curves | |
: (o.y += o.y > 0 ? -2 : 2, sqrtf(o % o))); | |
// Distance field tomfoolery for text | |
// Change side roundness, extrude out and make it a little round in z | |
d = powf(powf(d, 8) + powf(p.z, 8), .125) - .5; | |
// Return text as default material | |
m = 1; | |
// Calculates if we have hit a wall | |
F r = L( | |
-L(B(p, V(-30, -.5, -30), V(30, 18, 30)), | |
B(p, V(-25, 17, -25), V(25, 20, 25))), | |
// Here's where the fmod of the ceiling happens | |
B(V(fmodf(fabsf(p.x), 8), p.y, p.z), V(1.5, 18.5, -25), V(6.5, 20, 25))); | |
// Hack: if the walls are closer than the text then assume we | |
// will hit the walls -- depends on the scene! | |
if (r < d) | |
d = r, m = 2; | |
// Same hack: if we are closer to the sky than everything else | |
// then assume we will hit the sky | |
F s = 19.9 - p.y; | |
if (s < d) | |
d = s, m = 3; | |
R d; | |
} | |
// Samples the scene for 100 units | |
// Does distance field raymarching | |
I M(V o, V d, V &h, V &n) { | |
I m, s = 0; | |
F t = 0, c; | |
for (; t < 100; t += c) // march by distance field result | |
if ((c = S(h = o + d * t, m)) < .01 || ++s > 99) | |
R n = !V(S(h + V(.01, 0), s) - c, // Loads the gradient of distance field | |
S(h + V(0, .01), s) - c, // (this is the normal of surface at this point) | |
S(h + V(0, 0, .01), s) - c), | |
m; | |
// Neat, apparently you can do this: | |
// https://stackoverflow.com/questions/32094189/comma-separated-return-arguments-in-c-function | |
// sets n to the normal at sample point h and returns material (passed via S) | |
R 0; | |
} | |
// This is main sampling fn given ray origin and dir | |
V T(V o, V d) { | |
// t = transmission, goes down on hitting something | |
// n = normal of point from distance field | |
// h = point on distance field | |
// r = integrated color | |
V h, n, r, t = 1, l(!V(.6, .6, 1)); | |
for (I b = 3; b--;) { // 3 light bounces | |
I m = M(o, d, h, n); // sample SDF | |
if (!m) | |
break; | |
//Reflective | |
if (m == 1) { | |
d = d + n * (n % d * -2); | |
o = h + d * .1; | |
t = t * .2; | |
} | |
//Diffuse | |
if (m == 2) { | |
F i = n % l, p = 6.283185 * U(), c = U(), s = sqrtf(1 - c), | |
g = n.z < 0 ? -1 : 1, u = -1 / (g + n.z), v = n.x * n.y * u; | |
d = V(v, g + n.y * n.y * u, -n.y) * (cosf(p) * s) + | |
V(1 + g * n.x * n.x * u, g * v, -g * n.x) * (sinf(p) * s) + | |
n * sqrtf(c); | |
o = h + d * .1; | |
t = t * .2; | |
// If wall bounced off of sky pixel, treat it like sunlight | |
// A bit hacky, but a cheap way to get yellow walls and blue sky | |
// Also assumes 0 contribution from other wall pixels and | |
if (i > 0 && M(h + n * .1, l, h, n) == 3) | |
r = r + t * V(500, 466, 100) * i; | |
} | |
//Directly hit an outside pixel | |
//Return generic sky blue | |
if (m == 3) { | |
r = r + t * V(50, 80, 100); | |
break; | |
} | |
} | |
R r; | |
} | |
I main() { | |
I w = 960, h = 540, s = 16; | |
V e(-22, 5, 25), | |
g = !(V(-3, 4, 0) + e * -1), | |
l = !V(g.z, 0, -g.x) * (1. / w), | |
u(g.y * l.z - g.z * l.y, g.z * l.x - g.x * l.z, g.x * l.y - g.y * l.x); | |
// Dumb os-level hack to get shared memory between child processes | |
// I would never do this in real life but fork() is fewer chars than | |
// pthread_create()... and fork()'s return value lets us easily condition | |
// on each process. PROT_READ|PROT_WRITE lets us read/write to this memory | |
// and MAP_ANON|MAP_SHARED lets us share the memory between the 4 forked processes. | |
char *b = (char*)mmap(0,w*h*3,PROT_READ|PROT_WRITE,MAP_ANON|MAP_SHARED,-1,0); | |
// Forks into 3 child processes to speed up rendering on 4core machine | |
// 1st bit (LSB): if 2nd fork parent | |
// 2nd bit (MSB): if 1st fork parent | |
char f = 2*(!!fork())+(!!fork()); // !!a is the same as (a == 0 ? 0 : 1) | |
for (I y = h; y--;) | |
for (I k = w/4; k--;) { | |
V c; I x=k+f*w/4; | |
for (I p = s; p--;) | |
c = c + T(e, !(g + l * (x - w / 2 + U()) + u * (y - h / 2 + U()))); | |
c = c * (1. / s) + 14. / 241; | |
V o = c + 1; | |
c = V(c.x / o.x, c.y / o.y, c.z / o.z) * 255; | |
I i = 3*(w*y+x); | |
b[i] =(I)c.z; | |
b[i+1]=(I)c.y; | |
b[i+2]=(I)c.x; | |
} | |
// Wait for child processes to finish if this fork is a parent | |
if(f&1) wait(0); | |
if(f&2) wait(0); | |
// Die if we are a child process (ie not the original parent) | |
if((~f)&3) R 0; | |
// Print out the .ppm file | |
printf("P6 %d %d 255 ", w, h); | |
for(I c = w*h*3; c--;) | |
printf("%c", b[c]); | |
// Free anonymous memory that we alloc'd earlier | |
// (important! idk if this gets freed otherwise, it's up to the OS lol) | |
munmap(b,w*h*3); | |
} // |
This file contains hidden or 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
#include <stdlib.h> // card > adrian.ppm | |
#include <stdio.h> // based on card by Andrew Kensler | |
#include <math.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
#define R return | |
#define O operator | |
typedef float F;typedef int I;struct V{F x,y,z;V(F v=0){x=y=z=v;}V(F a,F b,F | |
c=0){x=a;y=b;z=c;}V O+(V r){R V(x+r.x,y+r.y,z+r.z);}V O*(V r){R V(x*r.x,y*r. | |
y,z*r.z);}F O%(V r){R x*r.x+y*r.y+z*r.z;}V O!(){R*this*(1/sqrtf(*this%*this) | |
);}};F L(F l,F r){R l<r?l:r;}F U(){R(F)rand()/RAND_MAX;}F B(V p,V l,V h){l=p | |
+l*-1;h=h+p*-1;R-L(L(L(l.x,h.x),L(l.y,h.y)),L(l.z,h.z));}F S(V p,I&m){F d=1\ | |
e9;V f=p;f.z=0;char l[]="3O3_3W7W7O7_=O=_;O?O;_?_COC_CWGWC_G_EWKOOOO_OWSWOO\ | |
SOO_S_YOY_Y_]O]Oa_aOa_eOe_eWiWeOiOe_i_";for(I i=0;i<88;i+=4){V b=V(l[i]-79,l | |
[i+1]-79)*.5,e=V(l[i+2]-79,l[i+3]-79)*.5+b*-1,o=f+(b+e*L(-L((b+f*-1)%e/(e%e) | |
,0),1))*-1;d=L(d,o%o);}d=sqrtf(d);V o=f+V(-4, 6) * -1;d=L(d,o.x>0?fabsf(sqr\ | |
tf(o%o)-2):(o.y+=o.y>0?-2:2,sqrtf(o%o)));d=powf(powf(d,8)+powf(p.z,8),.125)- | |
.5;m=1;F r=L(-L(B(p,V(-30,-.5,-30),V(30,18,30)),B(p,V(-25,17,-25),V(25,20,25 | |
))),B(V(fmodf(fabsf(p.x),8),p.y,p.z),V(1.5,18.5,-25),V(6.5,20,25)));if(r<d)d | |
=r,m=2;F s=19.9-p.y;if(s<d)d=s,m=3;R d;}I M(V o,V d,V&h,V&n){I m,s=0;F t=0,c | |
;for(;t<100;t+=c)if((c=S(h=o+d*t,m))<.01||++s>99)R n=!V(S(h+V(.01,0),s)-c,S( | |
h+V(0,.01),s)-c,S(h+V(0,0,.01),s)-c),m;R 0;}V T(V o,V d){V h,n,r,t=1,l(!V(.6 | |
,.6,1));for(I b=3;b--;){I m=M(o,d,h,n);if(!m)break;if(m==1){d=d+n*(n%d*-2);o | |
=h+d*.1;t=t*.2;}if(m==2){F i=n%l,p=6.283185*U(),c=U(),s=sqrtf(1-c),g=n.z<0?- | |
1:1,u=-1/(g+n.z),v=n.x*n.y*u;d=V(v,g+n.y*n.y*u,-n.y)*(cosf(p)*s)+V(1+ g*n.x* | |
n.x*u,g*v,-g*n.x)*(sinf(p)*s)+n*sqrtf(c);o=h+d*.1;t=t*.2;if(i>0&&M(h+n*.1,l, | |
h,n)==3)r=r+t*V(500,466,100)*i;}if(m==3){r=r+t*V(50,80,100);break;}}R r;}I \ | |
main(){I w=960,h=540,s=16;V e(-22,5,25),g=!(V(-3,4,0)+e*-1),l=!V(g.z,0,-g.x) | |
*(1./w),u(g.y*l.z-g.z*l.y,g.z*l.x-g.x*l.z,g.x*l.y-g.y*l.x);char*b=(char*)mm\ | |
ap(0,w*h*3,PROT_READ|PROT_WRITE,MAP_ANON|MAP_SHARED,-1,0);char f=2*(!!fork() | |
)+(!!fork());for(I y=h;y--;)for(I k=w/4;k--;){V c;I x=k+f*w/4;for(I p=s;p--; | |
)c=c+T(e,!(g+l*(x-w/2+U())+u*(y-h/2+U())));c=c*(1./s)+14./241;V o=c+1;c=V(c. | |
x/o.x,c.y/o.y,c.z/o.z)*255;I i=3*(w*y+x);b[i]=(I)c.z;b[i+1]=(I)c.y;b[i+2]=(I | |
)c.x;}if(f&1)wait(0);if(f&2)wait(0);if((~f)&3)R 0;printf("P6 %d %d 255 ",w,h | |
);for(I c=w*h*3;c--;)printf("%c",b[c]);munmap(b,w*h*3);} // Adrian Biagioli |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment