Skip to content

Instantly share code, notes, and snippets.

@Flafla2
Last active March 22, 2019 01:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Flafla2/d2f44c9e5e5a0ff13e6071fb782daa38 to your computer and use it in GitHub Desktop.
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"
// 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);
} //
#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