-
-
Save alco/6685248 to your computer and use it in GitHub Desktop.
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
#include <stdlib.h> | |
#include <stdio.h> | |
#include <math.h> | |
typedef int i; //Save space by using 'i' instead of 'int' | |
typedef float f; //Save even more space by using 'f' instead of 'float' | |
//Define a vector class with constructor and operator: 'v' | |
struct v { | |
f x,y,z; // Vector has three float attributes. | |
v operator+(v r){return v(x+r.x,y+r.y,z+r.z);} //Vector add | |
v operator*(f r){return v(x*r,y*r,z*r);} //Vector scaling | |
f operator%(v r){return x*r.x+y*r.y+z*r.z;} //Vector dot product | |
v(){} //Empty constructor | |
v operator^(v r){return v(y*r.z-z*r.y,z*r.x-x*r.z,x*r.y-y*r.x);} //Cross-product | |
v(f a,f b,f c){x=a;y=b;z=c;} //Constructor | |
v operator!(){return *this*(1 /sqrt(*this%*this));} // Used later for normalizing the vector | |
}; | |
i G[]={31768, 33316, 66114, 67138, 65572, 65560, 33792, 30720, 0}; | |
// Random generator, return a float within range [0-1] | |
f R(){return(f)rand()/RAND_MAX;} | |
//The intersection test for line [o,v]. | |
// Return 2 if a hit was found (and also return distance t and bouncing ray n). | |
// Return 0 if no hit was found but ray goes upward | |
// Return 1 if no hit was found but ray goes downward | |
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; | |
//The world is encoded in G, with 9 lines and 19 columns | |
for(i k=19;k--;) //For each columns of objects | |
for(i j=9;j--;) //For each line on that columns | |
if(G[j]&1<<k) { //For this line j, is there a sphere at column i ? | |
// There is a sphere but does the ray hits it ? | |
v p=o+v(-k,3,-j-4); | |
f b=p%d,c=p%p-1,q=b*b-c; | |
// Does the ray hit the sphere ? | |
if(q>0) { | |
//It does, compute the distance camera-sphere | |
f s=-b-sqrt(q); | |
if(s<t && s>.01) | |
// So far this is the minimum distance, save it. And also | |
// compute the bouncing ray vector into 'n' | |
t=s, n=!(p+d*t), m=2; | |
} | |
} | |
return m; | |
} | |
// (S)ample the world and return the pixel color for | |
// a ray passing by point o (Origin) and d (Direction) | |
v S(v o,v d) { | |
f t; | |
v n; | |
//Search for an intersection ray Vs World. | |
i m=T(o,d,t,n); | |
if(!m) // m==0 | |
//No sphere found and the ray goes upward: Generate a sky color | |
return v(.7,.6,1)*pow(1-d.z,4); | |
//A sphere was maybe hit. | |
v h=o+d*t, // h = intersection coordinate | |
l=!(v(9+R(),9+R(),16)+h*-1), // 'l' = direction to light (with random delta for soft-shadows). | |
r=d+n*(n%d*-2); // r = The half-vector | |
//Calculated the lambertian factor | |
f b=l%n; | |
//Calculate illumination factor (lambertian coefficient > 0 or in shadow)? | |
if(b<0||T(h,l,t,n)) | |
b=0; | |
// Calculate the color 'p' with diffuse and specular component | |
f p=pow(l%r*(b>0),99); | |
if(m&1) { //m == 1 | |
h=h*.2; //No sphere was hit and the ray was going downward: Generate a floor color | |
return((i)(ceil(h.x)+ceil(h.y))&1?v(3,1,1):v(3,3,3))*(b*.2+.1); | |
} | |
//m == 2 A sphere was hit. Cast an ray bouncing from the sphere surface. | |
return v(p,p,p)+S(h,r)*.5; //Attenuate color by 50% since it is bouncing (* .5) | |
} | |
// The main function. It generates a PPM image to stdout. | |
// Usage of the program is hence: ./card > erk.ppm | |
i main() { | |
printf("P6 512 512 255 "); // The PPM Header is issued | |
// The '!' are for normalizing each vectors with ! operator. | |
v g=!v(-5.5,-16,0), // Camera direction | |
a=!(v(0,0,1)^g)*.002, // Camera up vector...Seem Z is pointing up :/ WTF ! | |
b=!(g^a)*.002, // The right vector, obtained via traditional cross-product | |
c=(a+b)*-256+g; // WTF ? See https://news.ycombinator.com/item?id=6425965 for more. | |
for(i y=512;y--;) //For each column | |
for(i x=512;x--;) { //For each pixel in a line | |
//Reuse the vector class to store not XYZ but a RGB pixel color | |
v p(13,13,13); // Default pixel color is almost pitch black | |
//Cast 64 rays per pixel (For blur (stochastic sampling) and soft-shadows. | |
for(i r=64;r--;) { | |
// The delta to apply to the origin of the view (For Depth of View blur). | |
v t=a*(R()-.5)*99+b*(R()-.5)*99; // A little bit of delta up/down and left/right | |
// Set the camera focal point v(17,16,8) and Cast the ray | |
// Accumulate the color returned in the p variable | |
p=S(v(17,16,8)+t, //Ray Origin | |
!(t*-1+(a*(R()+x)+b*(y+R())+c)*16) // Ray Direction with random deltas | |
// for stochastic sampling | |
)*3.5+p; // +p for color accumulation | |
} | |
printf("%c%c%c",(i)p.x,(i)p.y,(i)p.z); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment