Updated readability of the code.
[sixth-3d.git] / src / main / java / eu / svjatoslav / sixth / e3d / renderer / octree / raytracer / RayTracer.java
1 /*
2  * Sixth 3D engine. Author: Svjatoslav Agejenko. 
3  * This project is released under Creative Commons Zero (CC0) license.
4  */
5 package eu.svjatoslav.sixth.e3d.renderer.octree.raytracer;
6
7 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
8 import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
9 import eu.svjatoslav.sixth.e3d.renderer.octree.OctreeVolume;
10 import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
11 import eu.svjatoslav.sixth.e3d.renderer.raster.texture.Texture;
12
13 import java.util.Vector;
14
15 public class RayTracer implements Runnable {
16
17     private static final int PROGRESS_UPDATE_FREQUENCY_MILLIS = 1000;
18     private final Camera camera;
19     private final Texture texture;
20     private final ViewPanel viewPanel;
21     private final OctreeVolume octreeVolume;
22     private final Vector<LightSource> lights;
23     private int computedLights;
24
25     public RayTracer(final Texture texture, final OctreeVolume octreeVolume,
26                      final Vector<LightSource> lights, final Camera camera,
27                      final ViewPanel viewPanel) {
28
29         this.texture = texture;
30         this.octreeVolume = octreeVolume;
31         this.lights = lights;
32         this.camera = camera;
33         this.viewPanel = viewPanel;
34     }
35
36     @Override
37     public void run() {
38         computedLights = 0;
39
40         // create camera
41
42         // Camera cam = new Camera(camCenter, upLeft, upRight, downLeft,
43         // downRight);
44
45         // add camera to the raytracing point
46         // Main.mainWorld.geometryCollection.addObject(cam);
47         // Main.mainWorld.compiledGeometry.compileGeometry(Main.mainWorld.geometryCollection);
48
49         final int width = texture.primaryBitmap.width;
50         final int height = texture.primaryBitmap.height;
51
52         final CameraView cameraView = camera.getCameraView();
53
54         // calculate vertical vectors
55         final double x1p = cameraView.bottomLeft.x - cameraView.topLeft.x;
56         final double y1p = cameraView.bottomLeft.y - cameraView.topLeft.y;
57         final double z1p = cameraView.bottomLeft.z - cameraView.topLeft.z;
58
59         final double x2p = cameraView.bottomRight.x - cameraView.topRight.x;
60         final double y2p = cameraView.bottomRight.y - cameraView.topRight.y;
61         final double z2p = cameraView.bottomRight.z - cameraView.topRight.z;
62
63         long nextBitmapUpdate = System.currentTimeMillis()
64                 + PROGRESS_UPDATE_FREQUENCY_MILLIS;
65
66         for (int y = 0; y < height; y++) {
67             final double cx1 = cameraView.topLeft.x + ((x1p * y) / height);
68             final double cy1 = cameraView.topLeft.y + ((y1p * y) / height);
69             final double cz1 = cameraView.topLeft.z + ((z1p * y) / height);
70
71             final double cx2 = cameraView.topRight.x + ((x2p * y) / height);
72             final double cy2 = cameraView.topRight.y + ((y2p * y) / height);
73             final double cz2 = cameraView.topRight.z + ((z2p * y) / height);
74
75             // calculate horisontal vector
76             final double x3p = cx2 - cx1;
77             final double y3p = cy2 - cy1;
78             final double z3p = cz2 - cz1;
79
80             for (int x = 0; x < width; x++) {
81                 final double cx3 = cx1 + ((x3p * x) / width);
82                 final double cy3 = cy1 + ((y3p * x) / width);
83                 final double cz3 = cz1 + ((z3p * x) / width);
84
85                 final Ray r = new Ray(
86                         new Point3D(cameraView.cameraCenter.x,
87                                 cameraView.cameraCenter.y,
88                                 cameraView.cameraCenter.z),
89                         new Point3D(
90                         cx3 - cameraView.cameraCenter.x, cy3
91                         - cameraView.cameraCenter.y, cz3
92                         - cameraView.cameraCenter.z)
93                 );
94                 final int c = traceRay(r);
95
96                 final Color color = new Color(c);
97                 texture.primaryBitmap.drawPixel(x, y, color);
98             }
99
100             if (System.currentTimeMillis() > nextBitmapUpdate) {
101                 nextBitmapUpdate = System.currentTimeMillis()
102                         + PROGRESS_UPDATE_FREQUENCY_MILLIS;
103                 texture.resetResampledBitmapCache();
104                 viewPanel.repaintDuringNextViewUpdate();
105             }
106         }
107
108         texture.resetResampledBitmapCache();
109         viewPanel.repaintDuringNextViewUpdate();
110     }
111
112     private int traceRay(final Ray ray) {
113
114         final int intersectingCell = octreeVolume.traceCell(0, 0, 0,
115                 octreeVolume.masterCellSize, 0, ray);
116
117         if (intersectingCell != -1) {
118             // if lightening not computed, compute it
119             if (octreeVolume.ce3[intersectingCell] == -1)
120                 // if cell is larger than 1
121                 if (ray.hitCellSize > 1) {
122                     // break it up
123                     octreeVolume.breakSolidCell(intersectingCell);
124                     return traceRay(ray);
125                 } else {
126                     computedLights++;
127                     float red = 30, green = 30, blue = 30;
128
129                     for (final LightSource l : lights) {
130                         final double xDist = (l.location.x - ray.hitCellX);
131                         final double yDist = (l.location.y - ray.hitCellY);
132                         final double zDist = (l.location.z - ray.hitCellZ);
133
134                         double newRed = 0, newGreen = 0, newBlue = 0;
135                         double tempRed, tempGreen, tempBlue;
136
137                         double distance = Math.sqrt((xDist * xDist)
138                                 + (yDist * yDist) + (zDist * zDist));
139                         distance = (distance / 3) + 1;
140
141                         final Ray r1 = new Ray(
142                                 new Point3D(
143                                 ray.hitCellX,
144                                 ray.hitCellY - (float) 1.5,
145                                 ray.hitCellZ),
146
147                                 new Point3D((float) l.location.x - (float) ray.hitCellX, l.location.y
148                                 - (ray.hitCellY - (float) 1.5), (float) l.location.z
149                                 - (float) ray.hitCellZ)
150                         );
151
152                         final int rt1 = octreeVolume.traceCell(0, 0, 0,
153                                 octreeVolume.masterCellSize, 0, r1);
154
155                         if (rt1 == -1) {
156                             newRed = (l.color.r * l.brightness) / distance;
157                             newGreen = (l.color.g * l.brightness) / distance;
158                             newBlue = (l.color.b * l.brightness) / distance;
159                         }
160
161                         final Ray r2 = new Ray(
162                                 new Point3D(
163                                 ray.hitCellX - (float) 1.5,
164                                 ray.hitCellY, ray.hitCellZ),
165
166                                 new Point3D(
167                                 l.location.x - (ray.hitCellX - (float) 1.5), (float) l.location.y
168                                 - (float) ray.hitCellY, (float) l.location.z
169                                 - (float) ray.hitCellZ)
170                         );
171
172                         final int rt2 = octreeVolume.traceCell(0, 0, 0,
173                                 octreeVolume.masterCellSize, 0, r2);
174
175                         if (rt2 == -1) {
176                             tempRed = (l.color.r * l.brightness) / distance;
177                             tempGreen = (l.color.g * l.brightness) / distance;
178                             tempBlue = (l.color.b * l.brightness) / distance;
179
180                             if (tempRed > newRed)
181                                 newRed = tempRed;
182                             if (tempGreen > newGreen)
183                                 newGreen = tempGreen;
184                             if (tempBlue > newBlue)
185                                 newBlue = tempBlue;
186                         }
187
188                         final Ray r3 = new Ray(
189                                 new Point3D (
190                                 ray.hitCellX, ray.hitCellY,
191                                 ray.hitCellZ - (float) 1.5),
192                                 new Point3D(
193                                 (float) l.location.x - (float) ray.hitCellX, (float) l.location.y
194                                 - (float) ray.hitCellY, l.location.z
195                                 - (ray.hitCellZ - (float) 1.5))
196                         );
197
198                         final int rt3 = octreeVolume.traceCell(0, 0, 0,
199                                 octreeVolume.masterCellSize, 0, r3);
200
201                         if (rt3 == -1) {
202                             tempRed = (l.color.r * l.brightness) / distance;
203                             tempGreen = (l.color.g * l.brightness) / distance;
204                             tempBlue = (l.color.b * l.brightness) / distance;
205                             if (tempRed > newRed)
206                                 newRed = tempRed;
207                             if (tempGreen > newGreen)
208                                 newGreen = tempGreen;
209                             if (tempBlue > newBlue)
210                                 newBlue = tempBlue;
211                         }
212
213                         final Ray r4 = new Ray(
214                                 new Point3D(
215                                 ray.hitCellX,
216                                 ray.hitCellY+ (float) 1.5,
217                                 ray.hitCellZ),
218
219                                 new Point3D(
220                                 (float) l.location.x - (float) ray.hitCellX, l.location.y
221                                 - (ray.hitCellY + (float) 1.5), (float) l.location.z
222                                 - (float) ray.hitCellZ)
223                         );
224
225                         final int rt4 = octreeVolume.traceCell(0, 0, 0,
226                                 octreeVolume.masterCellSize, 0, r4);
227
228                         if (rt4 == -1) {
229                             tempRed = (l.color.r * l.brightness) / distance;
230                             tempGreen = (l.color.g * l.brightness) / distance;
231                             tempBlue = (l.color.b * l.brightness) / distance;
232                             if (tempRed > newRed)
233                                 newRed = tempRed;
234                             if (tempGreen > newGreen)
235                                 newGreen = tempGreen;
236                             if (tempBlue > newBlue)
237                                 newBlue = tempBlue;
238                         }
239
240                         final Ray r5 = new Ray(
241                                 new Point3D(
242                                 ray.hitCellX + (float) 1.5,
243                                 ray.hitCellY, ray.hitCellZ),
244
245                                 new Point3D(
246                                 l.location.x - (ray.hitCellX + (float) 1.5), (float) l.location.y
247                                 - (float) ray.hitCellY, (float) l.location.z
248                                 - (float) ray.hitCellZ)
249                             );
250
251                         final int rt5 = octreeVolume.traceCell(0, 0, 0,
252                                 octreeVolume.masterCellSize, 0, r5);
253
254                         if (rt5 == -1) {
255                             tempRed = (l.color.r * l.brightness) / distance;
256                             tempGreen = (l.color.g * l.brightness) / distance;
257                             tempBlue = (l.color.b * l.brightness) / distance;
258                             if (tempRed > newRed)
259                                 newRed = tempRed;
260                             if (tempGreen > newGreen)
261                                 newGreen = tempGreen;
262                             if (tempBlue > newBlue)
263                                 newBlue = tempBlue;
264                         }
265
266                         final Ray r6 = new Ray(
267                                 new Point3D(
268                                 ray.hitCellX, ray.hitCellY,
269                                 ray.hitCellZ + (float) 1.5),
270
271                                 new Point3D(
272
273                                 (float) l.location.x - (float) ray.hitCellX, (float) l.location.y
274                                 - (float) ray.hitCellY, l.location.z
275                                 - (ray.hitCellZ + (float) 1.5)));
276
277                         final int rt6 = octreeVolume.traceCell(0, 0, 0,
278                                 octreeVolume.masterCellSize, 0, r6);
279
280                         if (rt6 == -1) {
281                             tempRed = (l.color.r * l.brightness) / distance;
282                             tempGreen = (l.color.g * l.brightness) / distance;
283                             tempBlue = (l.color.b * l.brightness) / distance;
284                             if (tempRed > newRed)
285                                 newRed = tempRed;
286                             if (tempGreen > newGreen)
287                                 newGreen = tempGreen;
288                             if (tempBlue > newBlue)
289                                 newBlue = tempBlue;
290                         }
291                         red += newRed;
292                         green += newGreen;
293                         blue += newBlue;
294
295                     }
296
297                     final int cellColor = octreeVolume.ce2[intersectingCell];
298
299                     red = (red * ((cellColor & 0xFF0000) >> 16)) / 255;
300                     green = (green * ((cellColor & 0xFF00) >> 8)) / 255;
301                     blue = (blue * (cellColor & 0xFF)) / 255;
302
303                     if (red > 255)
304                         red = 255;
305                     if (green > 255)
306                         green = 255;
307                     if (blue > 255)
308                         blue = 255;
309
310                     octreeVolume.ce3[intersectingCell] = (((int) red) << 16)
311                             + (((int) green) << 8) + ((int) blue);
312
313                 }
314             if (octreeVolume.ce3[intersectingCell] == 0)
315                 return octreeVolume.ce2[intersectingCell];
316             return octreeVolume.ce3[intersectingCell];
317         }
318
319         // return (200 << 16) + (200 << 8) + 255;
320         return 0;
321     }
322
323 }