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