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