├── .gitignore └── src ├── Ray.class ├── vec3.class ├── firstImage.class ├── Hittable.java ├── Camera.java ├── HittableList.java ├── Sphere.java ├── Hit_record.java ├── Ray.java ├── firstImage.java └── Vec3.java /.gitignore: -------------------------------------------------------------------------------- 1 | /out/ 2 | -------------------------------------------------------------------------------- /src/Ray.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/raytracer-hoabinh/master/src/Ray.class -------------------------------------------------------------------------------- /src/vec3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/raytracer-hoabinh/master/src/vec3.class -------------------------------------------------------------------------------- /src/firstImage.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/raytracer-hoabinh/master/src/firstImage.class -------------------------------------------------------------------------------- /src/Hittable.java: -------------------------------------------------------------------------------- 1 | interface Hittable { 2 | boolean hit(Ray r, double t_min, double t_max, Hit_record rec); 3 | } 4 | -------------------------------------------------------------------------------- /src/Camera.java: -------------------------------------------------------------------------------- 1 | public class Camera { 2 | private Vec3 origin; 3 | private Vec3 lower_left_corner; 4 | private Vec3 horizontal; 5 | private Vec3 vertikal; 6 | 7 | public Camera(){ 8 | double aspect_ratio = 16.0/9.0; 9 | double viewport_height = 2.0; 10 | double viewport_width = aspect_ratio * viewport_height; 11 | double focal_length = 1.0; 12 | 13 | 14 | origin = new Vec3(0,0,0); 15 | horizontal = new Vec3(viewport_width, 0.0,0.0); 16 | vertikal = new Vec3(0.0,viewport_height,0.0); 17 | lower_left_corner = origin.sub((horizontal).div(2)).sub((vertikal).div(2)).sub(new Vec3 (0,0,focal_length)); 18 | } 19 | Ray get_ray(double u, double v){ 20 | //System.out.println(horizontal); 21 | return new Ray(origin, lower_left_corner.add(horizontal.mul(u)).add(vertikal.mul(v)).sub(origin)); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/HittableList.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | public class HittableList implements Hittable { 4 | ArrayList list; 5 | 6 | HittableList(){ 7 | this.list = new ArrayList<>(); 8 | } 9 | HittableList( Hittable object){ 10 | add(object); 11 | } 12 | public void clear(){ 13 | list.clear(); 14 | } 15 | public void add(Hittable object){ 16 | list.add(object); 17 | } 18 | public boolean hit(Ray r, double t_min, double t_max, Hit_record rec){ 19 | Hit_record temp_rec = new Hit_record(); 20 | boolean hit_anything = false; 21 | double closest_so_far = t_max; 22 | 23 | for (Hittable object:list) { 24 | if (object.hit(r, t_min, closest_so_far, temp_rec)) { 25 | hit_anything = true; 26 | closest_so_far = temp_rec.t; 27 | rec.set(temp_rec); 28 | 29 | 30 | } 31 | 32 | } 33 | 34 | return hit_anything; 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Sphere.java: -------------------------------------------------------------------------------- 1 | public class Sphere implements Hittable{ 2 | public Vec3 center; 3 | public double radius; 4 | 5 | public Sphere(){ 6 | } 7 | public Sphere(Vec3 cen, double r) { 8 | center = cen; 9 | radius = r; 10 | } 11 | 12 | @Override 13 | public boolean hit(Ray r, double t_min, double t_max, Hit_record rec) { 14 | Vec3 oc = r.origin().sub(center); 15 | double a = r.direction().squared_length(); 16 | double half_b = Vec3.dot(oc,r.direction()); 17 | double c = oc.squared_length() - radius*radius; 18 | double discriminant = half_b * half_b - a*c; 19 | if(discriminant<0) { 20 | return false; 21 | } 22 | double sqrtd = Math.sqrt(discriminant); 23 | //find the nearest root that lies in the acceptable range 24 | double root = (-half_b-sqrtd)/a; 25 | if(root < t_min || t_max < root) { 26 | return false; 27 | } 28 | rec.t = root; 29 | rec.p = r.at(rec.t); 30 | //rec.normal = (rec.p.sub(center)).div(radius); 31 | Vec3 outward_normal = (rec.p.sub(center)).div(radius); 32 | rec.set_face_normal(r,outward_normal); 33 | return true; 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/Hit_record.java: -------------------------------------------------------------------------------- 1 | public class Hit_record { 2 | public Vec3 p; //Trefferpunkt wo man trifft 3 | public Vec3 normal; // steht senkrecht auf der Kugel 4 | public double t; //wie weit geht man den Ray entlangt 5 | boolean front_face; 6 | 7 | 8 | public void set_face_normal(Ray r, Vec3 outward_normal){ 9 | front_face = Vec3.dot(r.direction(),outward_normal)<0; 10 | if(front_face){ 11 | this.normal = outward_normal; 12 | } 13 | else{ 14 | this.normal = outward_normal.mul(-1); 15 | } 16 | } 17 | 18 | public void set(Hit_record temp_rec) { 19 | this.p = temp_rec.p; 20 | this.normal = temp_rec.normal; 21 | this.t = temp_rec.t; 22 | this.front_face = temp_rec.front_face; 23 | } 24 | 25 | public boolean front_face(Ray r, Vec3 outward_normal) { 26 | if(Vec3.dot( r.direction, outward_normal)>0.0){ 27 | //ray is inside the sphere 28 | normal = outward_normal.mul(-1); 29 | front_face = false; 30 | } 31 | else{ 32 | //ray is outside the sphere 33 | normal = outward_normal; 34 | front_face = true; 35 | } 36 | return front_face; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Ray.java: -------------------------------------------------------------------------------- 1 | public class Ray { 2 | Vec3 origin; 3 | Vec3 direction; 4 | double t; //Abstand bis man irgendwas trifft 5 | 6 | public Ray() { 7 | } 8 | 9 | public Ray(Vec3 a, Vec3 b) { 10 | origin = a; 11 | direction = b; 12 | t = 0; 13 | } 14 | 15 | public Ray(Vec3 a, Vec3 b, double ti) { 16 | origin = a; 17 | direction = b; 18 | t = ti; 19 | } 20 | 21 | public Vec3 origin() { 22 | return origin; 23 | } 24 | 25 | public Vec3 direction() { 26 | return direction; 27 | } 28 | 29 | public Vec3 at(double t){ 30 | return origin.add(direction.mul(t)); 31 | } 32 | 33 | public double time() { 34 | return t; 35 | } 36 | 37 | public Vec3 point_at_parameter(double t) { 38 | return origin.add(direction.mul(t)); 39 | } 40 | 41 | public void set(Ray r) { 42 | origin = r.origin; 43 | direction = r.direction; 44 | t = r.t; 45 | } 46 | 47 | public Vec3 color(Ray r, Hittable world){ 48 | //if(hit_sphere(new Vec3(0,0,-1),0.5, r)){ 49 | //return new Vec3(1,0,0); 50 | //} 51 | Hit_record rec = new Hit_record(); 52 | if(world.hit(r,0,Double.POSITIVE_INFINITY,rec)){ 53 | Vec3 target = rec.p.add(rec.normal).add(Vec3.random_in_unit_sphere()); 54 | Vec3 dir = target.sub(rec.p); 55 | return color(new Ray(rec.p.add(dir.mul(0.01)), dir), world).mul(0.5); 56 | //return (rec.normal.add(new Vec3(0.5,0.7,1.0)).mul(0.5)); 57 | } 58 | /*double t = hit_sphere(new Vec3(0,0,-1), 0.5, r); 59 | if(t>0.0){ 60 | Vec3 N = r.at(t).sub(new Vec3(0,0,-1)).unit_vector(); 61 | return new Vec3(N.x()+1, N.y()+1, N.z()+1).mul(0.5); 62 | }*/ 63 | Vec3 unit_direction = this.direction().unit_vector(); //fest Länge Einheitsvektor 64 | t = (float) (0.5*(unit_direction.y()+1.0)); 65 | return new Vec3 (1.0,1.0,1.0).mul(1.0-t).add(new Vec3 (0.5,0.7,1.0).mul(t)); 66 | //return new Vec3(1.0,1.0,1.0).mul(1.0-t).add(new Vec3(0.5,0.7,1.0).mul(t)); 67 | 68 | } 69 | 70 | public double hit_sphere(Vec3 center, double radius, Ray r ){ 71 | Vec3 oc = r.origin().sub(center); 72 | double a = r.direction().squared_length(); 73 | double half_b = Vec3.dot(oc, r.direction()); 74 | double c = oc.squared_length() - (radius*radius); 75 | double discriminant = half_b*half_b - a*c; 76 | //return (discriminant > 0); 77 | if(discriminant<0){ 78 | return -1.0; 79 | } else{ 80 | return (-half_b - Math.sqrt(discriminant))/(a); 81 | } 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /src/firstImage.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | public class firstImage { 4 | 5 | public static void main(String[] args) { 6 | 7 | //Image 8 | double aspect_ratio = 16.0 / 9.0; 9 | int image_width = 400; 10 | int image_height =(int) (image_width / aspect_ratio); 11 | int samples_per_pixel = 100; 12 | 13 | //World 14 | HittableList world = new HittableList(); 15 | world.add(new Sphere(new Vec3(0,0,-1), 0.5)); 16 | world.add(new Sphere(new Vec3(0,-100.5,-1), 100)); 17 | 18 | //Camera 19 | Camera cam = new Camera(); 20 | 21 | /*double viewport_height = 2.0; 22 | double viewport_width = aspect_ratio * viewport_height; 23 | double focal_length = 1.0; 24 | 25 | Vec3 origin = new Vec3(0,0,0); //wo ist der Nullpunkt 26 | Vec3 horizontal = new Vec3(viewport_width,0,0); //bezieht sich die Camera 27 | Vec3 vertical = new Vec3(0,viewport_height,0); 28 | Vec3 lower_left_corner = origin.sub(horizontal.div(2)).sub(vertical.div(2)).sub(new Vec3(0,0,focal_length)); //Koordinaten links unten 29 | */ 30 | 31 | //Render 32 | 33 | System.out.print("P3" + "\n" + image_width + " " + image_height+"\n" + "255" +"\n"); 34 | 35 | int j = image_height-1; 36 | for (; j>=0;j--) { 37 | System.err.print("\rScanlines remaining: " + j + " "); 38 | for (int i = 0; i < image_width; i++) { 39 | Vec3 pixel_color = new Vec3 (0,0,0); 40 | for (int s=0; s < samples_per_pixel; s++){ 41 | double u = (double) (i+ Math.random()) /(image_width-1); 42 | double v = (double) (j+ Math.random()) /(image_height-1); 43 | Ray r = cam.get_ray(u,v); 44 | pixel_color = r.color(r,world).add(pixel_color); 45 | } 46 | pixel_color.write_color(pixel_color, samples_per_pixel); 47 | 48 | 49 | 50 | //Vec3 pixel_color = new Vec3((double) i / (image_width - 1),(double) j / (image_height - 1),0.25); 51 | //pixel_color.write_color(pixel_color); 52 | 53 | /*double r = (double) i / (image_width - 1); 54 | double g = (double) j / (image_height - 1); 55 | double b = 0.25; 56 | 57 | int ir = (int) (255.999 * r); 58 | int ig = (int) (255.999 * g); 59 | int ib = (int) (255.999 * b); 60 | 61 | System.out.println(ir + " " + ig + " " + ib + " " + "\n"); 62 | 63 | */ 64 | 65 | /* 66 | Type aliases for vec3 67 | using point3 = vec3; // 3D point 68 | using color = vec3; // RGB color 69 | 70 | 71 | */ 72 | } 73 | } 74 | System.err.println("\nDone.\n"); 75 | 76 | 77 | } 78 | //Utility Functions 79 | public double degrees_to_radians(double degree){ 80 | return degree*Math.PI/180.0; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/Vec3.java: -------------------------------------------------------------------------------- 1 | public class Vec3 { 2 | private double[] e = new double[3]; 3 | 4 | public Vec3(double e0, double e1, double e2) { 5 | e[0] = e0; 6 | e[1] = e1; 7 | e[2] = e2; 8 | } 9 | 10 | public double x() { 11 | return e[0]; 12 | } 13 | 14 | public double y() { 15 | return e[1]; 16 | } 17 | 18 | public double z() { 19 | return e[2]; 20 | } 21 | 22 | public double r() { 23 | return e[0]; 24 | } 25 | 26 | public double g() { 27 | return e[1]; 28 | } 29 | 30 | public double b() { 31 | return e[2]; 32 | } 33 | 34 | public double length() { 35 | return Math.sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]); 36 | } 37 | 38 | public double squared_length() { 39 | return e[0] * e[0] + e[1] * e[1] + e[2] * e[2]; 40 | } 41 | 42 | 43 | public Vec3 minus() { 44 | return new Vec3(-e[0], -e[1], -e[2]); 45 | } 46 | 47 | public Vec3 add(Vec3 other) { 48 | return new Vec3(e[0] + other.e[0], e[1] + other.e[1], e[2] + other.e[2]); 49 | } 50 | 51 | public Vec3 sub(Vec3 other) { 52 | return new Vec3(e[0] - other.e[0], e[1] - other.e[1], e[2] - other.e[2]); 53 | } 54 | 55 | public Vec3 mul(Vec3 other) { 56 | return new Vec3(e[0] * other.e[0], e[1] * other.e[1], e[2] * other.e[2]); 57 | } 58 | 59 | public Vec3 mul(double t) { 60 | return new Vec3(t * e[0], t * e[1], t * e[2]); 61 | } 62 | 63 | public Vec3 div(Vec3 other) { 64 | return new Vec3(e[0] / other.e[0], e[1] / other.e[1], e[2] / other.e[2]); 65 | } 66 | 67 | public Vec3 div(double t) { 68 | return new Vec3(e[0] / t, e[1] / t, e[2] / t); 69 | } 70 | 71 | public static double dot(Vec3 v1, Vec3 v2) { 72 | return v1.e[0] * v2.e[0] + v1.e[1] * v2.e[1] + v1.e[2] * v2.e[2]; 73 | } 74 | 75 | public static Vec3 cross(Vec3 v1, Vec3 v2) { 76 | return new Vec3((v1.e[1] * v2.e[2] - v1.e[2] * v2.e[1]), (-(v1.e[0] * v2.e[2] - v1.e[2] * v2.e[0]) 77 | ), (v1.e[0] * v2.e[1] - v1.e[1] * v2.e[0])); 78 | } 79 | 80 | public void unit() { 81 | double k = 1.0 / length(); 82 | e[0] *= k; 83 | e[1] *= k; 84 | e[2] *= k; 85 | } 86 | 87 | public Vec3 unit_vector() { 88 | 89 | return this.div(this.length()); 90 | } 91 | 92 | public void set(Vec3 v) { 93 | e[0] = v.e[0]; 94 | e[1] = v.e[1]; 95 | e[2] = v.e[2]; 96 | } 97 | 98 | public double get(int i) { 99 | return e[i]; 100 | } 101 | 102 | public String toString() { 103 | return "<" + e[0] + "," + e[1] + "," + e[2] + ">"; 104 | } 105 | 106 | public boolean equals(Vec3 v2) { 107 | return e[0] == v2.e[0] && e[1] == v2.e[1] && e[2] == v2.e[2]; 108 | } 109 | 110 | public double clamp(double x, double min, double max) { 111 | if (x < min) { 112 | return min; 113 | } 114 | if (x > max) { 115 | return max; 116 | } 117 | return x; 118 | } 119 | 120 | public void write_color(Vec3 pixel_color, int samples_per_pixel) { 121 | // Divide the color by the number of samples 122 | double scale = 1.0 / samples_per_pixel; 123 | 124 | int ir = (int) (256.0 * clamp(pixel_color.r() * scale, 0.0, 0.999)); 125 | int ig = (int) (256.0 * clamp(pixel_color.g() * scale, 0.0, 0.999)); 126 | int ib = (int) (256.0 * clamp(pixel_color.b() * scale, 0.0, 0.999)); 127 | 128 | //Write the translated [0,255] value of each color component. 129 | System.out.println(ir + " " + ig + " " + ib); 130 | } 131 | 132 | public double random_double(double min, double max) { 133 | //Return a random real in [min, max] 134 | return min + (max - min) * Math.random(); 135 | } 136 | 137 | 138 | //ZU BEARBEITEN 139 | public static Vec3 random(double min, double max) { 140 | return new Vec3(Math.random(), Math.random(), Math.random()); 141 | } 142 | 143 | public static Vec3 random_in_unit_sphere() { 144 | while (true) { 145 | Vec3 p = Vec3.random(-1, 1); 146 | if (p.squared_length() >= 1) { 147 | continue; 148 | } else { 149 | return p; 150 | } 151 | 152 | } 153 | 154 | } 155 | 156 | 157 | } 158 | 159 | 160 | 161 | 162 | 163 | 164 | --------------------------------------------------------------------------------