Last active
January 30, 2021 11:00
-
-
Save Humayung/3d28a713d6d9668cc5b06706c3abea47 to your computer and use it in GitHub Desktop.
Ray Tracing
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
final int WIDTH = 683; | |
final int HEIGHT= 384; | |
public void settings(){ | |
size(WIDTH, HEIGHT, P2D); | |
} | |
public void printf(Object o){ | |
System.out.println(o); | |
} | |
Ball[] balls = new Ball[3]; | |
public void setup(){ | |
balls[0] = new Ball(new float[]{0, 0, 0}, 1, new Color(1, 1, 1), 0.9); | |
balls[1] = new Ball(new float[]{-3, 0, 0}, 0.5, new Color(0.3, 0.6, 0.9), 0.7); | |
balls[2] = new Ball(new float[]{0, -3, 0}, 0.3, new Color(1, 0.2, 0), 0.5); | |
} | |
float alfa = 0, beta = PI/2, r = 1.9; | |
public void draw(){ | |
loadPixels(); | |
Camera cam = new Camera(r,alfa,beta); | |
for(int i=0;i<HEIGHT;i++){ | |
for(int j=0;j<WIDTH;j++){ | |
float[] origin ={ | |
cam.x, | |
cam.y, | |
cam.z | |
}; | |
float[] unit= { | |
-((float)(j-WIDTH/2)+0.5)/(float)(WIDTH/2), | |
((float)(i-HEIGHT/2)+0.5)/(float)(WIDTH/2), | |
-1 | |
}; | |
transformVector(unit, cam.matrix); | |
unit[0] -= cam.x; | |
unit[1] -= cam.y; | |
unit[2] -= cam.z; | |
normalize(unit); | |
Color luminance = cam.rayTrace(origin,unit,balls,1,0.3,5).mul(256); | |
pixels[i * width + j] = color((int)luminance.red, (int)luminance.green, (int)luminance.blue); | |
} | |
} | |
updatePixels(); | |
beta = map(mouseY, 0, width, -PI, PI); | |
alfa = map(mouseX, 0, height, -PI, PI); | |
} | |
public void mouseWheel(MouseEvent e){ | |
int amt = e.getCount(); | |
r += amt; | |
} | |
class Ball { | |
float[] center; | |
float radius; | |
Color col; //on the interval from 0 (dark) to 1 (light) | |
float coeff; | |
Ball(float[] center, float radius, Color col, float coeff){ | |
this.center = center; | |
this.radius = radius; | |
this.col = col; | |
this.coeff = coeff; | |
} | |
} | |
class Camera { | |
float x,y,z; | |
float[] matrix = new float[16]; | |
float[] inv = new float[16]; | |
public Camera(float r, float alfa, float beta) { | |
float a = sin(alfa), b = cos(alfa), c = sin(beta), d = cos(beta); | |
x=r*b*d; | |
y=r*a*d; | |
z=r*c; | |
//matrix | |
matrix[3]=matrix[7]=matrix[11]=0; | |
matrix[15]=1; | |
//x | |
matrix[0]=-a; | |
matrix[1]=b; | |
matrix[2]=0; | |
//y | |
matrix[4]=b*c; | |
matrix[5]=a*c; | |
matrix[6]=-d; | |
//z | |
matrix[8]=b*d; | |
matrix[9]=a*d; | |
matrix[10]=c; | |
matrix[12]=x; | |
matrix[13]=y; | |
matrix[14]=z; | |
//invert | |
inv = invert(matrix); | |
} | |
Color rayTrace(float[] origin,float[] unit, Ball[] balls, float altitude, float coeff, int limit){ | |
float distanceToPlane =- (origin[2] + altitude) / unit[2]; //this is signed distance | |
int index = -1; | |
float distance = 0; | |
for(int i=0;i < balls.length;i++) { | |
float[] diff = diff(origin, balls[i].center); | |
float discriminant = dot(unit, diff) * dot(unit, diff) + balls[i].radius * balls[i].radius - dot(diff, diff); | |
if (discriminant < 0) continue; | |
distance =- dot(unit, diff) - sqrt(discriminant); | |
if (distance<=0) continue; | |
index = i; | |
break; | |
} | |
if (index == -1){ | |
if(unit[2] > 0){ | |
return new Color(0, 0, 0); | |
} else { | |
float | |
tx = origin[0] + distanceToPlane * unit[0], | |
ty = origin[1] + distanceToPlane * unit[1]; | |
float shade = clamp(1 / (1 + distanceToPlane / 10),0,1); | |
Color col = new Color(shade, shade, shade); | |
float[] origin2 = { | |
origin[0] + distanceToPlane * unit[0], | |
origin[1] + distanceToPlane * unit[1], | |
origin[2] + distanceToPlane * unit[2] | |
}; | |
float[] unit2 ={ | |
unit[0], | |
unit[1], | |
-unit[2] | |
}; | |
if( (int)(floor(tx) + floor(ty)) % 2 == 0) | |
return col.mul(1-coeff).add(rayTrace(origin2,unit2,balls,altitude,coeff,limit-1).mul(coeff)); | |
else | |
return new Color(0, 0, 0); | |
} | |
} | |
// Ray hit the ground | |
if (unit[2] < 0 && distance > distanceToPlane){ | |
float | |
tx=origin[0]+distanceToPlane*unit[0], | |
ty=origin[1]+distanceToPlane*unit[1]; | |
float checker = (int)(floor(tx)+floor(ty))%2; | |
return new Color(checker, checker, checker); | |
} | |
//ray hit a ball | |
float[] origin2 = new float[]{ | |
origin[0] + unit[0] * distance, | |
origin[1] + unit[1] * distance, | |
origin[2] + unit[2] * distance | |
}; | |
float[] normal = diff(origin2, balls[index].center); | |
normalize(normal); | |
float k = 2 * dot(unit, normal); | |
scale(normal, k); | |
float[] unit2 = diff(unit, normal); | |
if (limit == 0) return balls[index].col; | |
return balls[index].col.mul(1-balls[index].coeff).add(rayTrace(origin2,unit2,balls,altitude,coeff,limit-1).mul(balls[index].coeff)); | |
} | |
} | |
class Color { | |
float red; | |
float green; | |
float blue; | |
Color(float red, float green, float blue){ | |
this.red = red; | |
this.green = green; | |
this.blue = blue; | |
} | |
Color mul(float f){ | |
return new Color(this.red * f, | |
this.green * f, | |
this.blue * f); | |
} | |
Color add(float k){ | |
return | |
new Color(this.red + k, | |
this.green + k, | |
this.blue + k); | |
} | |
Color add(Color other){ | |
return new Color(this.red + other.red, | |
this.green + other.green, | |
this.blue + other.blue); | |
} | |
} | |
public static void transformVector(float[] vec, final float[] m){ | |
float tx=vec[0]*m[0]+vec[1]*m[4]+vec[2]*m[8]+m[12], | |
ty=vec[0]*m[1]+vec[1]*m[5]+vec[2]*m[9]+m[13], | |
tz=vec[0]*m[2]+vec[1]*m[6]+vec[2]*m[10]+m[14]; | |
vec[0]=tx; | |
vec[1]=ty; | |
vec[2]=tz; | |
} | |
public static float[] invert(final float[] matrix){ | |
float[] inv = new float[16]; | |
float det; | |
int i; | |
inv[0] = matrix[5] * matrix[10] * matrix[15] - | |
matrix[5] * matrix[11] * matrix[14] - | |
matrix[9] * matrix[6] * matrix[15] + | |
matrix[9] * matrix[7] * matrix[14] + | |
matrix[13] * matrix[6] * matrix[11] - | |
matrix[13] * matrix[7] * matrix[10]; | |
inv[4] = -matrix[4] * matrix[10] * matrix[15] + | |
matrix[4] * matrix[11] * matrix[14] + | |
matrix[8] * matrix[6] * matrix[15] - | |
matrix[8] * matrix[7] * matrix[14] - | |
matrix[12] * matrix[6] * matrix[11] + | |
matrix[12] * matrix[7] * matrix[10]; | |
inv[8] = matrix[4] * matrix[9] * matrix[15] - | |
matrix[4] * matrix[11] * matrix[13] - | |
matrix[8] * matrix[5] * matrix[15] + | |
matrix[8] * matrix[7] * matrix[13] + | |
matrix[12] * matrix[5] * matrix[11] - | |
matrix[12] * matrix[7] * matrix[9]; | |
inv[12] = -matrix[4] * matrix[9] * matrix[14] + | |
matrix[4] * matrix[10] * matrix[13] + | |
matrix[8] * matrix[5] * matrix[14] - | |
matrix[8] * matrix[6] * matrix[13] - | |
matrix[12] * matrix[5] * matrix[10] + | |
matrix[12] * matrix[6] * matrix[9]; | |
inv[1] = -matrix[1] * matrix[10] * matrix[15] + | |
matrix[1] * matrix[11] * matrix[14] + | |
matrix[9] * matrix[2] * matrix[15] - | |
matrix[9] * matrix[3] * matrix[14] - | |
matrix[13] * matrix[2] * matrix[11] + | |
matrix[13] * matrix[3] * matrix[10]; | |
inv[5] = matrix[0] * matrix[10] * matrix[15] - | |
matrix[0] * matrix[11] * matrix[14] - | |
matrix[8] * matrix[2] * matrix[15] + | |
matrix[8] * matrix[3] * matrix[14] + | |
matrix[12] * matrix[2] * matrix[11] - | |
matrix[12] * matrix[3] * matrix[10]; | |
inv[9] = -matrix[0] * matrix[9] * matrix[15] + | |
matrix[0] * matrix[11] * matrix[13] + | |
matrix[8] * matrix[1] * matrix[15] - | |
matrix[8] * matrix[3] * matrix[13] - | |
matrix[12] * matrix[1] * matrix[11] + | |
matrix[12] * matrix[3] * matrix[9]; | |
inv[13] = matrix[0] * matrix[9] * matrix[14] - | |
matrix[0] * matrix[10] * matrix[13] - | |
matrix[8] * matrix[1] * matrix[14] + | |
matrix[8] * matrix[2] * matrix[13] + | |
matrix[12] * matrix[1] * matrix[10] - | |
matrix[12] * matrix[2] * matrix[9]; | |
inv[2] = matrix[1] * matrix[6] * matrix[15] - | |
matrix[1] * matrix[7] * matrix[14] - | |
matrix[5] * matrix[2] * matrix[15] + | |
matrix[5] * matrix[3] * matrix[14] + | |
matrix[13] * matrix[2] * matrix[7] - | |
matrix[13] * matrix[3] * matrix[6]; | |
inv[6] = -matrix[0] * matrix[6] * matrix[15] + | |
matrix[0] * matrix[7] * matrix[14] + | |
matrix[4] * matrix[2] * matrix[15] - | |
matrix[4] * matrix[3] * matrix[14] - | |
matrix[12] * matrix[2] * matrix[7] + | |
matrix[12] * matrix[3] * matrix[6]; | |
inv[10] = matrix[0] * matrix[5] * matrix[15] - | |
matrix[0] * matrix[7] * matrix[13] - | |
matrix[4] * matrix[1] * matrix[15] + | |
matrix[4] * matrix[3] * matrix[13] + | |
matrix[12] * matrix[1] * matrix[7] - | |
matrix[12] * matrix[3] * matrix[5]; | |
inv[14] = -matrix[0] * matrix[5] * matrix[14] + | |
matrix[0] * matrix[6] * matrix[13] + | |
matrix[4] * matrix[1] * matrix[14] - | |
matrix[4] * matrix[2] * matrix[13] - | |
matrix[12] * matrix[1] * matrix[6] + | |
matrix[12] * matrix[2] * matrix[5]; | |
inv[3] = -matrix[1] * matrix[6] * matrix[11] + | |
matrix[1] * matrix[7] * matrix[10] + | |
matrix[5] * matrix[2] * matrix[11] - | |
matrix[5] * matrix[3] * matrix[10] - | |
matrix[9] * matrix[2] * matrix[7] + | |
matrix[9] * matrix[3] * matrix[6]; | |
inv[7] = matrix[0] * matrix[6] * matrix[11] - | |
matrix[0] * matrix[7] * matrix[10] - | |
matrix[4] * matrix[2] * matrix[11] + | |
matrix[4] * matrix[3] * matrix[10] + | |
matrix[8] * matrix[2] * matrix[7] - | |
matrix[8] * matrix[3] * matrix[6]; | |
inv[11] = -matrix[0] * matrix[5] * matrix[11] + | |
matrix[0] * matrix[7] * matrix[9] + | |
matrix[4] * matrix[1] * matrix[11] - | |
matrix[4] * matrix[3] * matrix[9] - | |
matrix[8] * matrix[1] * matrix[7] + | |
matrix[8] * matrix[3] * matrix[5]; | |
inv[15] = matrix[0] * matrix[5] * matrix[10] - | |
matrix[0] * matrix[6] * matrix[9] - | |
matrix[4] * matrix[1] * matrix[10] + | |
matrix[4] * matrix[2] * matrix[9] + | |
matrix[8] * matrix[1] * matrix[6] - | |
matrix[8] * matrix[2] * matrix[5]; | |
det = matrix[0] * inv[0] + matrix[1] * inv[4] + matrix[2] * inv[8] + matrix[3] * inv[12]; | |
det = 1.0 / det; | |
for (i = 0; i < 16; i++) | |
inv[i] *= det; | |
return inv; | |
} | |
public static void cross(float[] r,float[] a, float[] b) | |
{ | |
r[0]=a[1]*b[2]-a[2]*b[1]; | |
r[1]=a[2]*b[0]-a[0]*b[2]; | |
r[2]=a[0]*b[1]-a[1]*b[0]; | |
} | |
public static float magnitute(float[] r){ | |
return sqrt(r[0]*r[0]+r[1]*r[1]+r[2]*r[2]); | |
} | |
public static void normalize(float[] r){ | |
float len=magnitute(r); | |
r[0]/=len; | |
r[1]/=len; | |
r[2]/=len; | |
} | |
public static void scale(float[] a,float k){ | |
a[0]*=k; | |
a[1]*=k; | |
a[2]*=k; | |
} | |
public static float dot(float[] a, float[] b){ | |
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; | |
} | |
public static float[] diff(float[] a, float[] b){ | |
float[] diff = new float[3]; | |
diff[0]= a[0] - b[0]; | |
diff[1]= a[1] - b[1]; | |
diff[2]= a[2] - b[2]; | |
return diff; | |
} | |
public static float clamp(float x, float min, float max) | |
{ | |
if (x < min) | |
x = min; | |
else if (x > max) | |
x = max; | |
return x; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment