212 Commits

Author SHA1 Message Date
Manoël Trapier
0e188a0594 Update build badge from travis to github action.
(free for OSS project) Travis is dead!
2022-02-28 11:43:31 +00:00
Godzil
c1f41cb6f6 Trying to fix github actions. 2022-02-28 11:37:41 +00:00
Godzil
50143076ab Fix a typo in README 2022-02-28 11:29:44 +00:00
Manoël Trapier
c33cdabdec Add some actions! 2022-02-28 11:04:51 +00:00
Godzil
ad16643111 Googletest...
This "master" to "main" is already none-sense, but renaming the principal branch on an existing repo to break everything.
Thanks a lot.
2022-02-28 10:55:52 +00:00
Godzil
45f5f8098e Force cmake 3.11 because of changes in add_executable
Remove Ubuntu 18.04 arm target as it use an old cmake.
2021-03-10 15:22:26 +00:00
Godzil
28b619c566 Try to change (again) the travis file. May work this time? 2021-03-10 14:08:08 +00:00
Godzil
4f512405b2 Travis works, but always is unpredictable at time.. 2021-03-10 12:26:52 +00:00
Godzil
fe80488c5e Update travis file to more up to date practice for Mac OS X build using homebrew 2021-03-10 12:17:28 +00:00
Godzil
f8f4d7b21a Add sample output from the dragon scene 2021-03-10 11:58:09 +00:00
Godzil
5651570c2b Slight changes in octree/bvh 2020-03-17 00:44:58 +00:00
Godzil
71c236abb0 Better to fill the function I suppose. 2020-03-17 00:31:30 +00:00
Godzil
c0fc061834 Don't set the focal/aperture on the constructor and use a dedicated method for that. 2020-03-17 00:28:56 +00:00
Godzil
61ce9d3543 Add possibility to play with focal length and aperture to the camera. Not enabled by default. 2020-03-17 00:23:16 +00:00
Godzil
9849c16f66 Couple of small optimisation
Add option to build for gprof
Do not build by default with the renderstat (they have a reasonable impact on performances)
Separated created ray and castedray in the stats
Trying to force some simple function to be inlined
2020-03-13 18:22:35 +00:00
Godzil
aacd4f6c9e Make BVH and Octree to not flatten the world before parsing
It may help a lot on some scene that already use groups.

So each exiting group have their own BVH or Octree in.

It does help a lot on already organised scene like the Christmas balls.
2020-03-13 01:07:28 +00:00
Godzil
5b6b627a43 Small but effective optimisations.
Allow inlining the function helps a bit!
2020-03-13 01:04:56 +00:00
Manoël Trapier
4f2e327533 Update for a proper testing size and don’t get a timeout 2020-03-12 19:39:32 +00:00
Godzil
c858b4dcde A new scene and some optimisations. 2020-03-12 17:45:29 +00:00
Godzil
7a43a98816 Adding BVH optimisation. 2020-03-12 07:21:44 +00:00
Godzil
47e31714f3 That file was supposed to be there XD 2020-03-12 00:14:50 +00:00
Godzil
424d58c59b Octree Optimiser seems to work.
Well.. There are a couple of weird things happening, need to investigate, but it's not that easy when scene start to be complicated :/
2020-03-12 00:14:00 +00:00
Godzil
5996e38e6e Fix my own stupidity.. 2020-03-12 00:11:48 +00:00
Godzil
b00bb75189 Huge speed up by changing how Intersect are shared. 2020-03-12 00:11:26 +00:00
Godzil
0aa949c60b Continue working work optimiser. 2020-03-11 19:35:08 +00:00
Godzil
420203e95d Add a tool to debug the normal vector in objfiles by rendering them. 2020-03-11 16:59:02 +00:00
Godzil
c667ce26d7 Fix a bug in objfile where OBJ file were not the parent of the base group. 2020-03-11 16:57:49 +00:00
Godzil
13cc2c0ff9 Add more useful dump info for shapes 2020-03-11 16:56:38 +00:00
Godzil
1c4018e47a Cosmetics. 2020-03-11 16:56:03 +00:00
Godzil
083a5b600f typo 2020-03-11 16:54:46 +00:00
Godzil
3a2d21b787 Starting to work on the World Optimiser sequence. 2020-03-11 09:09:30 +00:00
Godzil
441d758845 Add locking mechanism to prevent updating transform/parent 2020-03-10 13:55:27 +00:00
Godzil
5da0c10182 Started working on "world optimiser" base class.
The idea is to reorganise objets to take use of the them to prevent most object to be intersect if they are not likely to be on the ray path.
2020-03-10 09:18:15 +00:00
Godzil
b89f9ec331 Add a way to remove shapes from groups 2020-03-10 09:16:39 +00:00
Godzil
add3d7c861 A bit of cleanup 2020-03-10 09:15:38 +00:00
Godzil
4e241a1871 Trying to make the dump a bit more usefull and slightly less cluttered 2020-03-09 17:41:11 +00:00
Godzil
15a861802a OBJFile now use group instead of it own list.
Change the group function to find group by name, and now name group when needed, and change tests to use group name instead of number.

Also now the default group is the base group, not a separate group.

Bonus: Add a destructor to cleanup memory
Added a function to get base group. OBJFile will still behave as a valid shape, but now we can skip it in the generated world by adding the base group instead.

Code is now cleaner.
2020-03-09 16:03:27 +00:00
Godzil
66a8b98aeb Add missing code \o/ 2020-03-09 15:59:52 +00:00
Godzil
0f945b69cc World default group now have a name!
Fancy!
2020-03-09 15:58:59 +00:00
Godzil
314da11005 Add support for naming groups 2020-03-09 15:58:32 +00:00
Godzil
8437ab8753 Move ShapeType into the Shape object. 2020-03-09 15:57:23 +00:00
Godzil
d514219ae6 Due to the way material are working now, we need to set by hand (for now) that the material is set. 2020-03-09 14:17:08 +00:00
Godzil
efa47f28ca Fix some potential buffer overflow issues.
Not critical, but better to avoid them!
2020-03-09 14:16:05 +00:00
Godzil
e653855556 Change World to use a base group instead of storing all the world object.
Makes the code simpler and avoid some potential issues. Add to change a bit some test to make them pass properly.
2020-03-09 13:47:42 +00:00
Godzil
1510de3b36 Change CSG to derive the intersect function and do the calculation there instead of the local one.
Also use the bounding box to reject ray that don't it that CSG element.
2020-03-09 13:45:57 +00:00
Godzil
8550d4068f Correct how filterIntersections work, seems c++ don't like how thing were done. 2020-03-09 13:44:10 +00:00
Godzil
cd93b67274 Revert some debug changes that should have not been commited. 2020-03-09 13:42:21 +00:00
Godzil
18965fe1bd They say it is better to do this way. 2020-03-06 21:59:16 +00:00
Godzil
57eff4830e Sample scene for CSG \o/ 2020-03-06 21:55:32 +00:00
Godzil
b5ee92c544 And CSG! \o/
Still working on a nice scene for it.
2020-03-06 19:00:31 +00:00
Godzil
e57b5715e8 Smooth triangles! And support for them in the OBJ File parser.
Also add an interesting tea party scene!
2020-03-06 15:07:26 +00:00
Godzil
73012b6dd1 We need to run testMyRays in the test folder as it now depends on some files that need to be in the work directory. 2020-03-06 10:13:04 +00:00
Godzil
2488cc6319 Seems long ago I forgot to update/correct the local boudingbox calculation for triangles.... 2020-03-06 09:39:33 +00:00
Godzil
518ac260e1 OBJFile parser seems to work.
Can render a simple scene using it.

TODO: Need add way to set material to childs.
2020-03-06 09:38:39 +00:00
Godzil
2725b5f657 Go a bit deeper in parsing the OBJ file. Now we parse each lines into token, and it's now ready to try to execute them. 2020-03-06 01:29:26 +00:00
Godzil
c17bfadc76 Started working on parsing OBJ Files.
Why string manipulation is so tedious in C/++ :(
2020-03-05 17:46:40 +00:00
Godzil
6bef6a1b77 over 9000 years of shame on me.
What where I thinking when I wrote that?!
2020-03-05 16:28:49 +00:00
Godzil
e33cf0d5f0 Maybe need to unlink Python2 before?! 2020-03-05 16:15:58 +00:00
Godzil
c41cbaeea8 Update readme 2020-03-05 16:01:47 +00:00
Godzil
3a8600d274 Add travis command to install ImageMagick on Mac OS X VMs 2020-03-05 15:58:03 +00:00
Godzil
f8aa5cc920 Fix a "bug" in UV Image introduced while debugging 2020-03-05 15:15:20 +00:00
Godzil
30db4d7ca1 Add support to load JPEG files along with PNGs. 2020-03-05 15:14:31 +00:00
Godzil
317148a37d Lua include is only added if lua support is enabled.
Add NanoJPEG dependency to the main library
2020-03-05 15:13:40 +00:00
Godzil
5c6a5afef6 Add support for NanoJPEG to load jpeg files 2020-03-05 15:12:35 +00:00
Godzil
90e79576a2 Correct the MD5 sum 2020-03-05 15:11:34 +00:00
Godzil
a31ae5b2ef Add download and copy of the earth texture map. 2020-03-05 15:09:26 +00:00
Godzil
2ebc177d9d Header update/corrections 2020-03-05 15:06:16 +00:00
Godzil
6a2c5a77ae Trying to implement image mapping.
Something not working yet.
2020-03-05 09:48:37 +00:00
Godzil
d6ae062f7f Add checkered cube render 2020-03-05 00:24:02 +00:00
Godzil
3ebe403de0 Continue working on Cube mapping 2020-03-05 00:10:39 +00:00
Godzil
f5685a45e1 Add AlignCheck UV Pattern 2020-03-04 16:42:43 +00:00
Godzil
7209244f48 Add cylindrical mapping! 2020-03-04 16:16:35 +00:00
Godzil
1b6c14691b fmod is not mathematically valid. Replace it by a correct one. 2020-03-04 16:15:49 +00:00
Godzil
107b612130 Added planar mapping 2020-03-04 13:35:09 +00:00
Godzil
5bbd036fc5 Add spherical mapping render to the README. 2020-03-04 13:23:22 +00:00
Godzil
1ceabe7e62 Change CMake files to simplify them.
Also disable dorayme.cpp for now as it if wrongly taken in the rayonnement library.
2020-03-04 13:21:39 +00:00
Godzil
3e37b5ca44 Add spherical mapping for UV Textures. 2020-03-04 13:20:15 +00:00
Godzil
5c10d65c8d Started working on 2D patterns. 2020-03-04 09:32:11 +00:00
Manoël Trapier
83c12dbd83 Update README.md 2020-03-03 00:12:45 +00:00
Godzil
3cfbb604b0 Fix missing includes. 2020-03-02 23:34:44 +00:00
Godzil
36962275f6 Disable the second jittered test as I can't find a way to make them consistant (they fail depends on combination of OS/Compiler because of the way compiler work..) 2020-03-02 23:29:06 +00:00
Godzil
a1c53fc9cc Commited that file with incorrect size for automated test. 2020-03-02 23:16:17 +00:00
Godzil
0be3236a03 Fix how the Lua lib is build to remove that annoying tmpnam warning. 2020-03-02 18:05:33 +00:00
Godzil
344c36cd78 Remove frand from that scene. 2020-03-02 17:44:17 +00:00
Godzil
478b1f0af1 Disable a test as it is not consistent between compilers. 2020-03-02 17:41:04 +00:00
Godzil
1cebcd4f8b Fix my own stupidity. 2020-03-02 16:49:10 +00:00
Godzil
aab9df0802 Add support for Lua in world, and create the Lua Pattern (pattern can be defined with a lua function) 2020-03-02 16:30:24 +00:00
Godzil
d05a0fb4d0 Update ch11 reflection scene to render the 3 different view 2020-03-02 14:09:30 +00:00
Godzil
21749695b6 Add jitter to area light and example render of it. 2020-03-02 14:03:31 +00:00
Godzil
1fbe682572 Update readme 2020-03-02 08:46:30 +00:00
Godzil
ace7d53571 Clearing up some memory to prevent stupid issues
Preparing for some optimisations. (absolutely need to reduce the ammount of allocations done.)
2020-03-02 08:24:09 +00:00
Godzil
0ac44c3539 Use area light and make a proper canvas size to run the size.
This test is eating memory like crazy. Need to see why.
2020-02-28 18:36:57 +00:00
Godzil
c4b680789e Starting working on area lights. 2020-02-28 18:35:45 +00:00
Godzil
53f66b554b Move renderstat function into the CPP file and add atomic to the variables. 2020-02-28 18:34:42 +00:00
Godzil
307c125eba More bounding boxes 2020-02-28 18:33:59 +00:00
Godzil
b4ae737b40 Continuing working on dumping the world 2020-02-28 09:29:09 +00:00
Godzil
8ceb68fdff Add dependencies to Lua. 2020-02-28 00:05:14 +00:00
Godzil
c369d2fe2d Start working on dumping the world (to a JSON file) for debug purposes. 2020-02-27 18:03:08 +00:00
Godzil
2926166ce6 Add Lua dependencies.
Lua is going to be used for both scene description (it will also provide a YAML importer) and some future expansion in the code. Expect some fun surprises!

(just playing with lua on the main app for now)
2020-02-27 17:24:40 +00:00
Godzil
e61382a129 Doh, this was suppose to be the other way around: add to the bound IF it have finit bounds! 2020-02-27 17:22:47 +00:00
Godzil
a6f0422bd1 Add renderstat to get some info about rendering. 2020-02-27 17:20:55 +00:00
Godzil
a4ddfddbf3 Found the problem with openmp.
X here need to be declared as private, else each thread are sharing the same variable which... well.... don't work well .. :/
2020-02-26 16:09:28 +00:00
Godzil
f1849cdbc1 Pow is way too slow. 2020-02-26 16:08:34 +00:00
Manoël Trapier
9174424d91 Update README.md 2020-02-26 02:29:10 +00:00
Godzil
0369bee306 It is christmas time! 2020-02-26 02:24:04 +00:00
Godzil
ed347e304d Quick (and dirty) change to be able to use OpenMP for rendering. 2020-02-26 02:18:54 +00:00
Godzil
7a96d42874 Add bounding box calculation to triangle..
Could be helpful XD
2020-02-26 02:17:57 +00:00
Godzil
1c00077949 Prepare code to be able to get material from some form of a "group leader". 2020-02-26 00:32:14 +00:00
Godzil
5e4cfb84e6 Fix an issue with groups, and add Chapter 14 example! 2020-02-26 00:30:09 +00:00
Godzil
aded6bb943 Triangles!!! 2020-02-25 18:42:45 +00:00
Godzil
2ea4abdce7 Boundingboxes should be ready.
Next step (later) would be to properly use them other than group to lower the number of intersection calculation per ray.
2020-02-25 18:03:12 +00:00
Godzil
831a096281 Continue working on bounding boxes. 2020-02-25 09:20:38 +00:00
Godzil
3011544e8f Started working on boundingboxes. 2020-02-24 18:03:25 +00:00
Godzil
d1965caf8d Add an option to run coverage locally 2020-02-24 17:26:36 +00:00
Godzil
7bbe5e843b Group should work now. 2020-02-24 17:25:54 +00:00
Godzil
7c794f0496 Working on groups 2020-02-24 09:25:52 +00:00
Godzil
80f59efa43 Add another hardcoded scene. Also made a test file for hw3 that should cover all the commands. 2020-02-23 19:37:47 +00:00
Godzil
f226664fe3 And cones ! 2020-02-23 02:31:30 +00:00
Godzil
0650ac7b44 There were a small copy mistake in ch12 test file. Update the render output 2020-02-22 23:01:06 +00:00
Godzil
d87bbb184e And now we have cylinders! 2020-02-22 22:58:57 +00:00
Godzil
b9bacd3ac9 Don't really understand why this code is marked as not being tested where it should. 2020-02-22 18:51:03 +00:00
Godzil
1d685de8fd Trying to identify why they say these lines are not tested 2020-02-22 18:29:47 +00:00
Godzil
9c35cfc4f3 Trying to fix coverage. 2020-02-22 18:21:30 +00:00
Godzil
56095169eb Add a test for hw3render 2020-02-22 18:00:07 +00:00
Godzil
60db274214 Trye to talk a bit more in the readme XD 2020-02-22 17:45:45 +00:00
Godzil
566be9bcf6 Add missing image 2020-02-22 17:40:48 +00:00
Godzil
dac74007ea Add sample from Chapter 12 :) 2020-02-22 17:39:25 +00:00
Godzil
b251b632ac Add a parameter for shapes to not drop shadow. 2020-02-22 17:38:25 +00:00
Godzil
81e323fdf4 Added CUBES! 2020-02-22 17:30:15 +00:00
Godzil
c9021974f6 Add a world generator based on another raytracer file format I made in the past and add a crude tool to run it.
it does not render properly, there are some major differences between both engine especially in the material definition. Will need more work, but is not urgent.
2020-02-22 15:16:25 +00:00
Godzil
4d4c4a7453 Add preliminary support for material emissivity.
Not yet sure it work as I intended.
2020-02-22 15:14:09 +00:00
Godzil
935c8ebff7 Add support for multiple lights 2020-02-22 15:12:06 +00:00
Godzil
4cdf7a4264 Correct default canvas size for ch11_test 2020-02-22 01:29:42 +00:00
Godzil
51a6bbebb9 Refraction is fully there, with magic fresnel! 2020-02-22 01:27:48 +00:00
Godzil
e45dbad59e Added some proper test scenes for chapter 11. 2020-02-22 00:50:55 +00:00
Godzil
3db0aaaeac Refraction seems to work. Still need to do a nice scene. 2020-02-21 22:50:12 +00:00
Godzil
df52cb36db Working on refraction & transparency.
Lots of work left to do!
2020-02-21 18:59:14 +00:00
Godzil
89dd74fa7c Finally! We have reflections! 2020-02-21 17:39:45 +00:00
Godzil
7337ae4837 Finally! We have reflections! 2020-02-21 17:21:06 +00:00
Godzil
9fffb68026 Remove nanogui dependencies for now. If the need of a gui come, will add back but for now it just add unnecessary checkout time 2020-02-21 12:08:54 +00:00
Godzil
7687581e83 Finishing touch for patterns! 2020-02-21 12:05:30 +00:00
Godzil
75cf59cc1a Adding support for pattern.
Still a bit more work to be done there.
2020-02-21 09:36:34 +00:00
Godzil
9d0db6a635 Added planes! 2020-02-21 00:26:48 +00:00
Godzil
66c1582a5f Shape is now an abstract class and can't be instanciated.
Change derived shape to only deal with local calculation they don't need anymore to deal with how they've been transformed.
2020-02-21 00:02:30 +00:00
Godzil
2a8fe61388 Working on adding test for the shape object. 2020-02-20 18:06:29 +00:00
Godzil
f8c60da05e Updating readme 2020-02-20 17:48:09 +00:00
Godzil
de315d06f9 Just to be sure. 2020-02-20 17:47:26 +00:00
Godzil
cf5597ad6d Adding shadows! 2020-02-20 17:46:03 +00:00
Manoël Trapier
5198888df6 Doh 2020-02-20 16:49:02 +00:00
Godzil
10ae695f01 Trying to fixing some weird things about coverall, also add some real more coverage. 2020-02-20 16:47:00 +00:00
Godzil
d4fae2dbe2 Revert the canvas size to the one from the chapter 2020-02-20 16:20:20 +00:00
Godzil
daef0c078f Revert the canvas size to the one from the chapter 2020-02-20 16:13:58 +00:00
Godzil
a477b137e7 Add a super special Camera from a well known constructor. Can take picture up to Infinite TeraPixel! 2020-02-20 16:08:47 +00:00
Godzil
ba1ae34855 Canvas: use Tuple instead of Colour for put Pixel, add two constructor that may be usefull in the future. 2020-02-20 16:07:39 +00:00
Godzil
bc047cd89e Add viewTransform transformation 2020-02-20 15:11:40 +00:00
Godzil
863bb2a34b Name consistency 2020-02-20 14:48:11 +00:00
Godzil
14c3044acf Cosmetics 2020-02-20 13:27:12 +00:00
Godzil
4b4d2b7819 Wow travis detected (by luck?) that uninitialised variable where one test failed in one specific configuration but no other one..
And thanks valgrind to give me a hint!
2020-02-20 02:01:35 +00:00
Godzil
9e1f448e0f testS.... 2020-02-20 01:53:28 +00:00
Godzil
457f5d04e4 Also run the unit test directly. 2020-02-20 01:49:37 +00:00
Godzil
999419dfe1 World is on the verge of working! 2020-02-20 01:41:53 +00:00
Godzil
be6b472472 Simplify hit search as now the list is ordered. 2020-02-20 01:40:50 +00:00
Godzil
aa078f4d46 Fix in world. 2020-02-20 00:47:02 +00:00
Godzil
dbaa6eea2c Fix Intersect and add sort the list each time we add something to it. 2020-02-20 00:46:19 +00:00
Godzil
a82b67faa4 Working on worlds.
It's currently crashing.
2020-02-19 18:05:48 +00:00
Godzil
efe46e2864 Fix function prototype 2020-02-19 15:45:19 +00:00
Godzil
60d639f3a7 Start working on world (domination) 2020-02-18 17:31:21 +00:00
Godzil
ddaefafa1a Don't fully understand coveralls behaviour. Let's try building with gcc to see it is works better. 2020-02-18 12:24:05 +00:00
Godzil
9f764018d3 Add a couple of test for code that wasn't tested before. 2020-02-18 12:20:40 +00:00
Godzil
6200e5ed56 It generally works better when we build before trying to run..... 2020-02-18 12:10:38 +00:00
Godzil
be245523c9 This should be the proper way. 2020-02-18 12:07:37 +00:00
Godzil
11a00a6e74 Testing travis job feature. 2020-02-18 11:50:32 +00:00
Godzil
af96d52c5a Renaming Object to Shape (part 2) 2020-02-18 11:43:05 +00:00
Godzil
5a4f9f4dc4 Renaming Object to Shape (part 1) 2020-02-18 11:40:55 +00:00
Godzil
df4ec9794a Update travis badge 2020-02-17 23:47:08 +00:00
Godzil
db9f2c0203 Do I really know SH script? I wonder sometimes 😣 2020-02-17 23:33:48 +00:00
Godzil
88fcd48481 This test wasn't support to be there at first. 2020-02-17 23:29:50 +00:00
Godzil
5e295c06b2 Seems that coveralls don't like the OS X build, so let's only push when build from linux 2020-02-17 23:28:38 +00:00
Godzil
4dd7a3af39 Add Chapter 5 and 6 executable to the test list 2020-02-17 23:22:05 +00:00
Godzil
1aab8f6619 Remove the test 🤨 2020-02-17 23:21:28 +00:00
Godzil
27ec4d5567 Trying to find which version of gcov is installed on travis-ci. 2020-02-17 23:13:09 +00:00
Godzil
a64b1288a5 Trying to make travis having the proper gcov version. 2020-02-17 23:06:02 +00:00
Godzil
77907499a4 Rework a bit the base Cmakelist to make it clearer. 2020-02-17 23:05:37 +00:00
Godzil
cf00e62c5a Update coverall script to use my fork that properly support AppleClang. 2020-02-17 23:05:08 +00:00
Godzil
5086a5c82f Use file/glob instead of set to add source files 2020-02-17 23:02:38 +00:00
Godzil
b84ed7496b Trying to make gcov/coveralls to work... 2020-02-17 22:32:33 +00:00
Godzil
b4bd8bd4b7 CoverallS... 2020-02-17 22:19:10 +00:00
Godzil
c1e7496d21 Fix a glib problem on some distros. 2020-02-17 22:18:59 +00:00
Godzil
674831b370 Travis don't like tabs! (he is right :)) 2020-02-17 22:09:31 +00:00
Godzil
8cc2272b50 Add a really really light readme. 2020-02-17 22:04:00 +00:00
Godzil
2e2d8c143c Add travis, coverall and other things. 2020-02-17 21:56:59 +00:00
Godzil
a8ca88640b Add GPLv2 strict license 2020-02-17 21:28:55 +00:00
Godzil
9bdfb26f7e Add Chapter 06 test! 2020-02-17 19:15:58 +00:00
Godzil
5ebed12f4f Add support for point light and materials.
Add material to objects.
2020-02-17 19:12:57 +00:00
Godzil
73d60fb7e4 Fix a copy mistake. 2020-02-17 19:09:31 +00:00
Godzil
4a9379c0b2 Naming consistency 2020-02-17 17:57:55 +00:00
Godzil
aeb4669162 Add vector reflection via a normal vector. 2020-02-17 15:56:08 +00:00
Godzil
a8194169c5 Add function to calculate sphere normal vector on given point on the sphere. 2020-02-17 15:39:14 +00:00
Godzil
656ff52204 Add Chapter 5 "putting it together" example. 2020-02-17 14:30:21 +00:00
Godzil
00b283053e Add transformation to objects. 2020-02-17 14:15:55 +00:00
Godzil
b799e5f819 Update a comment. 2020-02-17 13:57:07 +00:00
Godzil
cabe7ff147 Change Ray to use the generic Tuple instead of Point/Vector (but you still should use Point/Vector for initialisation) 2020-02-17 13:54:07 +00:00
Godzil
17aebe6538 Move the cross product to Tuple instead of just vector (to ease some stuff later, but this is invalid on Points) 2020-02-17 13:53:30 +00:00
Godzil
a1087a9871 Add default size to matrix (4 as it is the most common) 2020-02-17 13:52:28 +00:00
Godzil
c4418683c6 Add the hit function to get the closest non negative hit, and add some mecanisme to test that properly and report when no valid hit occur. 2020-02-17 12:24:15 +00:00
Godzil
1900d1f45d Change the Intersection to a class, and stop using memory allocation for it (and pointer)
A bit more clean (on the code side)
2020-02-17 11:48:29 +00:00
Godzil
513cd9d7eb Update glfw, googletest and lodepng submodules to their latest version 2020-02-17 11:19:53 +00:00
Godzil
01a0de09ab Add 3 new type of object: Sphere, Object and Intersect.
Add Intersect object as a way to report where a ray intersect another object and which one it is.
Add an Object base class for all object that can be rendered.
Add the Sphere object.
2020-02-17 11:16:20 +00:00
Godzil
8faf1db3be More Ray work. 2020-02-15 23:45:19 +00:00
Godzil
79af9fbc97 Also rename the test file. 2020-02-15 23:20:37 +00:00
Godzil
1e2588441f Rename tuple file to remove the plural.
Also add empty shell ray.
2020-02-15 23:18:04 +00:00
Godzil
1f4b14c896 Add a function to convert degree to radian. 2020-02-14 23:29:09 +00:00
178 changed files with 27025 additions and 139 deletions

44
.github/workflows/cmake.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: CMake
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
build:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.allow_failure }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-latest ]
allow_failure: [false]
# include:
# - os: macos-latest
# allow_failure: true
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Test round 1
working-directory: ${{github.workspace}}/build
run: make test
- name: Test round 2
working-directory: ${{github.workspace}}/build/tests
run: make test

6
.gitmodules vendored
View File

@@ -1,12 +1,12 @@
[submodule "external/googletest"] [submodule "external/googletest"]
path = external/googletest path = external/googletest
url = https://github.com/google/googletest.git url = https://github.com/google/googletest.git
[submodule "external/nanogui"]
path = external/nanogui
url = https://github.com/Godzil/nanogui.git
[submodule "external/glfw"] [submodule "external/glfw"]
path = external/glfw path = external/glfw
url = https://github.com/glfw/glfw.git url = https://github.com/glfw/glfw.git
[submodule "external/lodepng"] [submodule "external/lodepng"]
path = external/lodepng path = external/lodepng
url = https://github.com/lvandeve/lodepng url = https://github.com/lvandeve/lodepng
[submodule "external/coveralls-cmake"]
path = external/coveralls-cmake
url = https://github.com/Godzil/coveralls-cmake.git

87
.travis.yml Normal file
View File

@@ -0,0 +1,87 @@
language: c
addons:
apt:
packages:
- lcov
- imagemagick
homebrew:
packages:
- imagemagick
script:
- mkdir build
- cd build
- cmake ..
- make
- make test
- cd tests
- ./testMyRays
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink python@2 ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install imagemagick ; fi
jobs:
include:
- os: linux
dist: bionic
arch: amd64
compiler: gcc
- os: linux
dist: bionic
arch: amd64
compiler: clang
- os: linux
dist: focal
arch: amd64
compiler: gcc
- os: linux
dist: focal
arch: amd64
compiler: clang
- os: osx
compiler: clang
osx_image: xcode12.2
- os: linux
dist: focal
arch: arm64
compiler: gcc
- os: osx
compiler: clang
osx_image: xcode10.3
- os: osx
compiler: clang
osx_image: xcode11.6
- os: osx
compiler: clang
osx_image: xcode12
- stage: "Coverage"
os: linux
dist: bionic
arch: amd64
compiler: gcc
script:
- mkdir coverage
- cd coverage
- cmake .. -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug
- cmake --build .
- cmake --build . --target coveralls
after_success:
- bash <(curl -s https://codecov.io/bash)
allow_failures:
- os: linux
arch: arm64
- os: osx

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.11)
include(ExternalProject) include(ExternalProject)
@@ -6,19 +6,106 @@ project(DoRayMe)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
option(COVERALLS "Generate coveralls data" OFF)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/external/coveralls-cmake/cmake)
option(PACKAGE_TESTS "Build the tests" ON)
option(ENABLE_COVERAGE "Build for code coverage" OFF)
option(SHOW_STATS "Show rendering stat" OFF)
if (SHOW_STATS)
add_compile_options(-DRENDER_STATS)
endif()
option(USE_GPROF "Enable profiling" OFF)
if (USE_GPROF)
add_compile_options(-pg)
add_link_options(-pg)
endif()
option(USE_LUA "Enable the use of Lua" ON)
if (USE_LUA)
add_compile_options(-DENABLE_LUA_SUPPORT)
endif()
if (ENABLE_COVERAGE AND COVERALLS)
message(FATAL_ERROR "You can't enable both ENABLE_COVERAGE and COVERALLS at the same time")
endif()
if (COVERALLS)
include(Coveralls)
coveralls_turn_on_coverage()
endif()
if (ENABLE_COVERAGE)
if("${CMAKE_C_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang" OR
"${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
message("Building with LLVM Code Coverage Tools")
set(CMAKE_CXX_FLAGS "-fprofile-instr-generate -fcoverage-mapping")
elseif(CMAKE_COMPILER_IS_GNUCXX)
message("Building with lcov Code Coverage Tools")
set(CMAKE_CXX_FLAGS "--coverage")
else()
message(FATAL_ERROR "Compiler ${CMAKE_C_COMPILER_ID} is not supported for code coverage")
endif()
endif()
# LodePNG don't make a .a or .so, so let's build a library here # LodePNG don't make a .a or .so, so let's build a library here
add_library(LodePNG STATIC) add_library(LodePNG STATIC)
set(LODEPNG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/lodepng) set(LODEPNG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/lodepng)
target_sources(LodePNG PRIVATE external/lodepng/lodepng.cpp external/lodepng/lodepng.h) target_sources(LodePNG PRIVATE external/lodepng/lodepng.cpp external/lodepng/lodepng.h)
if (USE_LUA)
if (CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
set(LUA_MAKE_TARGET linux)
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
set(LUA_MAKE_TARGET macosx)
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
set(LUA_MAKE_TARGET posix)
else()
set(LUA_MAKE_TARGET posix)
endif()
message("-- Lua: Building Lua for ${LUA_MAKE_TARGET}")
ExternalProject_Add(LuaCore
URL "https://www.lua.org/ftp/lua-5.3.5.tar.gz"
URL_HASH SHA1=112eb10ff04d1b4c9898e121d6bdf54a81482447
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/lua
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE True
BUILD_COMMAND make ${LUA_MAKE_TARGET}
INSTALL_COMMAND ""
)
set(LUA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/lua/src")
set(LUA_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/external/lua/src/liblua.a" -ldl)
endif()
# NanoJPEG
file(DOWNLOAD
http://svn.emphy.de/nanojpeg/trunk/nanojpeg/nanojpeg.c
${CMAKE_CURRENT_SOURCE_DIR}/external/nanojpeg/nanojpeg.c
EXPECTED_HASH MD5=03ce304a71ae0ad1c43663fb386cc233
)
add_library(NanoJPEG STATIC)
set(NANOJPEG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/nanojpeg)
target_sources(NanoJPEG PRIVATE external/nanojpeg/nanojpeg.c)
# Main app # Main app
add_subdirectory(source) add_subdirectory(source)
option(PACKAGE_TESTS "Build the tests" ON) if(PACKAGE_TESTS OR COVERALLS)
if(PACKAGE_TESTS)
enable_testing() enable_testing()
include(GoogleTest) include(GoogleTest)
add_subdirectory("${PROJECT_SOURCE_DIR}/external/googletest" "external/googletest") add_subdirectory("${PROJECT_SOURCE_DIR}/external/googletest" "external/googletest")
add_subdirectory(tests) add_subdirectory(tests)
endif()
if (COVERALLS)
# Create the coveralls target.
coveralls_setup(
"${COVERAGE_SRCS}" # The source files.
ON # If we should upload.
) # (Optional) Alternate project cmake module path.
endif() endif()

340
COPYING Normal file
View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

14
LICENSE Normal file
View File

@@ -0,0 +1,14 @@
Copyright (C) 2020 Manoel <Godzil> Trapier
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

102
README.md
View File

@@ -0,0 +1,102 @@
[![codecov](https://codecov.io/gh/Godzil/DoRayMe/branch/master/graph/badge.svg)](https://codecov.io/gh/Godzil/DoRayMe) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/66339747e4a843719cba29cf5e31ff90)](https://www.codacy.com/manual/Godzil/DoRayMe?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=Godzil/DoRayMe&amp;utm_campaign=Badge_Grade) [![Coverage Status](https://coveralls.io/repos/github/Godzil/DoRayMe/badge.svg?branch=master)](https://coveralls.io/github/Godzil/DoRayMe?branch=master) [![CMake](https://github.com/Godzil/DoRayMe/actions/workflows/cmake.yml/badge.svg)](https://github.com/Godzil/DoRayMe/actions/workflows/cmake.yml)
DoRayMe
=======
A Quick and dirty raytracer.
This raytracer is made following the book
"[The Ray Tracer Challenge](https://pragprog.com/book/jbtracer/the-ray-tracer-challenge)" by Jamis Buck.
It is writen in C++ with no STL and use [LodePNG](https://github.com/lvandeve/lodepng) to output PNG file and use them
as texture, also use [NanoJPEG](https://keyj.emphy.de/nanojpeg/) to use jpeg file as texture, and can use use
[Lua 5.3](https://www.lua.org/) for 3D pattern definition and more to come on the Lua side later..
Examples outputs
----------------
#### From chapter 05 - Sphere intersections:
![Chapter 5 rendering test](output/ch5_test.png)
#### From Chapter 06 - Phong shading:
![Chapter 6 rendering test](output/ch6_test.png)
#### From Chapter 07 - World / Camera / Scenes:
![Chapter 7 rendering test](output/ch7_test.png)
#### From Chapter 08 - Shadows:
![Chapter 8 rendering test](output/ch8_test.png)
#### From Chapter 09 - Planes:
![Chapter 9 rendering test](output/ch9_test.png)
#### From Chapter 10 - Patterns:
![Chapter 10 rendering test](output/ch10_test.png)
#### From Chapter 11 - Reflections, Transparency & Refractions:
![Chapter 11 reflections rendering test](output/ch11_reflection.png)
###### Bonus: Zooming on a reflective ball:
![Chapter 11 zooming on a ball](output/ch11_zooming_on_reflective_ball.png)
###### Zooming on a reflection on that ball:
![Chapter 11 zooming on a reflection](output/ch11_reflection_on_ball.png)
![Chapter 11 refraction rendering test](output/ch11_refraction.png)
![Chapter 11 rendering test](output/ch11_test.png)
#### From Chapter 12 - Cubes:
![Chapter 12 rendering test](output/ch12_test.png)
#### From Chapter 13 - Cylinders:
![Chapter 13 rendering test](output/ch13_test.png)
###### Bonus:
![Chapter 13 cone test](output/ch13_cone.png)
#### From Chapter 14 - Groups & Bounding boxes:
![Chapter 14 rendering test](output/ch14_test.png)
#### From Chapter 15 - Triangles, Wavefrom OBJ files - Smooth trianges:
![Chapter 15 Triangles and teapots](output/ch15_teapot_objfile.png)
#### From Chapter 16 - Constructive Solid Geomety:
![Chapter 16 CSG](output/ch16_test.png)
#### Bonus (from the forum):
[Merry Christmas](https://forum.raytracerchallenge.com/thread/16/merry-christmas-scene-description)
![Merry Christmas](output/christmasball.png)
(about 1min render time using OpenMP on a 2.6Ghz Core i7 3720QM)
#### Bonus chapter - Soft shadow / Area light
###### Without jitter:
![Area light without jitter](output/arealight_test_nojitter.png)
###### With jitter:
![Area light witht jitter](output/arealight_test.png)
#### Bonus chapter - Texture mapping
###### Spherical mapping:
![Spherical mapping](output/uvmap_checkeredsphere.png)
###### Planar mapping:
![Planar mapping](output/uvmap_checkeredplane.png)
###### Cylindrical mapping:
![Cylindrical mapping](output/uvmap_checkeredcylinder.png)
###### Aligncheck plane:
![Aligncheck plane](output/uvmap_aligncheckplane.png)
###### Cubical mapping:
![Cubical mapping](output/uvmap_checkeredcube.png)
###### Image mapping:
![Image mapping](output/uvmap_earth.png)
###### Skybox:
![Skybox](output/uvmap_skybox.png)
###### Large OBJ file:
![Dragon](output/dragon_scene.png)

1
external/coveralls-cmake vendored Submodule

2
external/glfw vendored

1
external/nanogui vendored

Submodule external/nanogui deleted from 16bc6b1d3a

494
external/teapot-low.obj vendored Normal file
View File

@@ -0,0 +1,494 @@
#
# object Teapot001
#
v 7.0000 0.0000 12.0000
v 4.9700 -4.9700 12.0000
v 4.9811 -4.9811 12.4922
v 7.0156 0.0000 12.4922
v 5.3250 -5.3250 12.0000
v 7.5000 0.0000 12.0000
v 0.0000 -7.0000 12.0000
v 0.0000 -7.0156 12.4922
v 0.0000 -7.5000 12.0000
v -5.1387 -4.9700 12.0000
v -5.0022 -4.9811 12.4922
v -5.3250 -5.3250 12.0000
v -7.0000 0.0000 12.0000
v -7.0156 0.0000 12.4922
v -7.5000 0.0000 12.0000
v -4.9700 4.9700 12.0000
v -4.9811 4.9811 12.4922
v -5.3250 5.3250 12.0000
v 0.0000 7.0000 12.0000
v 0.0000 7.0156 12.4922
v 0.0000 7.5000 12.0000
v 4.9700 4.9700 12.0000
v 4.9811 4.9811 12.4922
v 5.3250 5.3250 12.0000
v 6.5453 -6.5453 8.1094
v 9.2188 0.0000 8.1094
v 7.1000 -7.1000 4.5000
v 10.0000 0.0000 4.5000
v 0.0000 -9.2188 8.1094
v 0.0000 -10.0000 4.5000
v -6.5453 -6.5453 8.1094
v -7.1000 -7.1000 4.5000
v -9.2188 0.0000 8.1094
v -10.0000 0.0000 4.5000
v -6.5453 6.5453 8.1094
v -7.1000 7.1000 4.5000
v 0.0000 9.2188 8.1094
v 0.0000 10.0000 4.5000
v 6.5453 6.5453 8.1094
v 7.1000 7.1000 4.5000
v 6.2125 -6.2125 1.9219
v 8.7500 0.0000 1.9219
v 5.3250 -5.3250 0.7500
v 7.5000 0.0000 0.7500
v 0.0000 -8.7500 1.9219
v 0.0000 -7.5000 0.7500
v -6.2125 -6.2125 1.9219
v -5.3250 -5.3250 0.7500
v -8.7500 0.0000 1.9219
v -7.5000 0.0000 0.7500
v -6.2125 6.2125 1.9219
v -5.3250 5.3250 0.7500
v 0.0000 8.7500 1.9219
v 0.0000 7.5000 0.7500
v 6.2125 6.2125 1.9219
v 5.3250 5.3250 0.7500
v 4.5595 -4.5595 0.2344
v 6.4219 0.0000 0.2344
v 0.0000 0.0000 0.0000
v 0.0000 -6.4219 0.2344
v -4.5595 -4.5595 0.2344
v -6.4219 0.0000 0.2344
v -4.5595 4.5595 0.2344
v 0.0000 6.4219 0.2344
v 4.5595 4.5595 0.2344
v -8.0000 0.0000 10.1250
v -7.7500 -1.1250 10.6875
v -12.5938 -1.1250 10.4766
v -12.0625 0.0000 9.9844
v -14.2500 -1.1250 9.0000
v -13.5000 0.0000 9.0000
v -7.5000 0.0000 11.2500
v -13.1250 0.0000 10.9688
v -15.0000 0.0000 9.0000
v -7.7500 1.1250 10.6875
v -12.5938 1.1250 10.4766
v -14.2500 1.1250 9.0000
v -13.1719 -1.1250 6.2695
v -12.6875 0.0000 6.7500
v -9.7500 -1.1250 3.7500
v -13.6563 0.0000 5.7891
v -9.5000 0.0000 3.0000
v -13.1719 1.1250 6.2695
v -9.7500 1.1250 3.7500
v 8.5000 0.0000 7.1250
v 8.5000 -2.4750 5.0625
v 12.6875 -1.7062 8.1094
v 11.9375 0.0000 9.0000
v 15.0000 -0.9375 12.0000
v 13.5000 0.0000 12.0000
v 8.5000 0.0000 3.0000
v 13.4375 0.0000 7.2187
v 16.5000 0.0000 12.0000
v 8.5000 2.4750 5.0625
v 12.6875 1.7062 8.1094
v 15.0000 0.9375 12.0000
v 15.6328 -0.7500 12.3340
v 14.1250 0.0000 12.2813
v 15.0000 -0.5625 12.0000
v 14.0000 0.0000 12.0000
v 17.1406 0.0000 12.3867
v 16.0000 0.0000 12.0000
v 15.6328 0.7500 12.3340
v 15.0000 0.5625 12.0000
v 1.1552 -1.1552 14.9063
v 1.6250 0.0000 14.9063
v 0.0000 0.0000 15.7500
v 0.7100 -0.7100 13.5000
v 1.0000 0.0000 13.5000
v 0.0000 -1.6250 14.9063
v 0.0000 -1.0000 13.5000
v -1.1552 -1.1552 14.9063
v -0.7100 -0.7100 13.5000
v -1.6250 0.0000 14.9063
v -1.0000 0.0000 13.5000
v -1.1552 1.1552 14.9063
v -0.7100 0.7100 13.5000
v 0.0000 1.6250 14.9063
v 0.0000 1.0000 13.5000
v 1.1552 1.1552 14.9063
v 0.7100 0.7100 13.5000
v 2.9288 -2.9288 12.7500
v 4.1250 0.0000 12.7500
v 4.6150 -4.6150 12.0000
v 6.5000 0.0000 12.0000
v 0.0000 -4.1250 12.7500
v 0.0000 -6.5000 12.0000
v -2.9288 -2.9288 12.7500
v -4.6150 -4.6150 12.0000
v -4.1250 0.0000 12.7500
v -6.5000 0.0000 12.0000
v -2.9288 2.9288 12.7500
v -4.6150 4.6150 12.0000
v 0.0000 4.1250 12.7500
v 0.0000 6.5000 12.0000
v 2.9288 2.9288 12.7500
v 4.6150 4.6150 12.0000
# 137 vertices
vn -0.9995 -0.0000 0.0317
vn -0.7067 0.7067 0.0319
vn -0.0966 0.0966 0.9906
vn -0.1416 0.0000 0.9899
vn 0.5936 -0.5936 0.5435
vn 0.8400 0.0000 0.5425
vn -0.0010 0.9996 0.0283
vn -0.0008 0.1421 0.9899
vn 0.0000 -0.8400 0.5425
vn 0.7268 0.6636 -0.1773
vn 0.0816 0.2165 0.9729
vn -0.5949 -0.5971 0.5381
vn 0.9994 -0.0148 0.0317
vn 0.1496 -0.0134 0.9886
vn -0.8403 0.0004 0.5422
vn 0.7067 -0.7067 0.0319
vn 0.0966 -0.0966 0.9906
vn -0.5936 0.5936 0.5435
vn 0.0000 -0.9995 0.0317
vn -0.0000 -0.1416 0.9899
vn -0.0000 0.8400 0.5425
vn -0.7067 -0.7067 0.0319
vn -0.0966 -0.0966 0.9906
vn 0.5936 0.5936 0.5435
vn 0.6738 -0.6738 0.3034
vn 0.9532 -0.0000 0.3025
vn 0.7028 -0.7028 -0.1107
vn 0.9939 -0.0000 -0.1105
vn -0.0000 -0.9532 0.3025
vn -0.0000 -0.9939 -0.1105
vn -0.6738 -0.6738 0.3034
vn -0.7028 -0.7028 -0.1107
vn -0.9532 0.0000 0.3025
vn -0.9939 0.0000 -0.1105
vn -0.6738 0.6738 0.3034
vn -0.7028 0.7028 -0.1107
vn 0.0000 0.9532 0.3025
vn 0.0000 0.9939 -0.1105
vn 0.6738 0.6738 0.3034
vn 0.7028 0.7028 -0.1107
vn 0.5792 -0.5792 -0.5735
vn 0.8198 0.0000 -0.5726
vn 0.4157 -0.4157 -0.8089
vn 0.5888 -0.0000 -0.8083
vn 0.0000 -0.8198 -0.5726
vn -0.0000 -0.5888 -0.8083
vn -0.5792 -0.5792 -0.5735
vn -0.4157 -0.4157 -0.8089
vn -0.8198 -0.0000 -0.5726
vn -0.5888 0.0000 -0.8083
vn -0.5792 0.5792 -0.5735
vn -0.4157 0.4157 -0.8089
vn -0.0000 0.8198 -0.5726
vn 0.0000 0.5888 -0.8083
vn 0.5792 0.5792 -0.5735
vn 0.4157 0.4157 -0.8089
vn 0.2016 -0.2016 -0.9585
vn 0.2850 -0.0000 -0.9585
vn 0.0000 -0.0000 -1.0000
vn -0.0000 -0.2850 -0.9585
vn -0.2016 -0.2016 -0.9585
vn -0.2850 0.0000 -0.9585
vn -0.2016 0.2016 -0.9585
vn 0.0000 0.2850 -0.9585
vn 0.2016 0.2016 -0.9585
vn 0.0384 0.0031 -0.9993
vn -0.0182 -0.9619 0.2727
vn -0.0190 -0.9786 0.2047
vn 0.2817 0.0145 -0.9594
vn -0.2938 -0.9475 0.1264
vn 0.9324 0.0422 -0.3590
vn -0.0473 -0.0015 0.9989
vn -0.4420 -0.0127 0.8969
vn -0.9859 -0.0106 0.1669
vn -0.0177 0.9631 0.2685
vn -0.0097 0.9839 0.1786
vn -0.2735 0.9565 0.1013
vn -0.1217 -0.9875 -0.0998
vn 0.8176 0.0138 0.5756
vn -0.3352 -0.7946 -0.5061
vn 0.6216 0.0294 0.7828
vn -0.7747 -0.0079 -0.6322
vn -0.5711 -0.0076 -0.8208
vn -0.1055 0.9904 -0.0889
vn -0.3009 0.8200 -0.4869
vn -0.4862 0.0074 0.8738
vn 0.3271 -0.9145 -0.2382
vn 0.1595 -0.9869 0.0246
vn -0.6970 -0.0236 0.7167
vn -0.0062 -0.9245 0.3812
vn -0.7234 -0.0562 0.6881
vn 0.6538 0.0025 -0.7567
vn 0.7677 0.0173 -0.6406
vn 0.6465 0.0447 -0.7616
vn 0.3456 0.9087 -0.2343
vn 0.1845 0.9828 0.0081
vn 0.0506 0.9476 0.3154
vn 0.2319 -0.5821 0.7793
vn 0.0415 -0.0704 0.9967
vn 0.3158 0.9477 -0.0454
vn 0.9011 -0.0135 -0.4334
vn 0.9533 0.0371 0.2997
vn -0.3219 0.0032 0.9468
vn 0.3655 0.5783 0.7294
vn 0.3394 -0.9333 -0.1174
vn 0.6774 -0.6773 0.2871
vn 0.9576 -0.0001 0.2882
vn 0.0000 0.0000 1.0000
vn 0.5955 -0.5952 0.5396
vn 0.8436 -0.0002 0.5370
vn -0.0001 -0.9576 0.2882
vn -0.0002 -0.8436 0.5370
vn -0.6773 -0.6774 0.2871
vn -0.5952 -0.5955 0.5396
vn -0.9576 0.0001 0.2882
vn -0.8436 0.0002 0.5370
vn -0.6774 0.6773 0.2871
vn -0.5955 0.5952 0.5396
vn 0.0001 0.9576 0.2882
vn 0.0002 0.8436 0.5370
vn 0.6773 0.6774 0.2871
vn 0.5952 0.5955 0.5396
vn 0.1942 -0.1942 0.9616
vn 0.2754 0.0000 0.9613
vn 0.2121 -0.2121 0.9539
vn 0.3011 0.0000 0.9536
vn 0.0000 -0.2754 0.9613
vn 0.0000 -0.3011 0.9536
vn -0.1942 -0.1942 0.9616
vn -0.2121 -0.2121 0.9539
vn -0.2754 -0.0000 0.9613
vn -0.3011 -0.0000 0.9536
vn -0.1942 0.1942 0.9616
vn -0.2121 0.2121 0.9539
vn -0.0000 0.2754 0.9613
vn -0.0000 0.3011 0.9536
vn 0.1942 0.1942 0.9616
vn 0.2121 0.2121 0.9539
# 138 vertex normals
vt 2.0000 2.0000 0.0000
vt 1.5000 2.0000 0.0000
vt 1.5000 1.9500 0.0000
vt 2.0000 1.9500 0.0000
vt 1.5000 1.9000 0.0000
vt 2.0000 1.9000 0.0000
vt 1.0000 2.0000 0.0000
vt 1.0000 1.9500 0.0000
vt 1.0000 1.9000 0.0000
vt 0.5000 2.0000 0.0000
vt 0.5000 1.9500 0.0000
vt 0.5000 1.9000 0.0000
vt 0.0000 2.0000 0.0000
vt 0.0000 1.9500 0.0000
vt 0.0000 1.9000 0.0000
vt 1.5000 1.4500 0.0000
vt 2.0000 1.4500 0.0000
vt 1.5000 1.0000 0.0000
vt 2.0000 1.0000 0.0000
vt 1.0000 1.4500 0.0000
vt 1.0000 1.0000 0.0000
vt 0.5000 1.4500 0.0000
vt 0.5000 1.0000 0.0000
vt 0.0000 1.4500 0.0000
vt 0.0000 1.0000 0.0000
vt 1.5000 0.7000 0.0000
vt 2.0000 0.7000 0.0000
vt 1.5000 0.4000 0.0000
vt 2.0000 0.4000 0.0000
vt 1.0000 0.7000 0.0000
vt 1.0000 0.4000 0.0000
vt 0.5000 0.7000 0.0000
vt 0.5000 0.4000 0.0000
vt 0.0000 0.7000 0.0000
vt 0.0000 0.4000 0.0000
vt 1.5000 0.2000 0.0000
vt 2.0000 0.2000 0.0000
vt 1.5000 0.0000 0.0000
vt 1.0000 0.2000 0.0000
vt 1.0000 0.0000 0.0000
vt 0.5000 0.2000 0.0000
vt 0.5000 0.0000 0.0000
vt 0.0000 0.2000 0.0000
vt 0.0000 0.0000 0.0000
vt 0.7500 1.0000 0.0000
vt 0.7500 0.7500 0.0000
vt 1.0000 0.7500 0.0000
vt 0.7500 0.5000 0.0000
vt 1.0000 0.5000 0.0000
vt 0.5000 0.7500 0.0000
vt 0.5000 0.5000 0.0000
vt 0.2500 1.0000 0.0000
vt 0.2500 0.7500 0.0000
vt 0.2500 0.5000 0.0000
vt 0.0000 0.7500 0.0000
vt 0.0000 0.5000 0.0000
vt 0.7500 0.2500 0.0000
vt 1.0000 0.2500 0.0000
vt 0.7500 0.0000 0.0000
vt 0.5000 0.2500 0.0000
vt 0.2500 0.2500 0.0000
vt 0.2500 0.0000 0.0000
vt 0.0000 0.2500 0.0000
vt 0.7500 0.4500 0.0000
vt 0.5000 0.4500 0.0000
vt 0.7500 0.9000 0.0000
vt 0.5000 0.9000 0.0000
vt 1.0000 0.4500 0.0000
vt 1.0000 0.9000 0.0000
vt 0.2500 0.4500 0.0000
vt 0.0000 0.4500 0.0000
vt 0.2500 0.9000 0.0000
vt 0.0000 0.9000 0.0000
vt 0.7500 0.9500 0.0000
vt 0.5000 0.9500 0.0000
vt 1.0000 0.9500 0.0000
vt 0.2500 0.9500 0.0000
vt 0.0000 0.9500 0.0000
# 78 texture coords
g Teapot001
f 1/1/1 2/2/2 3/3/3 4/4/4
f 4/4/4 3/3/3 5/5/5 6/6/6
f 2/2/2 7/7/7 8/8/8 3/3/3
f 3/3/3 8/8/8 9/9/9 5/5/5
f 7/7/7 10/10/10 11/11/11 8/8/8
f 8/8/8 11/11/11 12/12/12 9/9/9
f 10/10/10 13/13/13 14/14/14 11/11/11
f 11/11/11 14/14/14 15/15/15 12/12/12
f 13/1/13 16/2/16 17/3/17 14/4/14
f 14/4/14 17/3/17 18/5/18 15/6/15
f 16/2/16 19/7/19 20/8/20 17/3/17
f 17/3/17 20/8/20 21/9/21 18/5/18
f 19/7/19 22/10/22 23/11/23 20/8/20
f 20/8/20 23/11/23 24/12/24 21/9/21
f 22/10/22 1/13/1 4/14/4 23/11/23
f 23/11/23 4/14/4 6/15/6 24/12/24
f 6/6/6 5/5/5 25/16/25 26/17/26
f 26/17/26 25/16/25 27/18/27 28/19/28
f 5/5/5 9/9/9 29/20/29 25/16/25
f 25/16/25 29/20/29 30/21/30 27/18/27
f 9/9/9 12/12/12 31/22/31 29/20/29
f 29/20/29 31/22/31 32/23/32 30/21/30
f 12/12/12 15/15/15 33/24/33 31/22/31
f 31/22/31 33/24/33 34/25/34 32/23/32
f 15/6/15 18/5/18 35/16/35 33/17/33
f 33/17/33 35/16/35 36/18/36 34/19/34
f 18/5/18 21/9/21 37/20/37 35/16/35
f 35/16/35 37/20/37 38/21/38 36/18/36
f 21/9/21 24/12/24 39/22/39 37/20/37
f 37/20/37 39/22/39 40/23/40 38/21/38
f 24/12/24 6/15/6 26/24/26 39/22/39
f 39/22/39 26/24/26 28/25/28 40/23/40
f 28/19/28 27/18/27 41/26/41 42/27/42
f 42/27/42 41/26/41 43/28/43 44/29/44
f 27/18/27 30/21/30 45/30/45 41/26/41
f 41/26/41 45/30/45 46/31/46 43/28/43
f 30/21/30 32/23/32 47/32/47 45/30/45
f 45/30/45 47/32/47 48/33/48 46/31/46
f 32/23/32 34/25/34 49/34/49 47/32/47
f 47/32/47 49/34/49 50/35/50 48/33/48
f 34/19/34 36/18/36 51/26/51 49/27/49
f 49/27/49 51/26/51 52/28/52 50/29/50
f 36/18/36 38/21/38 53/30/53 51/26/51
f 51/26/51 53/30/53 54/31/54 52/28/52
f 38/21/38 40/23/40 55/32/55 53/30/53
f 53/30/53 55/32/55 56/33/56 54/31/54
f 40/23/40 28/25/28 42/34/42 55/32/55
f 55/32/55 42/34/42 44/35/44 56/33/56
f 44/29/44 43/28/43 57/36/57 58/37/58
f 58/37/58 57/36/57 59/38/59
f 43/28/43 46/31/46 60/39/60 57/36/57
f 57/36/57 60/39/60 59/40/59
f 46/31/46 48/33/48 61/41/61 60/39/60
f 60/39/60 61/41/61 59/42/59
f 48/33/48 50/35/50 62/43/62 61/41/61
f 61/41/61 62/43/62 59/44/59
f 50/29/50 52/28/52 63/36/63 62/37/62
f 62/37/62 63/36/63 59/38/59
f 52/28/52 54/31/54 64/39/64 63/36/63
f 63/36/63 64/39/64 59/40/59
f 54/31/54 56/33/56 65/41/65 64/39/64
f 64/39/64 65/41/65 59/42/59
f 56/33/56 44/35/44 58/43/58 65/41/65
f 65/41/65 58/43/58 59/44/59
f 66/21/66 67/45/67 68/46/68 69/47/69
f 69/47/69 68/46/68 70/48/70 71/49/71
f 67/45/67 72/23/72 73/50/73 68/46/68
f 68/46/68 73/50/73 74/51/74 70/48/70
f 72/23/72 75/52/75 76/53/76 73/50/73
f 73/50/73 76/53/76 77/54/77 74/51/74
f 75/52/75 66/25/66 69/55/69 76/53/76
f 76/53/76 69/55/69 71/56/71 77/54/77
f 71/49/71 70/48/70 78/57/78 79/58/79
f 79/58/79 78/57/78 80/59/80 34/40/81
f 70/48/70 74/51/74 81/60/82 78/57/78
f 78/57/78 81/60/82 82/42/83 80/59/80
f 74/51/74 77/54/77 83/61/84 81/60/82
f 81/60/82 83/61/84 84/62/85 82/42/83
f 77/54/77 71/56/71 79/63/79 83/61/84
f 83/61/84 79/63/79 34/44/81 84/62/85
f 85/42/86 86/59/87 87/64/88 88/65/89
f 88/65/89 87/64/88 89/66/90 90/67/91
f 86/59/87 91/40/92 92/68/93 87/64/88
f 87/64/88 92/68/93 93/69/94 89/66/90
f 91/44/92 94/62/95 95/70/96 92/71/93
f 92/71/93 95/70/96 96/72/97 93/73/94
f 94/62/95 85/42/86 88/65/89 95/70/96
f 95/70/96 88/65/89 90/67/91 96/72/97
f 90/67/91 89/66/90 97/74/98 98/75/99
f 98/75/99 97/74/98 99/45/100 100/23/101
f 89/66/90 93/69/94 101/76/102 97/74/98
f 97/74/98 101/76/102 102/21/103 99/45/100
f 93/73/94 96/72/97 103/77/104 101/78/102
f 101/78/102 103/77/104 104/52/105 102/25/103
f 96/72/97 90/67/91 98/75/99 103/77/104
f 103/77/104 98/75/99 100/23/101 104/52/105
f 105/48/106 106/49/107 107/21/108
f 106/49/107 105/48/106 108/59/109 109/40/110
f 110/51/111 105/48/106 107/45/108
f 105/48/106 110/51/111 111/42/112 108/59/109
f 112/54/113 110/51/111 107/23/108
f 110/51/111 112/54/113 113/62/114 111/42/112
f 114/56/115 112/54/113 107/52/108
f 112/54/113 114/56/115 115/44/116 113/62/114
f 116/48/117 114/49/115 107/21/108
f 114/49/115 116/48/117 117/59/118 115/40/116
f 118/51/119 116/48/117 107/45/108
f 116/48/117 118/51/119 119/42/120 117/59/118
f 120/54/121 118/51/119 107/23/108
f 118/51/119 120/54/121 121/62/122 119/42/120
f 106/56/107 120/54/121 107/52/108
f 120/54/121 106/56/107 109/44/110 121/62/122
f 109/21/110 108/45/109 122/48/123 123/49/124
f 123/49/124 122/48/123 124/59/125 125/40/126
f 108/45/109 111/23/112 126/51/127 122/48/123
f 122/48/123 126/51/127 127/42/128 124/59/125
f 111/23/112 113/52/114 128/54/129 126/51/127
f 126/51/127 128/54/129 129/62/130 127/42/128
f 113/52/114 115/25/116 130/56/131 128/54/129
f 128/54/129 130/56/131 131/44/132 129/62/130
f 115/21/116 117/45/118 132/48/133 130/49/131
f 130/49/131 132/48/133 133/59/134 131/40/132
f 117/45/118 119/23/120 134/51/135 132/48/133
f 132/48/133 134/51/135 135/42/136 133/59/134
f 119/23/120 121/52/122 136/54/137 134/51/135
f 134/51/135 136/54/137 137/62/138 135/42/136
f 121/52/122 109/25/110 123/56/124 136/54/137
f 136/54/137 123/56/124 125/44/126 137/62/138
# 112 polygons - 16 triangles

274
external/teapot-lowtri.obj vendored Normal file
View File

@@ -0,0 +1,274 @@
#
# object Teapot001
#
v 7.0000 0.0000 12.0000
v 4.9700 -4.9700 12.0000
v 4.9811 -4.9811 12.4922
v 7.0156 0.0000 12.4922
v 5.3250 -5.3250 12.0000
v 7.5000 0.0000 12.0000
v 0.0000 -7.0000 12.0000
v 0.0000 -7.0156 12.4922
v 0.0000 -7.5000 12.0000
v -5.1387 -4.9700 12.0000
v -5.0022 -4.9811 12.4922
v -5.3250 -5.3250 12.0000
v -7.0000 0.0000 12.0000
v -7.0156 0.0000 12.4922
v -7.5000 0.0000 12.0000
v -4.9700 4.9700 12.0000
v -4.9811 4.9811 12.4922
v -5.3250 5.3250 12.0000
v 0.0000 7.0000 12.0000
v 0.0000 7.0156 12.4922
v 0.0000 7.5000 12.0000
v 4.9700 4.9700 12.0000
v 4.9811 4.9811 12.4922
v 5.3250 5.3250 12.0000
v 6.5453 -6.5453 8.1094
v 9.2188 0.0000 8.1094
v 7.1000 -7.1000 4.5000
v 10.0000 0.0000 4.5000
v 0.0000 -9.2188 8.1094
v 0.0000 -10.0000 4.5000
v -6.5453 -6.5453 8.1094
v -7.1000 -7.1000 4.5000
v -9.2188 0.0000 8.1094
v -10.0000 0.0000 4.5000
v -6.5453 6.5453 8.1094
v -7.1000 7.1000 4.5000
v 0.0000 9.2188 8.1094
v 0.0000 10.0000 4.5000
v 6.5453 6.5453 8.1094
v 7.1000 7.1000 4.5000
v 6.2125 -6.2125 1.9219
v 8.7500 0.0000 1.9219
v 5.3250 -5.3250 0.7500
v 7.5000 0.0000 0.7500
v 0.0000 -8.7500 1.9219
v 0.0000 -7.5000 0.7500
v -6.2125 -6.2125 1.9219
v -5.3250 -5.3250 0.7500
v -8.7500 0.0000 1.9219
v -7.5000 0.0000 0.7500
v -6.2125 6.2125 1.9219
v -5.3250 5.3250 0.7500
v 0.0000 8.7500 1.9219
v 0.0000 7.5000 0.7500
v 6.2125 6.2125 1.9219
v 5.3250 5.3250 0.7500
v 4.5595 -4.5595 0.2344
v 6.4219 0.0000 0.2344
v 0.0000 0.0000 0.0000
v 0.0000 -6.4219 0.2344
v -4.5595 -4.5595 0.2344
v -6.4219 0.0000 0.2344
v -4.5595 4.5595 0.2344
v 0.0000 6.4219 0.2344
v 4.5595 4.5595 0.2344
v -8.0000 0.0000 10.1250
v -7.7500 -1.1250 10.6875
v -12.5938 -1.1250 10.4766
v -12.0625 0.0000 9.9844
v -14.2500 -1.1250 9.0000
v -13.5000 0.0000 9.0000
v -7.5000 0.0000 11.2500
v -13.1250 0.0000 10.9688
v -15.0000 0.0000 9.0000
v -7.7500 1.1250 10.6875
v -12.5938 1.1250 10.4766
v -14.2500 1.1250 9.0000
v -13.1719 -1.1250 6.2695
v -12.6875 0.0000 6.7500
v -9.7500 -1.1250 3.7500
v -13.6563 0.0000 5.7891
v -9.5000 0.0000 3.0000
v -13.1719 1.1250 6.2695
v -9.7500 1.1250 3.7500
v 8.5000 0.0000 7.1250
v 8.5000 -2.4750 5.0625
v 12.6875 -1.7062 8.1094
v 11.9375 0.0000 9.0000
v 15.0000 -0.9375 12.0000
v 13.5000 0.0000 12.0000
v 8.5000 0.0000 3.0000
v 13.4375 0.0000 7.2187
v 16.5000 0.0000 12.0000
v 8.5000 2.4750 5.0625
v 12.6875 1.7062 8.1094
v 15.0000 0.9375 12.0000
v 15.6328 -0.7500 12.3340
v 14.1250 0.0000 12.2813
v 15.0000 -0.5625 12.0000
v 14.0000 0.0000 12.0000
v 17.1406 0.0000 12.3867
v 16.0000 0.0000 12.0000
v 15.6328 0.7500 12.3340
v 15.0000 0.5625 12.0000
v 1.1552 -1.1552 14.9063
v 1.6250 0.0000 14.9063
v 0.0000 0.0000 15.7500
v 0.7100 -0.7100 13.5000
v 1.0000 0.0000 13.5000
v 0.0000 -1.6250 14.9063
v 0.0000 -1.0000 13.5000
v -1.1552 -1.1552 14.9063
v -0.7100 -0.7100 13.5000
v -1.6250 0.0000 14.9063
v -1.0000 0.0000 13.5000
v -1.1552 1.1552 14.9063
v -0.7100 0.7100 13.5000
v 0.0000 1.6250 14.9063
v 0.0000 1.0000 13.5000
v 1.1552 1.1552 14.9063
v 0.7100 0.7100 13.5000
v 2.9288 -2.9288 12.7500
v 4.1250 0.0000 12.7500
v 4.6150 -4.6150 12.0000
v 6.5000 0.0000 12.0000
v 0.0000 -4.1250 12.7500
v 0.0000 -6.5000 12.0000
v -2.9288 -2.9288 12.7500
v -4.6150 -4.6150 12.0000
v -4.1250 0.0000 12.7500
v -6.5000 0.0000 12.0000
v -2.9288 2.9288 12.7500
v -4.6150 4.6150 12.0000
v 0.0000 4.1250 12.7500
v 0.0000 6.5000 12.0000
v 2.9288 2.9288 12.7500
v 4.6150 4.6150 12.0000
# 137 vertices
g Teapot001
f 1 2 3 4
f 4 3 5 6
f 2 7 8 3
f 3 8 9 5
f 7 10 11 8
f 8 11 12 9
f 10 13 14 11
f 11 14 15 12
f 13 16 17 14
f 14 17 18 15
f 16 19 20 17
f 17 20 21 18
f 19 22 23 20
f 20 23 24 21
f 22 1 4 23
f 23 4 6 24
f 6 5 25 26
f 26 25 27 28
f 5 9 29 25
f 25 29 30 27
f 9 12 31 29
f 29 31 32 30
f 12 15 33 31
f 31 33 34 32
f 15 18 35 33
f 33 35 36 34
f 18 21 37 35
f 35 37 38 36
f 21 24 39 37
f 37 39 40 38
f 24 6 26 39
f 39 26 28 40
f 28 27 41 42
f 42 41 43 44
f 27 30 45 41
f 41 45 46 43
f 30 32 47 45
f 45 47 48 46
f 32 34 49 47
f 47 49 50 48
f 34 36 51 49
f 49 51 52 50
f 36 38 53 51
f 51 53 54 52
f 38 40 55 53
f 53 55 56 54
f 40 28 42 55
f 55 42 44 56
f 44 43 57 58
f 58 57 59
f 43 46 60 57
f 57 60 59
f 46 48 61 60
f 60 61 59
f 48 50 62 61
f 61 62 59
f 50 52 63 62
f 62 63 59
f 52 54 64 63
f 63 64 59
f 54 56 65 64
f 64 65 59
f 56 44 58 65
f 65 58 59
f 66 67 68 69
f 69 68 70 71
f 67 72 73 68
f 68 73 74 70
f 72 75 76 73
f 73 76 77 74
f 75 66 69 76
f 76 69 71 77
f 71 70 78 79
f 79 78 80 34
f 70 74 81 78
f 78 81 82 80
f 74 77 83 81
f 81 83 84 82
f 77 71 79 83
f 83 79 34 84
f 85 86 87 88
f 88 87 89 90
f 86 91 92 87
f 87 92 93 89
f 91 94 95 92
f 92 95 96 93
f 94 85 88 95
f 95 88 90 96
f 90 89 97 98
f 98 97 99 100
f 89 93 101 97
f 97 101 102 99
f 93 96 103 101
f 101 103 104 102
f 96 90 98 103
f 103 98 100 104
f 105 106 107
f 106 105 108 109
f 110 105 107
f 105 110 111 108
f 112 110 107
f 110 112 113 111
f 114 112 107
f 112 114 115 113
f 116 114 107
f 114 116 117 115
f 118 116 107
f 116 118 119 117
f 120 118 107
f 118 120 121 119
f 106 120 107
f 120 106 109 121
f 109 108 122 123
f 123 122 124 125
f 108 111 126 122
f 122 126 127 124
f 111 113 128 126
f 126 128 129 127
f 113 115 130 128
f 128 130 131 129
f 115 117 132 130
f 130 132 133 131
f 117 119 134 132
f 132 134 135 133
f 119 121 136 134
f 134 136 137 135
f 121 109 123 136
f 136 123 125 137
# 112 polygons - 16 triangles

11284
external/teapot.obj vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
output/arealight_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
output/ch10_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
output/ch11_reflection.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 KiB

BIN
output/ch11_refraction.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

BIN
output/ch11_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
output/ch12_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
output/ch13_cone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

BIN
output/ch13_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
output/ch14_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

BIN
output/ch16_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
output/ch5_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

BIN
output/ch6_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
output/ch7_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
output/ch8_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
output/ch9_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
output/christmasball.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 KiB

BIN
output/dragon_scene.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
output/uvmap_earth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
output/uvmap_skybox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

685
samplescenes/orrery.yml Normal file
View File

@@ -0,0 +1,685 @@
# ======================================================
# orrery.yml
#
# This file describes the title image for the "Texture
# Mapping" bonus chapter at:
#
# http://www.raytracerchallenge.com/bonus/texture-mapping.html
#
# It requires several additional resources, provided as a
# separate download. The resources were found on the following
# sites:
#
# * https://www.bittbox.com/freebies/free-hi-resolution-wood-textures
# : the wooden texture for the table
# * https://astrogeology.usgs.gov/search/map/Mercury/Messenger/Global/Mercury_MESSENGER_MDIS_Basemap_LOI_Mosaic_Global_166m
# : the map of Mercury
# * http://planetpixelemporium.com/planets.html
# : maps of Earth, Mars, Jupiter, Saturn, Uranus, and Neptune
# * https://hdrihaven.com/hdri/?c=indoor&h=artist_workshop
# : the "artist workshop" environment map
#
# by Jamis Buck <jamis@jamisbuck.org>
# ======================================================
- add: camera
width: 800
height: 400
field-of-view: 1.2
from: [ 2, 4, -10]
to: [ -1, -1, 0 ]
up: [ 0, 1, 0 ]
# The scene as shown in the bonus chapter is rendered using an area light,
# precisely as described in the "Rendering soft shadows" bonus chapter,
# here: http://www.raytracerchallenge.com/bonus/area-light.html
#
# if you haven't implemented area lights, you can replace this with a point
# light located at [0, 2.5, -10].
- add: light
corner: [-5, 0, -10 ]
uvec: [ 10, 0, 0 ]
vvec: [ 0, 5, 0 ]
usteps: 10
vsteps: 5
jitter: true
intensity: [ 1, 1, 1 ]
# -------------------------------------------
# some common textures
# -------------------------------------------
- define: GOLD
value:
color: [ 1, 0.8, 0.1 ]
ambient: 0.1
diffuse: 0.6
specular: 0.3
shininess: 15
- define: SILVER
value:
color: [ 1, 1, 1 ]
ambient: 0.1
diffuse: 0.7
specular: 0.3
shininess: 15
# -----------------------------------------------
# CSG definition for the gears used to construct
# the orrery.
#
# NOTCH is a helper object used to create the
# teeth for the gears.
#
# GEAR is the actual gear object itself.
# -----------------------------------------------
- define: NOTCH
value:
add: csg
operation: difference
left:
type: cube
transform:
- [ scale, 1, 0.25, 1 ]
- [ translate, 1, 0, 1 ]
- [ rotate-y, 0.7854 ]
- [ scale, 1, 1, 0.1 ]
right:
type: cylinder
min: -0.26
max: 0.26
closed: true
transform:
- [ scale, 0.8, 1, 0.8 ]
- define: GEAR
value:
add: csg
operation: difference
left:
type: cylinder
min: -0.025
max: 0.025
closed: true
right:
type: group
children:
# center hole
- add: cylinder
min: -0.06
max: 0.06
closed: true
transform:
- [ scale, 0.1, 1, 0.1 ]
# crescents
- add: csg
operation: difference
left:
type: cylinder
min: -0.06
max: 0.06
closed: true
transform:
- [ scale, 0.7, 1, 0.7 ]
right:
type: cube
transform:
- [ scale, 1, 0.1, 0.2 ]
# teeth
- add: NOTCH
- add: NOTCH
transform:
- [ rotate-y, 0.31415 ]
- add: NOTCH
transform:
- [ rotate-y, 0.6283 ]
- add: NOTCH
transform:
- [ rotate-y, 0.94245 ]
- add: NOTCH
transform:
- [ rotate-y, 1.2566 ]
- add: NOTCH
transform:
- [ rotate-y, 1.57075 ]
- add: NOTCH
transform:
- [ rotate-y, 1.8849 ]
- add: NOTCH
transform:
- [ rotate-y, 2.19905 ]
- add: NOTCH
transform:
- [ rotate-y, 2.5132 ]
- add: NOTCH
transform:
- [ rotate-y, 2.82735 ]
- add: NOTCH
transform:
- [ rotate-y, 3.1415 ]
- add: NOTCH
transform:
- [ rotate-y, -0.31415 ]
- add: NOTCH
transform:
- [ rotate-y, -0.6283 ]
- add: NOTCH
transform:
- [ rotate-y, -0.94245 ]
- add: NOTCH
transform:
- [ rotate-y, -1.2566 ]
- add: NOTCH
transform:
- [ rotate-y, -1.57075 ]
- add: NOTCH
transform:
- [ rotate-y, -1.8849 ]
- add: NOTCH
transform:
- [ rotate-y, -2.19905 ]
- add: NOTCH
transform:
- [ rotate-y, -2.5132 ]
- add: NOTCH
transform:
- [ rotate-y, -2.82735 ]
# mechanism: top plate
- add: csg
operation: difference
material: GOLD
transform:
- [ rotate-y, -1 ]
left:
type: cylinder
min: -1.51
max: -1.5
closed: true
right:
type: group
children:
- add: cylinder
min: -1.52
max: -1.49
closed: true
transform:
- [ scale, 0.1, 1, 0.1 ]
- add: csg
operation: difference
left:
type: cylinder
min: -1.52
max: -1.49
closed: true
transform:
- [ scale, 0.75, 1, 0.75 ]
right:
type: cube
transform:
- [ scale, 1, 0.1, 0.2 ]
- [ translate, 0, -1.5, 0 ]
# mechanism: gear
- add: GEAR
material: SILVER
transform:
- [ scale, 0.5, 0.5, 0.5 ]
- [ translate, 0.4, -1.45, -0.4 ]
# mechanism: gear
- add: GEAR
material: SILVER
transform:
- [ rotate-y, 0.8 ]
- [ scale, 0.4, 0.4, 0.4 ]
- [ translate, -0.4, -1.45, 0.2 ]
# sun
- add: group
children:
- add: sphere
shadow: false
material:
color: [1, 1, 0]
ambient: 0.1
diffuse: 0.6
specular: 0 # count on the skybox reflection being the specular highlight
reflective: 0.2
- add: group
material: GOLD
children:
- add: cylinder
min: -4
max: -0.5
transform:
- [ scale, 0.025, 1, 0.025 ]
# base
- add: sphere
transform:
- [ translate, 0, -4, 0 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: checkers
width: 16
height: 8
colors:
- [ 0, 0, 0 ]
- [ 0.5, 0.5, 0.5 ]
diffuse: 0.6
specular: 0 # count on the skybox reflection being the specular highlight
ambient: 0.1
reflective: 0.2
# table
- add: cube
transform:
- [ scale, 5, 0.1, 5 ]
- [ translate, 0, -4, 0 ]
material:
diffuse: 0.9
ambient: 0.1
specular: 0
pattern:
type: map
mapping: planar
uv_pattern:
type: image
file: res/wood.ppm
transform:
- [ scale, 0.5, 0.5, 0.5 ]
# mechanism: gear-plate between top & mercury
- add: GEAR
material: SILVER
transform:
- [ rotate-y, -0.4 ]
- [ scale, 0.9, 0.9, 0.9 ]
- [ translate, 0, -1.75, 0 ]
# mercury
- add: group
transform:
- [ translate, 2, 0, 0 ]
- [ rotate-y, 0.7 ]
children:
- add: sphere
transform:
- [ scale, 0.25, 0.25, 0.25 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: image
file: res/mercury-small.ppm
- add: group
material: GOLD
children:
- add: cylinder
min: -2
max: 0
transform:
- [ scale, 0.025, 1, 0.025 ]
- add: sphere
transform:
- [ scale, 0.025, 0.025, 0.025 ]
- [ translate, 0, -2, 0 ]
- add: cylinder
min: 0
max: 2
transform:
- [ scale, 0.025, 1, 0.025 ]
- [ rotate-z, 1.5708 ]
- [ translate, 0, -2, 0 ]
# mechanism: gear-plate between mercury & venus
- add: GEAR
material: SILVER
transform:
- [ rotate-y, 1.3 ]
- [ translate, 0, -2.05, 0 ]
# venus
- add: group
transform:
- [ translate, 3, 0, 0 ]
- [ rotate-y, 0.3 ]
children:
- add: sphere
transform:
- [ scale, 0.25, 0.25, 0.25 ]
material:
color: [ 1, 1, 0.8 ]
- add: group
material: GOLD
children:
- add: cylinder
min: -2.1
max: 0
transform:
- [ scale, 0.025, 1, 0.025 ]
- add: sphere
transform:
- [ scale, 0.025, 0.025, 0.025 ]
- [ translate, 0, -2.1, 0 ]
- add: cylinder
min: 0
max: 3
transform:
- [ scale, 0.025, 1, 0.025 ]
- [ rotate-z, 1.5708 ]
- [ translate, 0, -2.1, 0 ]
# mechanism: gear-plate between venus & earth
- add: GEAR
material: SILVER
transform:
- [ scale, 0.9, 0.9, 0.9 ]
- [ rotate-y, -2.2 ]
- [ translate, 0, -2.15, 0 ]
# earth
- add: group
transform:
- [ translate, 4, 0, 0 ]
- [ rotate-y, 2 ]
children:
- add: sphere
transform:
- [ scale, 0.25, 0.25, 0.25 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: image
file: res/earthmap-small.ppm
- add: group
material: GOLD
children:
- add: cylinder
min: -2.2
max: 0
transform:
- [ scale, 0.025, 1, 0.025 ]
- add: sphere
transform:
- [ scale, 0.025, 0.025, 0.025 ]
- [ translate, 0, -2.2, 0 ]
- add: cylinder
min: 0
max: 4
transform:
- [ scale, 0.025, 1, 0.025 ]
- [ rotate-z, 1.5708 ]
- [ translate, 0, -2.2, 0 ]
# mechanism: gear-plate between earth & mars
- add: GEAR
material: SILVER
transform:
- [ scale, 0.8, 0.8, 0.8 ]
- [ rotate-y, 1.7 ]
- [ translate, 0, -2.25, 0 ]
# mars
- add: group
transform:
- [ translate, 5, 0, 0 ]
- [ rotate-y, -2 ]
children:
- add: sphere
transform:
- [ scale, 0.25, 0.25, 0.25 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: image
file: res/mars-small.ppm
- add: group
material: GOLD
children:
- add: cylinder
min: -2.3
max: 0
transform:
- [ scale, 0.025, 1, 0.025 ]
- add: sphere
transform:
- [ scale, 0.025, 0.025, 0.025 ]
- [ translate, 0, -2.3, 0 ]
- add: cylinder
min: 0
max: 5
transform:
- [ scale, 0.025, 1, 0.025 ]
- [ rotate-z, 1.5708 ]
- [ translate, 0, -2.3, 0 ]
# mechanism: gear-plate between mars & jupiter
- add: GEAR
material: SILVER
transform:
- [ rotate-y, -0.9 ]
- [ translate, 0, -2.35, 0 ]
# jupiter
- add: group
transform:
- [ translate, 6.5, 0, 0 ]
- [ rotate-y, -0.75 ]
children:
- add: sphere
transform:
- [ scale, 0.67, 0.67, 0.67 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: image
file: res/jupitermap-small.ppm
- add: group
material: GOLD
children:
- add: cylinder
min: -2.4
max: 0
transform:
- [ scale, 0.025, 1, 0.025 ]
- add: sphere
transform:
- [ scale, 0.025, 0.025, 0.025 ]
- [ translate, 0, -2.4, 0 ]
- add: cylinder
min: 0
max: 6.5
transform:
- [ scale, 0.025, 1, 0.025 ]
- [ rotate-z, 1.5708 ]
- [ translate, 0, -2.4, 0 ]
# mechanism: gear-plate between jupiter & saturn
- add: GEAR
material: SILVER
transform:
- [ scale, 0.95, 0.95, 0.95 ]
- [ rotate-y, -1.1 ]
- [ translate, 0, -2.45, 0 ]
# saturn
- add: group
transform:
- [ translate, 8, 0, 0 ]
- [ rotate-y, -2.5 ]
children:
- add: sphere
transform:
- [ scale, 0.5, 0.5, 0.5 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: image
file: res/saturnmap-small.ppm
# rings
- add: csg
operation: difference
transform:
- [ rotate-z, 0.2 ]
material:
pattern:
type: rings
colors:
- [ 1, 1, 0.5 ]
- [ 1, 1, 0 ]
transform:
- [ scale, 0.05, 1, 0.05 ]
left:
type: cylinder
min: -0.01
max: 0.01
closed: true
transform:
- [ scale, 1.2, 1, 1.2 ]
right:
type: cylinder
min: -0.02
max: 0.02
closed: true
transform:
- [ scale, 0.75, 1, 0.75 ]
- add: group
material: GOLD
children:
- add: cylinder
min: -2.5
max: 0
transform:
- [ scale, 0.025, 1, 0.025 ]
- add: sphere
transform:
- [ scale, 0.025, 0.025, 0.025 ]
- [ translate, 0, -2.5, 0 ]
- add: cylinder
min: 0
max: 8
transform:
- [ scale, 0.025, 1, 0.025 ]
- [ rotate-z, 1.5708 ]
- [ translate, 0, -2.5, 0 ]
# mechanism: gear-plate between saturn & uranus
- add: GEAR
material: SILVER
transform:
- [ scale, 0.9, 0.9, 0.9 ]
- [ rotate-y, 1 ]
- [ translate, 0, -2.55, 0 ]
# uranus
- add: group
transform:
- [ translate, 9, 0, 0 ]
- [ rotate-y, -3 ]
children:
- add: sphere
transform:
- [ scale, 0.4, 0.4, 0.4 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: image
file: res/uranusmap-small.ppm
- add: group
material: GOLD
children:
- add: cylinder
min: -2.6
max: 0
transform:
- [ scale, 0.025, 1, 0.025 ]
- add: sphere
transform:
- [ scale, 0.025, 0.025, 0.025 ]
- [ translate, 0, -2.6, 0 ]
- add: cylinder
min: 0
max: 9
transform:
- [ scale, 0.025, 1, 0.025 ]
- [ rotate-z, 1.5708 ]
- [ translate, 0, -2.6, 0 ]
# mechanism: gear-plate between uranus & neptune
- add: GEAR
material: SILVER
transform:
- [ rotate-y, -1 ]
- [ translate, 0, -2.65, 0 ]
# neptune
- add: group
transform:
- [ translate, 10, 0, 0 ]
- [ rotate-y, -1.25 ]
children:
- add: sphere
transform:
- [ scale, 0.4, 0.4, 0.4 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: image
file: res/neptunemap-small.ppm
- add: group
material: GOLD
children:
- add: cylinder
min: -2.7
max: 0
transform:
- [ scale, 0.025, 1, 0.025 ]
- add: sphere
transform:
- [ scale, 0.025, 0.025, 0.025 ]
- [ translate, 0, -2.7, 0 ]
- add: cylinder
min: 0
max: 10
transform:
- [ scale, 0.025, 1, 0.025 ]
- [ rotate-z, 1.5708 ]
- [ translate, 0, -2.7, 0 ]
# outer sphere as the surrounding environment
- add: sphere
transform:
- [ scale, 1000, 1000, 1000 ]
material:
pattern:
type: map
mapping: spherical
uv_pattern:
type: image
file: res/artist_workshop.ppm
transform:
- [ rotate-y, -2.7 ]
diffuse: 0
specular: 0
ambient: 1

View File

@@ -1,16 +1,43 @@
# To simplify testing, the app is build in two passes, # To simplify testing, the app is build in two passes,
option(USE_OPENMP "Build using OpenMP" OFF)
if (USE_OPENMP)
find_package(OpenMP REQUIRED)
endif()
# First most is build as a library # First most is build as a library
add_library(rayonnement STATIC) add_library(rayonnement STATIC)
set(RAY_HEADERS include/tuples.h include/math_helper.h include/colour.h include/canvas.h include/matrix.h include/transformation.h) file(GLOB RAY_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/pattern/*.h
set(RAY_SOURCES tuples.cpp math_helper.cpp colour.cpp canvas.cpp matrix.cpp transformation.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/uvpattern/*.h)
target_include_directories(rayonnement PUBLIC include) file(GLOB RAY_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shapes/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/worldbuilder/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/worldoptimiser/*.cpp)
target_include_directories(rayonnement PUBLIC include pattern)
if (USE_LUA)
add_dependencies(rayonnement LuaCore)
target_link_libraries(rayonnement ${LUA_LIBRARIES})
target_include_directories(rayonnement PUBLIC ${LUA_INCLUDE_DIR})
endif()
target_include_directories(rayonnement PUBLIC include ${LODEPNG_INCLUDE_FOLDER} ${NANOJPEG_INCLUDE_FOLDER})
target_sources(rayonnement PRIVATE ${RAY_HEADERS} ${RAY_SOURCES}) target_sources(rayonnement PRIVATE ${RAY_HEADERS} ${RAY_SOURCES})
target_link_libraries(rayonnement LodePNG) target_link_libraries(rayonnement LodePNG NanoJPEG)
# Second we build the main executable if (USE_OPENMP)
add_executable(dorayme main.cpp) target_link_libraries(rayonnement OpenMP::OpenMP_CXX)
target_include_directories(rayonnement PUBLIC include ${LODEPNG_INCLUDE_FOLDER}) endif()
target_link_libraries(dorayme rayonnement)
# The main executable
#add_executable(dorayme main.cpp)
#add_dependencies(dorayme LuaCore)
#target_link_libraries(dorayme rayonnement ${LUA_LIBRARIES})
if (COVERALLS)
set(COVERAGE_SRCS ${RAY_HEADERS} ${RAY_SOURCES} ${COVERAGE_SRCS} PARENT_SCOPE)
endif()

102
source/camera.cpp Normal file
View File

@@ -0,0 +1,102 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Camera implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <matrix.h>
#include <stdint.h>
#include <math.h>
#include <ray.h>
#include <camera.h>
#include <stdio.h>
#include <renderstat.h>
Camera::Camera(uint32_t hsize, uint32_t vsize, double fov) : verticalSize(vsize),
horizontalSize(hsize), fieldOfView(fov), focalDistance(1), apertureSize(0), rayCount(1)
{
double aspectRatio = (double)hsize / (double)vsize;
double halfView = tan(fov / 2.0) * this->focalDistance;
if (aspectRatio >= 1)
{
this->halfWidth = halfView;
this->halfHeight = halfView / aspectRatio;
}
else
{
this->halfWidth = halfView * aspectRatio;
this->halfHeight = halfView;
}
this->pixelSize = (this->halfWidth * 2) / this->horizontalSize;
this->setTransform(Matrix4().identity());
}
void Camera::setTransform(Matrix transform)
{
this->transformMatrix = transform;
this->inverseTransform = transform.inverse();
}
Ray Camera::rayForPixel(uint32_t pixelX, uint32_t pixelY, double horzOffset, double vertOffset)
{
double xOffset = ((double)pixelX + 0.5) * this->pixelSize;
double yOffset = ((double)pixelY + 0.5) * this->pixelSize;
double worldX = this->halfWidth - xOffset;
double worldY = this->halfHeight - yOffset;
Tuple pixel = this->inverseTransform * Point(worldX, worldY, -this->focalDistance);
Tuple origin = this->inverseTransform * Point(horzOffset, vertOffset, 0);
Tuple direction = (pixel - origin).normalise();
stats.addCastedRay();
return Ray(origin, direction);
}
Canvas Camera::render(World world, uint32_t depth)
{
uint32_t x, y;
Canvas image = Canvas(this->horizontalSize, this->verticalSize);
#pragma omp parallel default(shared) private(x, y) shared(image, stats)
{
#pragma omp for schedule(dynamic, 5)
for (y = 0 ; y < this->verticalSize ; y++)
{
for (x = 0 ; x < this->horizontalSize ; x++)
{
Tuple colour;
if (this->apertureSize > 0)
{
int i;
for (i = 0 ; i < this->rayCount ; i++)
{
double horz = frandclip(-this->apertureSize/2, this->apertureSize / 2);
double vert = frandclip(-this->apertureSize/2, this->apertureSize / 2);
Ray r = this->rayForPixel(x, y, horz, vert);
colour = colour + world.colourAt(r, depth);
}
colour = colour / this->rayCount;
}
else
{
Ray r = this->rayForPixel(x, y);
colour = world.colourAt(r, depth);
}
stats.addPixel();
image.putPixel(x, y, colour);
}
}
}
stats.printStats();
return image;
}

View File

@@ -9,6 +9,16 @@
#include <canvas.h> #include <canvas.h>
#include <lodepng.h> #include <lodepng.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* NanoJPEG is a bit interesting to include as a header */
extern "C" {
#define _NJ_INCLUDE_HEADER_ONLY
#include <nanojpeg.c>
#undef _NJ_INCLUDE_HEADER_ONLY
}
#define BPP (24) #define BPP (24)
#define BytePP (BPP / 8) #define BytePP (BPP / 8)
@@ -22,6 +32,98 @@ Canvas::Canvas(uint32_t width, uint32_t height) : width(width), height(height)
this->stride = BytePP * width; this->stride = BytePP * width;
} }
Canvas::Canvas(const Canvas &b)
{
this->width = b.width;
this->height = b.height;
this->stride = b.stride;
this->bitmap = (uint8_t *)calloc(4, b.width * b.height);
memcpy(this->bitmap, b.bitmap, 4 * b.width * b.height);
}
Canvas::Canvas(const Canvas *b)
{
this->width = b->width;
this->height = b->height;
this->stride = b->stride;
this->bitmap = (uint8_t *)calloc(4, b->width * b->height);
memcpy(this->bitmap, b->bitmap, 4 * b->width * b->height);
}
Canvas::Canvas(const char *imgfile)
{
/* Try to determine the file type in a really lazy way */
const char *fileExt = strrchr(imgfile, '.');
this->bitmap = NULL;
if (fileExt == NULL)
{
printf("ERROR: Invalid file name '%s' - Can't determine the file format\n", imgfile);
}
else if (strncasecmp(fileExt, ".png", strlen(fileExt)) == 0)
{
uint32_t ret = lodepng_decode24_file(&this->bitmap, &this->width, &this->height, imgfile);
if (ret)
{
printf("ERROR: %s\n", lodepng_error_text(ret));
}
}
else if ( (strncasecmp(fileExt, ".jpg", strlen(fileExt)) == 0) || (strncasecmp(fileExt, ".jpeg", strlen(fileExt)) == 0) )
{
FILE *fp;
char *fileBuff;
size_t fileSize;
fp = fopen(imgfile, "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
fileSize = ftell(fp);
fileBuff = (char *)calloc(fileSize, 1);
fseek(fp, 0, SEEK_SET);
fileSize = fread(fileBuff, 1, fileSize, fp);
fclose(fp);
njInit();
if (!njDecode(fileBuff, fileSize))
{
this->width = njGetWidth();
this->height = njGetHeight();
/* Need to do a local copy */
this->bitmap = (uint8_t *)calloc(1, njGetImageSize());
memcpy(this->bitmap, njGetImage(), njGetImageSize());
}
else
{
printf("ERROR: Error while decoding the file '%s'\n", imgfile);
}
free(fileBuff);
njDone();
}
else
{
printf("ERROR: Can't open/find the file '%s'.\n", imgfile);
}
}
else
{
printf("ERROR: File extention '%s' is not a recognized one.\n", fileExt);
}
if (this->bitmap == NULL)
{
printf("ABORT: Opening image file '%s' failed\n", imgfile);
exit(-1);
}
this->stride = BytePP * width;
}
Canvas::~Canvas() Canvas::~Canvas()
{ {
if (this->bitmap != nullptr) if (this->bitmap != nullptr)
@@ -30,28 +132,23 @@ Canvas::~Canvas()
} }
} }
void Canvas::put_pixel(uint32_t x, uint32_t y, Colour c) void Canvas::putPixel(uint32_t x, uint32_t y, Tuple c)
{ {
uint32_t offset = y * this->stride + x * BytePP; uint32_t offset = y * this->stride + x * BytePP;
this->bitmap[offset + 0] = MAX(MIN(c.red() * 255, 255), 0); this->bitmap[offset + 0] = MAX(MIN(c.x * 255, 255), 0);
this->bitmap[offset + 1] = MAX(MIN(c.green() * 255, 255), 0); this->bitmap[offset + 1] = MAX(MIN(c.y * 255, 255), 0);
this->bitmap[offset + 2] = MAX(MIN(c.blue() * 255, 255), 0); this->bitmap[offset + 2] = MAX(MIN(c.z * 255, 255), 0);
} }
Colour Canvas::get_pixel(uint32_t x, uint32_t y) Colour Canvas::getPixel(uint32_t x, uint32_t y)
{ {
uint32_t offset = y * this->stride + x * BytePP; uint32_t offset = y * this->stride + x * BytePP;
return Colour(this->bitmap[offset + 0] / 255, this->bitmap[offset + 1] / 255, this->bitmap[offset + 2] / 255); return Colour(this->bitmap[offset + 0] / 255.0, this->bitmap[offset + 1] / 255.0, this->bitmap[offset + 2] / 255.0);
} }
bool Canvas::SaveAsPNG(const char *filename) bool Canvas::SaveAsPNG(const char *filename)
{ {
uint32_t ret = lodepng_encode24_file(filename, this->bitmap, this->width, this->height); uint32_t ret = lodepng_encode24_file(filename, this->bitmap, this->width, this->height);
if (ret > 0)
{
printf("lodepng_encode_file returned %d!\n", ret);
}
return ret == 0; return ret == 0;
} }

View File

@@ -0,0 +1,134 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Bounding box header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_BOUNDINGBOX_H
#define DORAYME_BOUNDINGBOX_H
#include <renderstat.h>
#include <stdio.h>
struct BoundingBox
{
private:
bool isReset;
public:
Tuple min;
Tuple max;
BoundingBox() : min(INFINITY, INFINITY, INFINITY, 1.0), max(-INFINITY, -INFINITY, -INFINITY, 1.0), isReset(true) { };
BoundingBox(Tuple min, Tuple max) : min(min), max(max), isReset(false) { };
void operator|(const BoundingBox &b) {
isReset = false;
if (this->min.x > b.min.x) { this->min.x = b.min.x; }
if (this->min.y > b.min.y) { this->min.y = b.min.y; }
if (this->min.z > b.min.z) { this->min.z = b.min.z; }
if (this->max.x < b.max.x) { this->max.x = b.max.x; }
if (this->max.y < b.max.y) { this->max.y = b.max.y; }
if (this->max.z < b.max.z) { this->max.z = b.max.z; }
}
void operator|(const Tuple &b) {
isReset = false;
if (this->min.x > b.x) { this->min.x = b.x; }
if (this->min.y > b.y) { this->min.y = b.y; }
if (this->min.z > b.z) { this->min.z = b.z; }
if (this->max.x < b.x) { this->max.x = b.x; }
if (this->max.y < b.y) { this->max.y = b.y; }
if (this->max.z < b.z) { this->max.z = b.z; }
}
bool haveFiniteBounds() { return this->min.isRepresentable() && this->max.isRepresentable(); };
bool fitsIn(const BoundingBox &other) {
bool fits = true;
if (this->min.x > other.min.x) { fits = false; }
if (this->min.y > other.min.y) { fits = false; }
if (this->min.z > other.min.z) { fits = false; }
if (this->max.x < other.max.x) { fits = false; }
if (this->max.y < other.max.y) { fits = false; }
if (this->max.z < other.max.z) { fits = false; }
return fits;
}
void checkAxis(double axeOrigin, double axeDirection, double xMin, double xMax, double *axeMin, double *axeMax)
{
double tMinNumerator = (xMin - axeOrigin);
double tMaxNumerator = (xMax - axeOrigin);
if (fabs(axeDirection) >= getEpsilon())
{
*axeMin = tMinNumerator / axeDirection;
*axeMax = tMaxNumerator / axeDirection;
}
else
{
*axeMin = tMinNumerator * INFINITY;
*axeMax = tMaxNumerator * INFINITY;
}
if (*axeMin > *axeMax)
{
double swap = *axeMax;
*axeMax = *axeMin;
*axeMin = swap;
}
}
void reset()
{
this->isReset = true;
min.x = min.y = min.z = INFINITY;
max.x = max.y = max.z = -INFINITY;
}
bool isEmpty() { return this->isReset; };
bool intesectMe(Ray r) {
double xtMin, xtMax, ytMin, ytMax, ztMin, ztMax;
double tMin, tMax;
this->checkAxis(r.origin.x, r.direction.x, this->min.x, this->max.x, &xtMin, &xtMax);
this->checkAxis(r.origin.y, r.direction.y, this->min.y, this->max.y, &ytMin, &ytMax);
this->checkAxis(r.origin.z, r.direction.z, this->min.z, this->max.z, &ztMin, &ztMax);
tMin = max3(xtMin, ytMin, ztMin);
tMax = min3(xtMax, ytMax, ztMax);
if (tMin <= tMax)
{
return true;
}
stats.addDiscardedIntersect();
return false;
}
void dumpMe(FILE *fp)
{
Tuple t = this->min;
fprintf(fp, "\"min\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
t = this->max;
fprintf(fp, "\"max\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
}
};
#endif /* DORAYME_BOUNDINGBOX_H */

47
source/include/camera.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Camera header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_CAMERA_H
#define DORAYME_CAMERA_H
#include <matrix.h>
#include <stdint.h>
#include <ray.h>
#include <canvas.h>
#include <world.h>
class Camera
{
private:
double halfWidth;
double halfHeight;
public:
double focalDistance;
double apertureSize;
uint32_t rayCount;
uint32_t verticalSize;
uint32_t horizontalSize;
double fieldOfView;
double pixelSize;
Matrix transformMatrix;
Matrix inverseTransform;
public:
Camera(uint32_t hsize, uint32_t vsize, double fov);
void setFocal(double focal, double aperture, uint32_t rayCount) {
this->focalDistance = focal;
this->apertureSize = aperture;
this->rayCount = rayCount;
}
void setTransform(Matrix transform);
Ray rayForPixel(uint32_t pixelX, uint32_t pixelY, double horzOffset = 0, double vertOffset = 0);
Canvas render(World w, uint32_t depth = 5);
};
#endif /* DORAYME_CAMERA_H */

View File

@@ -21,10 +21,14 @@ public:
uint32_t width, height; uint32_t width, height;
Canvas(uint32_t width, uint32_t height); Canvas(uint32_t width, uint32_t height);
Canvas(const Canvas *c);
Canvas(const Canvas &c);
Canvas(const char *imgfile);
~Canvas(); ~Canvas();
void put_pixel(uint32_t x, uint32_t y, Colour c); void putPixel(uint32_t x, uint32_t y, Tuple c);
Colour get_pixel(uint32_t x, uint32_t y); Colour getPixel(uint32_t x, uint32_t y);
bool SaveAsPNG(const char *filename); bool SaveAsPNG(const char *filename);
}; };

View File

@@ -9,7 +9,7 @@
#ifndef DORAYME_COLOUR_H #ifndef DORAYME_COLOUR_H
#define DORAYME_COLOUR_H #define DORAYME_COLOUR_H
#include <tuples.h> #include <tuple.h>
class Colour : public Tuple class Colour : public Tuple
{ {

39
source/include/cone.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Cone header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_CONE_H
#define DORAYME_CONE_H
#include <shape.h>
#include <ray.h>
#include <intersect.h>
#include <renderstat.h>
#include <stdio.h>
class Cone : public Shape {
protected:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
bool checkCap(Ray r, double t, double y);
void intersectCaps(Ray r, Intersect &xs);
public:
bool isClosed;
double minCap;
double maxCap;
Cone() : minCap(-INFINITY), maxCap(INFINITY), isClosed(false), Shape(Shape::CONE) { stats.addCone(); };
BoundingBox getLocalBounds();
bool haveFiniteBounds() { return !(isinf(this->minCap) || isinf(this->maxCap)); };
void dumpMe(FILE *fp);
};
#endif /* DORAYME_CONE_H */

56
source/include/csg.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* DoRayMe - a quick and dirty Raytracer
* CSG header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_CSG_H
#define DORAYME_CSG_H
#include <shape.h>
class CSG : public Shape
{
public:
enum OperationType
{
UNION,
DIFFERENCE,
INTERSECTION
};
protected:
Shape *left;
Shape *right;
OperationType operation;
BoundingBox bounds;
protected:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
BoundingBox getLocalBounds();
bool intersectionAllowed(bool leftHit, bool inLeft, bool inRight);
void filterIntersections(Intersect &xs, Intersect &ret);
void updateBoundingBox();
BoundingBox getBounds();
public:
CSG(OperationType operation, Shape *left, Shape *right);
void intersect(Ray &r, Intersect &xs);
bool includes(Shape *b);
void updateTransform();
void lock();
void dumpMe(FILE *fp);
};
#endif /* DORAYME_CSG_H */

32
source/include/cube.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Cube header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_CUBE_H
#define DORAYME_CUBE_H
#include <shape.h>
#include <ray.h>
#include <intersect.h>
#include <renderstat.h>
#include <stdio.h>
class Cube : public Shape {
protected:
void checkAxis(double axeOrigin, double axeDirection, double *axeMin, double *axeMax);
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
Cube() : Shape(Shape::CUBE) { stats.addCube(); };
void dumpMe(FILE *fp);
};
#endif /* DORAYME_CUBE_H */

41
source/include/cylinder.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Cylinder header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_CYLINDER_H
#define DORAYME_CYLINDER_H
#include <shape.h>
#include <ray.h>
#include <intersect.h>
#include <renderstat.h>
#include <stdio.h>
class Cylinder : public Shape {
protected:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
bool checkCap(Ray r, double t);
void intersectCaps(Ray r, Intersect &xs);
public:
bool isClosed;
double minCap;
double maxCap;
Cylinder() : minCap(-INFINITY), maxCap(INFINITY), isClosed(false), Shape(Shape::CYLINDER) { stats.addCylinder(); };
BoundingBox getLocalBounds();
bool haveFiniteBounds() { return !(isinf(this->minCap) || isinf(this->maxCap)); };
void dumpMe(FILE *fp);
};
#endif //DORAYME_CYLINDER_H

69
source/include/group.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Group header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_GROUP_H
#define DORAYME_GROUP_H
#include <shape.h>
#include <stdio.h>
/* TODO: Add a way to force(?) material from group to be applied on childs */
class Group : public Shape
{
private:
uint32_t allocatedObjectCount;
Shape* *objectList;
uint32_t objectCount;
uint32_t allocatedUnboxableObjectCount;
Shape* *unboxableObjectList;
uint32_t unboxableObjectCount;
char name[32 + 1];
protected:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
BoundingBox bounds;
public:
bool isEmpty();
void addObject(Shape *s);
void removeObject(Shape *s);
Shape *operator[](const int p) { return this->getObject(p); };
Shape *getObject(const int p) { return this->objectList[p]; };
Shape *getUnboxable(const int p) { return this->unboxableObjectList[p]; };
void intersect(Ray &r, Intersect &xs);
BoundingBox getLocalBounds();
BoundingBox getBounds();
void updateBoundingBox();
void updateTransform();
bool includes(Shape *b);
uint32_t getObjectCount() { return this->objectCount; };
uint32_t getUnboxableCount() { return this->unboxableObjectCount; };
Group(const char *name = nullptr);
void lock();
void setBounds(BoundingBox &bb) { this->bounds | bb; };
const char *getName() { return this->name; };
void dumpMe(FILE * fp);
};
#endif /* DORAYME_GROUP_H */

View File

@@ -0,0 +1,31 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Intersect header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_INTERSECT_H
#define DORAYME_INTERSECT_H
#include <stdint.h>
#include <intersection.h>
class Intersect
{
private:
Intersection **list;
uint32_t num;
uint32_t allocated;
public:
Intersect();
~Intersect();
void reset();
void add(Intersection i);
int count() { return this->num; };
Intersection operator[](const int p) { return *this->list[p]; }
Intersection hit();
};
#endif /* DORAYME_INTERSECT_H */

View File

@@ -0,0 +1,63 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Intersection header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_INTERSECTION_H
#define DORAYME_INTERSECTION_H
#include <stdlib.h>
#include <ray.h>
#include <material.h>
#include <renderstat.h>
class Shape;
class Intersect;
struct Computation
{
Computation(Shape *object, double t, Tuple point, Tuple eyev, Tuple normalv, Tuple overHitP,
bool inside, Tuple reflectV = Vector(0, 0, 0), double n1 = 1.0, double n2 = 1.0,
Tuple underHitP = Point(0, 0, 0), Material *objMat = nullptr) :
object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside),
overHitPoint(overHitP), underHitPoint(underHitP), reflectVector(reflectV), n1(n1), n2(n2), material(objMat) { };
double schlick();
Shape *object;
double t;
Tuple hitPoint;
Tuple overHitPoint;
Tuple underHitPoint;
Tuple eyeVector;
Tuple normalVector;
Tuple reflectVector;
Material *material;
double n1;
double n2;
bool inside;
};
class Intersection
{
public:
double t;
Shape *object;
double u, v;
public:
Intersection(double t, Shape *object, double u = NAN, double v = NAN) : t(t), object(object), u(u), v(v) { stats.addIntersection(); };
bool nothing() { return (this->object == nullptr); };
Computation prepareComputation(Ray r, Intersect *xs = nullptr);
bool operator==(const Intersection &b) const { return ((this->t == b.t) && (this->object == b.object)); };
};
#endif /* DORAYME_INTERSECTION_H */

67
source/include/light.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Light header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_LIGHT_H
#define DORAYME_LIGHT_H
#include <tuple.h>
#include <colour.h>
#include <renderstat.h>
#include <sequence.h>
#include <stdio.h>
class World;
enum LightType
{
POINT_LIGHT = 0,
AREA_LIGHT,
};
class Light
{
public:
Colour intensity;
Tuple position;
LightType type;
/* For area light */
Tuple corner;
Tuple uVec;
Tuple vVec;
uint32_t samples;
uint32_t uSteps;
uint32_t vSteps;
bool jitter;
Sequence jitterBy;
public:
Light(LightType type = POINT_LIGHT, Tuple position=Point(0, 0, 0),
Colour intensity=Colour(1, 1, 1)) : type(type), position(position), intensity(intensity)
{ stats.addLight(); };
Light(LightType type, Tuple corner, Tuple fullUVec, uint32_t uSteps, Tuple fullVVec, uint32_t vSteps,
Colour intensity, bool jitter = false): type(type), corner(corner), uVec(fullUVec / uSteps), uSteps(uSteps),
vVec(fullVVec / vSteps), vSteps(vSteps), intensity(intensity), jitter(jitter)
{
this->samples = this->vSteps * this->uSteps;
this->position = this->corner + ((fullUVec + fullVVec) / 2);
stats.addLight();
};
double intensityAt(World &w, Tuple point);
bool operator==(const Light &b) const { return this->intensity == b.intensity &&
this->position == b.position &&
this->type == b.type; };
Tuple pointOnLight(uint32_t u, uint32_t v);
void dumpMe(FILE *fp);
};
#endif /* DORAYME_LIGHT_H */

120
source/include/list.h Normal file
View File

@@ -0,0 +1,120 @@
/*
* DoRayMe - a quick and dirty Raytracer
* List header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_LIST_H
#define DORAYME_LIST_H
#include <shape.h>
struct ChainList
{
Shape *shape;
ChainList *next;
};
class List
{
private:
ChainList *head;
ChainList *tail;
uint32_t count;
public:
List() : head(nullptr), tail(nullptr), count(0) { };
~List()
{
ChainList *p = this->head;
if (p == nullptr) { return; }
/* clear up the list */
do
{
ChainList *next = p->next;
free(p);
p = next;
}
while(p != nullptr);
}
Shape *last()
{
ChainList *p = this->tail;
if (p == nullptr) { return nullptr; }
return p->shape;
}
void remove(Shape *s)
{
ChainList *p = this->head;
if (p == nullptr) { return; }
if ((p->next == nullptr) && (p->shape == s))
{
/* First element */
this->tail = nullptr;
free(this->head);
this->head = nullptr;
this->count = 0;
return;
}
while(p->next != nullptr)
{
if (p->next->shape == s)
{
ChainList *found = p->next;
p->next = p->next->next;
free(found);
if (p->next == NULL) { this->tail = p; }
this->count --;
return;
}
p = p->next;
}
}
void append(Shape *s)
{
ChainList *theNew = (ChainList *)calloc(1, sizeof(ChainList));
theNew->shape = s;
ChainList *p = this->tail;
this->tail = theNew;
if (p != nullptr) { p->next = theNew; }
else { this->head = theNew; } /* If the tail is empty, it mean the list IS empty. */
this->count ++;
}
bool isEmpty()
{
return (this->count == 0);
}
bool doesInclude(Shape *s)
{
ChainList *p = this->head;
while(p != nullptr)
{
if (p->shape == s) { return true; }
p = p->next;
}
return false;
}
};
#endif //DORAYME_LIST_H

57
source/include/material.h Normal file
View File

@@ -0,0 +1,57 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Material header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_MATERIAL_H
#define DORAYME_MATERIAL_H
#include <tuple.h>
#include <colour.h>
#include <pattern.h>
#include <light.h>
#include <stdio.h>
class Shape;
class Material
{
public:
Colour colour;
double ambient;
double diffuse;
double specular;
double shininess;
double reflective;
double transparency;
double emissive;
double refractiveIndex;
Pattern *pattern;
public:
Material() : colour(Colour(1, 1, 1)), ambient(0.1), diffuse(0.9), specular(0.9), shininess(200),
reflective(0.0), transparency(0.0), emissive(0), refractiveIndex(1.0), pattern(nullptr) {};
Colour lighting(Light light, Tuple point, Tuple eyeVector, Tuple normalVector, Shape *hitObject,
double lightIntensity = 1.0);
bool operator==(const Material &b) const { return double_equal(this->ambient, b.ambient) &&
double_equal(this->diffuse, b.diffuse) &&
double_equal(this->specular, b.specular) &&
double_equal(this->shininess, b.shininess) &&
double_equal(this->reflective, b.reflective) &&
double_equal(this->transparency, b.transparency) &&
double_equal(this->emissive, b.emissive) &&
double_equal(this->refractiveIndex, b.refractiveIndex) &&
(this->colour == b.colour); };
bool operator!=(const Material &b) const { return !(*this == b); };
void dumpMe(FILE *fp);
};
#endif /* DORAYME_MATERIAL_H */

View File

@@ -10,7 +10,23 @@
#ifndef DORAYME_MATH_HELPER_H #ifndef DORAYME_MATH_HELPER_H
#define DORAYME_MATH_HELPER_H #define DORAYME_MATH_HELPER_H
#include <math.h>
void set_equal_precision(double v); void set_equal_precision(double v);
double getEpsilon();
bool double_equal(double a, double b); bool double_equal(double a, double b);
#endif //DORAYME_MATH_HELPER_H double deg_to_rad(double deg);
double min3(double a, double b, double c);
double max3(double a, double b, double c);
double frand();
double frandclip(double min, double max);
static double modulo(double a, double b)
{
return a - floor(a/b) * b;
}
#endif /* DORAYME_MATH_HELPER_H */

View File

@@ -9,7 +9,17 @@
#ifndef DORAYME_MATRIX_H #ifndef DORAYME_MATRIX_H
#define DORAYME_MATRIX_H #define DORAYME_MATRIX_H
#include <tuples.h> #include <tuple.h>
/* Some **** linux distro seems to define "minor" as a macro
* and wreak havoc.
* Let's make sure we are clean here
*/
#ifdef minor
#undef minor
#endif
#define FastGet4(_x, _y) (this->data[4 * (_x) + (_y)])
class Matrix class Matrix
{ {
@@ -19,7 +29,7 @@ protected:
int size; int size;
public: public:
Matrix(int size); Matrix(int size = 4);
Matrix(double values[], int size); Matrix(double values[], int size);
double get(int x, int y) const { return this->data[this->size * x + y]; }; double get(int x, int y) const { return this->data[this->size * x + y]; };
@@ -38,7 +48,12 @@ public:
bool isInvertible() { return this->determinant() != 0; } bool isInvertible() { return this->determinant() != 0; }
Matrix operator*(const Matrix &b) const; Matrix operator*(const Matrix &b) const;
Tuple operator*(const Tuple &b) const; Tuple operator*(const Tuple &b) const {
return Tuple(b.x * FastGet4(0, 0) + b.y * FastGet4(0, 1) + b.z * FastGet4(0, 2) + b.w * FastGet4(0, 3),
b.x * FastGet4(1, 0) + b.y * FastGet4(1, 1) + b.z * FastGet4(1, 2) + b.w * FastGet4(1, 3),
b.x * FastGet4(2, 0) + b.y * FastGet4(2, 1) + b.z * FastGet4(2, 2) + b.w * FastGet4(2, 3),
b.x * FastGet4(3, 0) + b.y * FastGet4(3, 1) + b.z * FastGet4(3, 2) + b.w * FastGet4(3, 3));
}
}; };
class Matrix4: public Matrix class Matrix4: public Matrix

80
source/include/objfile.h Normal file
View File

@@ -0,0 +1,80 @@
/*
* DoRayMe - a quick and dirty Raytracer
* OBJ File header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_OBJFILE_H
#define DORAYME_OBJFILE_H
#include <stdint.h>
#include <tuple.h>
#include <shape.h>
#include <group.h>
#include <renderstat.h>
class OBJFile : public Shape
{
private:
Group *baseGroup;
Group *currentGroup;
uint32_t allocatedVertexCount;
Point* *vertexList;
uint32_t vertexCount;
uint32_t allocatedVertexNormalCount;
Vector* *vertexNormalList;
uint32_t vertexNormalCount;
private:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
/* Some stats */
uint32_t ignoredLines;
protected:
void addGroup(Group *group);
void addVertex(Point *vertex);
void addVertexNormal(Vector *vertexNormal);
void parseLine(char *line, uint32_t currentLine);
int execLine(int argc, char *argv[], uint32_t currentLine);
BoundingBox bounds;
public:
OBJFile();
OBJFile(const char *filepath);
~OBJFile();
int parseOBJFile(const char *content);
/* OBJ file expect the first vertice to be 1 and not 0 */
Point vertices(uint32_t i) { return *this->vertexList[i - 1]; };
Vector verticesNormal(uint32_t i) { return *this->vertexNormalList[i - 1]; };
Group *groups(const char *groupName);
void intersect(Ray &r, Intersect &xs);
BoundingBox getLocalBounds();
BoundingBox getBounds();
Shape *getBaseGroup() { return this->baseGroup; };
bool includes(Shape *b);
void updateBoundingBox();
void updateTransform();
void lock();
void dumpMe(FILE * fp);
};
#define OBJ_DEFAULT_GROUP "_DefaultObjGroup_"
#endif /* DORAYME_OBJFILE_H */

38
source/include/pattern.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_PATTERN_H
#define DORAYME_PATTERN_H
#include <colour.h>
#include <tuple.h>
#include <matrix.h>
#include <stdio.h>
class Shape;
class Pattern
{
public:
Colour a;
Colour b;
Matrix transformMatrix;
Matrix inverseTransform;
public:
Pattern(Colour a, Colour b);
virtual Colour patternAt(Tuple point) = 0;
virtual void dumpMe(FILE *fp);
void setTransform(Matrix transform);
Colour patternAtObject(Shape *object, Tuple point);
};
#endif /* DORAYME_PATTERN_H */

26
source/include/plane.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Plane header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_PLANE_H
#define DORAYME_PLANE_H
#include <renderstat.h>
class Plane : public Shape
{
protected:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
Plane() : Shape(Shape::PLANE) { stats.addPlane(); };
BoundingBox getLocalBounds();
bool haveFiniteBounds() { return false; };
};
#endif //DORAYME_PLANE_H

26
source/include/ray.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Ray header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_RAY_H
#define DORAYME_RAY_H
#include <tuple.h>
#include <renderstat.h>
class Ray
{
public:
Tuple direction;
Tuple origin;
Ray(Tuple origin, Tuple direction) : origin(origin), direction(direction) { stats.addRay(); };
Tuple position(double t) { return this->origin + this->direction * t; };
};
#endif /* DORAYME_RAY_H */

107
source/include/renderstat.h Normal file
View File

@@ -0,0 +1,107 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Render statistics header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_RENDERSTAT_H
#define DORAYME_RENDERSTAT_H
#include <stdint.h>
class RenderStats
{
private:
uint64_t coneCount; /* Total number of cones */
uint64_t cylinderCount; /* Total number of cylinder */
uint64_t cubeCount; /* Total number of cubes */
uint64_t groupCount; /* Total number of groups */
uint64_t lightCount; /* Total number of light */
uint64_t planeCount; /* Total number of plane */
uint64_t sphereCount; /* Total number of sphere */
uint64_t triangleCount; /* Total number of triangle */
uint64_t smoothTriangleCount; /* Total number of smooth triangle */
uint64_t objfileCount; /* Total number of OBJ File */
uint64_t csgCount; /* Total number of CSG */
uint64_t pixelCount; /* Total number of rendered pixels */
uint64_t rayCount; /* Total number of rays object created */
uint64_t rayCasted; /* Total number of rays actually casted */
uint64_t lightRayEmitedCount; /* Total number of ray launched for light tests */
uint64_t reflectionRayCount; /* Total number of reflection ray launched */
uint64_t refractedRayCount; /* Total number of refracted ray launched */
uint64_t intersectCount; /* Total number of intersect object created */
uint64_t intersectionCount; /* Total number of intersection for all casted rays, including light and reflections */
uint64_t reallocCallCount; /* Total number of time realloc being called */
uint64_t mallocCallCount; /* Total number of time malloc/calloc being called */
uint64_t discardedIntersectCount; /* Number of time a bounding box check said "no need to test me" */
uint64_t maxDepthAttained; /* Report the lowest depth attained during ray recursion */
uint64_t maxIntersectOnARay; /* Biggest intersect done */
public:
RenderStats() : coneCount(0), cylinderCount(0), cubeCount(0), groupCount(0), lightCount(0), planeCount(0), sphereCount(0), triangleCount(0),
pixelCount(0), rayCount(0), lightRayEmitedCount(0), reflectionRayCount(0), refractedRayCount(0),
intersectCount(0), intersectionCount(0), reallocCallCount(0), mallocCallCount(0), smoothTriangleCount(0),
discardedIntersectCount(0), maxDepthAttained(UINT64_MAX), maxIntersectOnARay(0), objfileCount(0),
csgCount(0), rayCasted(0) {};
#ifdef RENDER_STATS
void addCone();
void addCylinder();
void addCube();
void addGroup();
void addLight();
void addPlane();
void addSphere();
void addCsg();
void addOBJFile();
void addTriangle();
void addSmoothTriangle();
void printStats();
void addPixel();
void addRay();
void addCastedRay();
void addLightRay();
void addReflectRay();
void addRefractRay();
void addIntersection();
void addDiscardedIntersect();
void setMaxDepth(uint32_t depth);
void addIntersect();
void addMalloc();
void addRealloc();
void setMaxIntersect(uint32_t count);
#else
static void addCone() {};
static void addCylinder() {};
static void addCube() {};
static void addGroup() {};
static void addLight() {};
static void addPlane() {};
static void addSphere() {};
static void addTriangle() {};
static void addSmoothTriangle() {};
static void printStats() {};
static void addPixel() {};
static void addRay() {};
static void addCastedRay() {};
static void addLightRay() {};
static void addReflectRay() {};
static void addRefractRay() {};
static void addIntersection() {};
static void addDiscardedIntersect() {};
static void setMaxDepth(uint32_t depth) {};
static void addIntersect() {};
static void addMalloc() {};
static void addRealloc() {};
static void setMaxIntersect(uint32_t count) {};
static void addOBJFile() {};
static void addCsg() {};
#endif
};
extern RenderStats stats;
#endif /* DORAYME_RENDERSTAT_H */

27
source/include/sequence.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Sequence header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_SEQUENCE_H
#define DORAYME_SEQUENCE_H
#include <stdint.h>
class Sequence
{
private:
double *list;
uint32_t listPos;
uint32_t listSize;
public:
Sequence();
Sequence(double *list, uint32_t listSize);
double next();
};
#endif /* DORAYME_SEQUENCE_H */

111
source/include/shape.h Normal file
View File

@@ -0,0 +1,111 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Object header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_SHAPE_H
#define DORAYME_SHAPE_H
class Shape;
#include <stdio.h>
#include <ray.h>
#include <tuple.h>
#include <matrix.h>
#include <intersect.h>
#include <material.h>
#include <boundingbox.h>
/* Base class for all object that can be presented in the world */
class Shape
{
public:
enum ShapeType
{
NONE,
SPHERE,
PLANE,
CUBE,
CYLINDER,
CONE,
GROUP,
TRIANGLE,
OBJFILE,
SMOOTHTRIANGLE,
CSG,
};
protected:
ShapeType type;
Matrix localTransformMatrix;
bool locked;
uint64_t objectId;
protected:
virtual void localIntersect(Ray r, Intersect &xs) = 0;
virtual Tuple localNormalAt(Tuple point, Intersection *hit) = 0;
static uint64_t newObjectId();
public:
Matrix transformMatrix;
Matrix inverseTransform;
Matrix transposedInverseTransform;
Material material;
bool dropShadow;
Shape *parent;
bool materialSet;
public:
Shape(ShapeType = Shape::NONE);
ShapeType getType() { return this->type; };
virtual void intersect(Ray &r, Intersect &xs) { this->localIntersect(this->invTransform(r), xs); };
Tuple normalAt(Tuple point, Intersection *hit = nullptr);
uint64_t getObjectId() { return this->objectId; };
void setObjectId(uint64_t oid) { this->objectId = oid; };
/* Bounding box points are always world value */
virtual BoundingBox getLocalBounds();
virtual BoundingBox getBounds();
virtual bool haveFiniteBounds() { return true; };
virtual void updateTransform();
virtual bool includes(Shape *b) { return this == b; };
virtual void dumpMe(FILE *fp);
/* When an object is locked, the matrix transformation and bounding box can't be updated. This is
* usefull to move object between group without changing the real hierarchy between them.
* It will also not change the parent member.
* This is supposed to be used only before a render is going to start so we can optimise the
* way the object are stored to prefer lots of un-needed intersections.
*/
virtual void lock() { this->locked = true; };
Tuple worldToObject(Tuple point) { return this->inverseTransform * point; };
Tuple objectToWorld(Tuple point) { return this->transformMatrix * point; };
Tuple normalToWorld(Tuple normalVector);
void setParent(Shape *parent) { if (!this->locked) { this->parent = parent; };};
void setTransform(Matrix transform);
void setMaterial(Material material) { this->material = material; this->materialSet = true; };
Material *getMaterial();
Ray transform(Ray &r) { return Ray(this->transformMatrix * r.origin, this->transformMatrix * r.direction); };
Ray invTransform(Ray &r) { return Ray(this->inverseTransform * r.origin, this->inverseTransform * r.direction); };
bool operator==(const Shape &b) const { return this->material == b.material &&
this->type == b.type &&
this->transformMatrix == b.transformMatrix; };
};
#endif /* DORAYME_SHAPE_H */

View File

@@ -0,0 +1,30 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Smooth Triangle header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_SMOOTHTRIANGLE_H
#define DORAYME_SMOOTHTRIANGLE_H
#include <triangle.h>
class SmoothTriangle : public Triangle
{
public:
Vector n1;
Vector n2;
Vector n3;
protected:
Tuple localNormalAt(Tuple point, Intersection *hit);
public:
SmoothTriangle(Point p1, Point p2, Point p3, Vector n1, Vector n2, Vector n3);
void dumpMe(FILE *fp);
};
#endif /* DORAYME_SMOOTHTRIANGLE_H */

39
source/include/sphere.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Sphere header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_SPHERE_H
#define DORAYME_SPHERE_H
#include <shape.h>
#include <ray.h>
#include <intersect.h>
#include <renderstat.h>
#include <stdio.h>
class Sphere : public Shape
{
protected:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
Sphere() : Shape(Shape::SPHERE) { stats.addSphere(); };
/* All sphere are at (0, 0, 0) and radius 1 in the object space */
void dumpMe(FILE *fp);
};
/* Mostly for test purposes */
class GlassSphere : public Sphere
{
public:
GlassSphere() : Sphere() { this->material.transparency = 1.0; this->material.refractiveIndex = 1.5; };
};
#endif /* DORAYME_SPHERE_H */

View File

@@ -0,0 +1,28 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Test shape header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_TESTSHAPE_H
#define DORAYME_TESTSHAPE_H
#include <shape.h>
#include <ray.h>
#include <tuple.h>
class TestShape : public Shape
{
private:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
Ray localRay;
TestShape();
};
#endif //DORAYME_TESTSHAPE_H

View File

@@ -15,10 +15,12 @@ Matrix translation(double x, double y, double z);
Matrix scaling(double x, double y, double z); Matrix scaling(double x, double y, double z);
Matrix rotation_x(double angle); Matrix rotationX(double angle);
Matrix rotation_y(double angle); Matrix rotationY(double angle);
Matrix rotation_z(double angle); Matrix rotationZ(double angle);
Matrix shearing(double Xy, double Xx, double Yx, double Yz, double Zx, double Zy); Matrix shearing(double Xy, double Xx, double Yx, double Yz, double Zx, double Zy);
Matrix viewTransform(Tuple from, Tuple to, Tuple up);
#endif /* DORAYME_TRANSFORMATION_H */ #endif /* DORAYME_TRANSFORMATION_H */

34
source/include/triangle.h Normal file
View File

@@ -0,0 +1,34 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Triangle header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_TRIANGLE_H
#define DORAYME_TRIANGLE_H
#include <shape.h>
#include <stdio.h>
class Triangle : public Shape
{
protected:
void localIntersect(Ray r, Intersect &xs);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
Tuple p1, p2, p3;
Tuple e1, e2;
Tuple normal;
public:
Triangle(Point p1, Point p2, Point p3);
BoundingBox getLocalBounds();
void dumpMe(FILE *fp);
};
#endif /* DORAYME_TRIANGLE_H */

View File

@@ -6,8 +6,8 @@
* Copyright (c) 2020 986-Studio. * Copyright (c) 2020 986-Studio.
* *
*/ */
#ifndef DORAYME_TUPLES_H #ifndef DORAYME_TUPLE_H
#define DORAYME_TUPLES_H #define DORAYME_TUPLE_H
#include <math_helper.h> #include <math_helper.h>
@@ -17,6 +17,7 @@ public:
double x, y, z, w; double x, y, z, w;
public: public:
Tuple() : x(0), y(0), z(0), w(0.0) {};
Tuple(double x, double y, double z) : x(x), y(y), z(z), w(0.0) {}; Tuple(double x, double y, double z) : x(x), y(y), z(z), w(0.0) {};
Tuple(double x, double y, double z, double w) : x(x), y(y), z(z), w(w) {}; Tuple(double x, double y, double z, double w) : x(x), y(y), z(z), w(w) {};
bool isPoint() { return (this->w == 1.0); }; bool isPoint() { return (this->w == 1.0); };
@@ -26,6 +27,7 @@ public:
double_equal(this->y, b.y) && double_equal(this->y, b.y) &&
double_equal(this->z, b.z) && double_equal(this->z, b.z) &&
double_equal(this->w, b.w); }; double_equal(this->w, b.w); };
bool operator!=(const Tuple &b) const { return !(*this == b); };
Tuple operator+(const Tuple &b) const { return Tuple(this->x + b.x, this->y + b.y, Tuple operator+(const Tuple &b) const { return Tuple(this->x + b.x, this->y + b.y,
this->z + b.z, this->w + b.w); }; this->z + b.z, this->w + b.w); };
@@ -37,23 +39,38 @@ public:
this->z * b, this->w * b); }; this->z * b, this->w * b); };
Tuple operator/(const double &b) const { return Tuple(this->x / b, this->y / b, Tuple operator/(const double &b) const { return Tuple(this->x / b, this->y / b,
this->z / b, this->w / b); }; this->z / b, this->w / b); };
bool isRepresentable();
void set(double nX, double nY, double nZ) { this->x = nX; this->y = nY; this->z = nZ; };
double magnitude(); double magnitude();
Tuple normalise(); Tuple normalise();
double dot(const Tuple &b);
double dot(const Tuple &b) {
return this->x * b.x + this->y * b.y + this->z * b.z + this->w * b.w;
}
Tuple cross(const Tuple &b) const {
return Tuple(this->y * b.z - this->z * b.y,
this->z * b.x - this->x * b.z,
this->x * b.y - this->y * b.x,
0);
}
Tuple reflect(const Tuple &normal);
}; };
class Point: public Tuple class Point: public Tuple
{ {
public: public:
Point() : Tuple(0, 0, 0, 1.0) {};
Point(double x, double y, double z) : Tuple(x, y, z, 1.0) {}; Point(double x, double y, double z) : Tuple(x, y, z, 1.0) {};
}; };
class Vector: public Tuple class Vector: public Tuple
{ {
public: public:
Vector() : Tuple(0, 0, 0, 0.0) {};
Vector(double x, double y, double z) : Tuple(x, y, z, 0.0) {}; Vector(double x, double y, double z) : Tuple(x, y, z, 0.0) {};
Vector cross(const Vector &b) const;
}; };
#endif /* DORAYME_TUPLES_H */ #endif /* DORAYME_TUPLE_H */

View File

@@ -0,0 +1,28 @@
/*
* DoRayMe - a quick and dirty Raytracer
* UV Pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_UV_PATTERN_H
#define DORAYME_UV_PATTERN_H
#include <colour.h>
class UVPattern
{
public:
Colour a;
Colour b;
double width;
double height;
UVPattern(double width, double height, Colour a, Colour b) : a(a), b(b),
width(width), height(height) {};
virtual Colour uvPatternAt(double u, double v) = 0;
};
#endif /* DORAYME_UV_PATTERN_H */

73
source/include/world.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* DoRayMe - a quick and dirty Raytracer
* World header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_WORLD_H
#define DORAYME_WORLD_H
#include <stdint.h>
#include <light.h>
#include <shape.h>
#include <intersect.h>
#include <ray.h>
#include <stdio.h>
#include <group.h>
#include <worldoptimiser.h>
#ifdef ENABLE_LUA_SUPPORT
extern "C" {
#include <lua.h>
}
#endif
class World
{
public:
uint32_t lightCount;
private:
uint32_t allocatedLightCount;
Light* *lightList;
Group worldGroup;
#ifdef ENABLE_LUA_SUPPORT
lua_State *L;
#endif
public:
World();
~World();
void addObject(Shape *s);
void addLight(Light *l);
/* Some debug things */
bool lightIsIn(Light &l);
bool objectIsIn(Shape &s);
Shape *getObject(int i) { return this->worldGroup[i]; };
Light *getLight(int i) { return this->lightList[i]; };
uint32_t getObjectCount() { return this->worldGroup.getObjectCount(); };
uint32_t getLightCount() { return this->lightCount; };
Tuple shadeHit(Computation comps, uint32_t depthCount = 4);
Tuple colourAt(Ray r, uint32_t depthCount = 4);
bool isShadowed(Tuple point, Tuple lightPosition);
Colour reflectColour(Computation comps, uint32_t depthCount = 4);
Colour refractedColour(Computation comps, uint32_t depthCount = 4);
void intersect(Ray &r, Intersect &xs);
void finalise(WorldOptimiser &opt);
void dumpMe(FILE *fp);
};
#endif /* DORAYME_WORLD_H */

View File

@@ -0,0 +1,53 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Worldbuilder header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_WORLDBUILDER_H
#define DORAYME_WORLDBUILDER_H
#include <world.h>
#include <camera.h>
/* Let's keep a single header for now, will see later */
class DefaultWorld : public World
{
public:
DefaultWorld();
};
/* Not implemented yet */
class Hw3File : public World
{
private:
Matrix transformStack[50];
uint32_t transStackCount;
public:
double currentAmbient;
double currentShininess;
double currentSpecular;
double currentDiffuse;
double currentEmission;
double currentReflective;
double currentTransparency;
double currentRefIndex;
Colour currentColour;
Matrix cam;
double camFoV;
public:
Matrix getTransformMatrix();
void popTransformMatrix();
void pushTransformMatrix();
void applyTransformMatrix(Matrix t);
Hw3File(const char *filename);
};
#endif /* DORAYME_WORLDBUILDER_H */

View File

@@ -0,0 +1,51 @@
/*
* DoRayMe - a quick and dirty Raytracer
* World optimiser header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_WORLDOPTIMISER_H
#define DORAYME_WORLDOPTIMISER_H
#include <group.h>
/* World Optimiser subclasses will created move objects around to try to optimise the raytrace of the world, to
* have as least as possible object to intersect per ray.
* This class is abstract to we can implement different type and change at runtime or build time
*/
class WorldOptimiser
{
protected:
Group *root;
void moveInfiniteObjects(Shape *s = nullptr);
void moveAllObjects(Shape *s = nullptr);
public:
void setRoot(Group *root) { this->root = root; };
virtual void run() = 0;
};
class NoWorldOptimisation : public WorldOptimiser
{
public:
void run() {};
};
class BVHOptimisation : public WorldOptimiser
{
private:
void makeTree(Group *leaf, int depth = 0);
public:
void run();
};
class OctreeOptimisation : public WorldOptimiser
{
private:
void makeTree(Group *leaf, int depth = 0);
public:
void run();
};
#endif /* DORAYME_WORLDOPTIMISER_H */

105
source/intersect.cpp Normal file
View File

@@ -0,0 +1,105 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Intersect implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <stdlib.h>
#include <math_helper.h>
#include <intersect.h>
#include <float.h>
#include <renderstat.h>
#define MIN_ALLOC (2)
/* TODO: Memory allocation, even if using standard calloc/realloc have a huge impact on performances. need to find a way
* to reuse the intersect object without reallocating from scratch all the time. We use a lot of Intersect objects as
* there is at least 2 per ray (one for Ray intersect object, one object per light)
*/
Intersect::Intersect()
{
this->allocated = MIN_ALLOC;
this->list = (Intersection **)calloc(sizeof(Intersection *), MIN_ALLOC);
if (this->list != nullptr)
{
stats.addMalloc();
stats.addIntersect();
this->num = 0;
}
else
{
printf("ABORT: Allocation error [%s]!\n", __FUNCTION__);
exit(-1);
}
}
Intersect::~Intersect()
{
int i;
for(i = 0; i < this->num; i++)
{
if (this->list[i] != nullptr)
{
delete this->list[i];
this->list[i] = nullptr;
}
}
/* Free stuff */
if (this->list != nullptr)
{
free(this->list);
this->list = nullptr;
}
}
void Intersect::reset()
{
this->num = 0;
}
void Intersect::add(Intersection i)
{
Intersection *x;
int j, k;
if ((this->num + 1) > this->allocated)
{
this->allocated *= 2;
stats.addRealloc();
this->list = (Intersection **)realloc(this->list, sizeof(Intersection *) * this->allocated);
}
this->list[this->num++] = new Intersection(i.t, i.object, i.u, i.v);
stats.setMaxIntersect(this->num);
/* Now sort.. */
for(j = 1; j < (this->num); j++)
{
x = this->list[j];
k = j;
while( (k > 0) && (this->list[k - 1]->t) > x->t )
{
this->list[k] = this->list[k - 1];
k--;
}
this->list[k] = x;
}
}
Intersection Intersect::hit()
{
int i;
for(i = 0; i < this->num; i++)
{
if (this->list[i]->t >= 0)
return *this->list[i];
}
return Intersection(0, nullptr);
}

123
source/intersection.cpp Normal file
View File

@@ -0,0 +1,123 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Intersection implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <intersection.h>
#include <shape.h>
#include <list.h>
double Computation::schlick()
{
/* Find the cos of the angle betzeen the eye and normal vector */
double cos = this->eyeVector.dot(this->normalVector);
double r0;
/* Total internal reflection can only occur when n1 > n2 */
if (this->n1 > this->n2)
{
double n, sin2_t;
n = this->n1 / this->n2;
sin2_t = (n * n) * (1.0 - (cos * cos));
if (sin2_t > 1.0)
{
return 1.0;
}
/* Compute the cos of theta */
cos = sqrt(1.0 - sin2_t);
}
r0 = ((this->n1 - this->n2) / (this->n1 + this->n2));
r0 = r0 * r0;
return r0 + (1 - r0) * ((1 - cos)*(1 - cos)*(1 - cos)*(1 - cos)*(1 - cos));
};
Computation Intersection::prepareComputation(Ray r, Intersect *xs)
{
double n1 = 1.0;
double n2 = 1.0;
Tuple hitP = r.position(this->t);
Tuple normalV;
if (xs != nullptr)
{
Intersection hit = xs->hit();
normalV = this->object->normalAt(hitP, &hit);
}
else
{
normalV = this->object->normalAt(hitP, nullptr);
}
Tuple eyeV = -r.direction;
bool inside = false;
if (normalV.dot(eyeV) < 0)
{
inside = true;
normalV = -normalV;
}
Tuple overHitP = hitP + normalV * getEpsilon();
Tuple underHitP = hitP - normalV * getEpsilon();
Tuple reflectV = r.direction.reflect(normalV);
/* If the hit object is not transparent, there is no need to do that. I think .*/
if ((xs != nullptr) && (xs->hit().object->getMaterial()->transparency > 0))
{
List containers;
int j;
for (j = 0 ; j < xs->count() ; j++)
{
Intersection i = ( *xs )[j];
if (*this == i)
{
if (!containers.isEmpty())
{
n1 = containers.last()->getMaterial()->refractiveIndex;
}
}
if (containers.doesInclude(i.object))
{
containers.remove(i.object);
}
else
{
containers.append(i.object);
}
if (*this == i)
{
if (!containers.isEmpty())
{
n2 = containers.last()->getMaterial()->refractiveIndex;
}
/* End the loop */
break;
}
}
}
Material *m = this->object->getMaterial();
return Computation(this->object,
this->t,
hitP,
eyeV,
normalV,
overHitP,
inside,
reflectV,
n1,
n2,
underHitP,
m);
}

View File

@@ -8,10 +8,45 @@
* *
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <math.h>
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
static int l_sin (lua_State *L) {
double d = luaL_checknumber(L, 1); /* get argument */
lua_pushnumber(L, sin(d)); /* push result */
return 1; /* number of results */
}
#if 0
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
printf("Hello !\n"); char buff[256];
int error;
lua_State *L = luaL_newstate(); /* opens Lua */
luaL_openlibs(L); /* opens the basic library */
lua_pushcfunction(L, l_sin);
lua_setglobal(L, "mysin");
printf("[0]>");
while (fgets(buff, sizeof(buff), stdin) != NULL)
{
error = luaL_loadstring(L, buff) || lua_pcall(L, 0, LUA_MULTRET, 0);
if (error)
{
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_pop(L, 1); /* pop error message from the stack */
}
printf("[%d]>", lua_gettop(L));
}
lua_close(L);
return 0; return 0;
} }
#endif

View File

@@ -7,6 +7,7 @@
* *
*/ */
#include <stdlib.h>
#include <math.h> #include <math.h>
#include <float.h> #include <float.h>
#include <math_helper.h> #include <math_helper.h>
@@ -18,7 +19,58 @@ void set_equal_precision(double v)
current_precision = v; current_precision = v;
} }
double getEpsilon()
{
return current_precision;
}
bool double_equal(double a, double b) bool double_equal(double a, double b)
{ {
if (isinf(a) && isinf(b))
return true;
return fabs(a - b) < current_precision; return fabs(a - b) < current_precision;
} }
double deg_to_rad(double deg)
{
return deg * M_PI / 180.;
}
double min3(double a, double b, double c)
{
if (a <= b)
{
if (c < a) return c;
return a;
}
if (b <= a)
{
if (c < b) return c;
}
return b;
}
double max3(double a, double b, double c)
{
if (a >= b)
{
if (c > a) return c;
return a;
}
if (b >= a)
{
if (c > b) return c;
}
return b;
}
double frand()
{
return rand() / ((double) RAND_MAX);
}
double frandclip(double min, double max)
{
return (frand() * (max - min)) + min;
}

View File

@@ -9,7 +9,7 @@
#include <stdio.h> #include <stdio.h>
#include <matrix.h> #include <matrix.h>
#include <tuples.h> #include <tuple.h>
#include <math_helper.h> #include <math_helper.h>
Matrix::Matrix(int width) Matrix::Matrix(int width)
@@ -101,14 +101,18 @@ Matrix Matrix::operator*(const Matrix &b) const
return ret; return ret;
} }
//#define FastGet4(_x, _y) (this->data[4 * (_x) + (_y)])
/* TODO: Check if we can optimise this function. It is called a lot */
/*
Tuple Matrix::operator*(const Tuple &b) const Tuple Matrix::operator*(const Tuple &b) const
{ {
return Tuple(b.x * this->get(0, 0) + b.y * this->get(0, 1) + b.z * this->get(0, 2) + b.w * this->get(0, 3), return Tuple(b.x * FastGet4(0, 0) + b.y * FastGet4(0, 1) + b.z * FastGet4(0, 2) + b.w * FastGet4(0, 3),
b.x * this->get(1, 0) + b.y * this->get(1, 1) + b.z * this->get(1, 2) + b.w * this->get(1, 3), b.x * FastGet4(1, 0) + b.y * FastGet4(1, 1) + b.z * FastGet4(1, 2) + b.w * FastGet4(1, 3),
b.x * this->get(2, 0) + b.y * this->get(2, 1) + b.z * this->get(2, 2) + b.w * this->get(2, 3), b.x * FastGet4(2, 0) + b.y * FastGet4(2, 1) + b.z * FastGet4(2, 2) + b.w * FastGet4(2, 3),
b.x * this->get(3, 0) + b.y * this->get(3, 1) + b.z * this->get(3, 2) + b.w * this->get(3, 3)); b.x * FastGet4(3, 0) + b.y * FastGet4(3, 1) + b.z * FastGet4(3, 2) + b.w * FastGet4(3, 3));
} }
*/
Matrix Matrix::identity() Matrix Matrix::identity()
{ {
int i; int i;
@@ -123,6 +127,7 @@ Matrix Matrix::transpose()
{ {
int x, y; int x, y;
Matrix ret = Matrix(this->size); Matrix ret = Matrix(this->size);
for (y = 0 ; y < this->size ; y++) for (y = 0 ; y < this->size ; y++)
{ {
for (x = 0 ; x < this->size ; x++) for (x = 0 ; x < this->size ; x++)
@@ -138,6 +143,7 @@ Matrix Matrix::submatrix(int row, int column)
int i, j; int i, j;
int x = 0, y = 0; int x = 0, y = 0;
Matrix ret = Matrix(this->size - 1); Matrix ret = Matrix(this->size - 1);
for (i = 0 ; i < this->size ; i++) for (i = 0 ; i < this->size ; i++)
{ {
if (i == row) if (i == row)

38
source/pattern.cpp Normal file
View File

@@ -0,0 +1,38 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Pattern implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <pattern.h>
#include <shape.h>
#include <stdio.h>
Pattern::Pattern(Colour a, Colour b): a(a), b(b)
{
this->transformMatrix = Matrix4().identity();
this->inverseTransform = this->transformMatrix.inverse();
};
Colour Pattern::patternAtObject(Shape *object, Tuple worldPoint)
{
Tuple objectPoint = object->worldToObject(worldPoint);
Tuple patternPoint = this->inverseTransform * objectPoint;
return this->patternAt(patternPoint);
}
void Pattern::setTransform(Matrix transform)
{
this->transformMatrix = transform;
this->inverseTransform = transform.inverse();
}
void Pattern::dumpMe(FILE *fp)
{
fprintf(fp, "\"Colour A\": {\"red\": %f, \"green\": %f, \"blue\": %f},\n", this->a.x, this->a.y, this->a.z);
fprintf(fp, "\"Colour B\": {\"red\": %f, \"green\": %f, \"blue\": %f},\n", this->b.x, this->b.y, this->b.z);
}

View File

@@ -0,0 +1,33 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Checkers Pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_CHECKERSPATTERN_H
#define DORAYME_CHECKERSPATTERN_H
#include <stdio.h>
class CheckersPattern : public Pattern
{
public:
CheckersPattern(Colour a, Colour b) : Pattern(a, b) { };
Colour patternAt(Tuple point)
{
double value = floor(point.x) + floor(point.y) + floor(point.z);
return (modulo(value, 2) == 0)?this->a:this->b;
}
void dumpMe(FILE *fp) {
fprintf(fp, "\"Type\": \"Checkers\",\n");
Pattern::dumpMe(fp);
}
};
#endif /* DORAYME_CHECKERSPATTERN_H */

View File

@@ -0,0 +1,37 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Gradient Pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_GRADIENTPATTERN_H
#define DORAYME_GRADIENTPATTERN_H
#include <pattern.h>
#include <stdio.h>
class GradientPattern : public Pattern
{
public:
GradientPattern(Colour a, Colour b) : Pattern(a, b) { };
Colour patternAt(Tuple point)
{
Tuple distance = this->b - this->a;
double fraction = point.x - floor(point.x);
Tuple ret = this->a + distance * fraction;
return Colour(ret.x, ret.y, ret.z);
}
void dumpMe(FILE *fp) {
fprintf(fp, "\"Type\": \"Gradient\",\n");
Pattern::dumpMe(fp);
}
};
#endif /* DORAYME_GRADIENTPATTERN_H */

107
source/pattern/luapattern.h Normal file
View File

@@ -0,0 +1,107 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Lua based Pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_LUAPATTERN_H
#define DORAYME_LUAPATTERN_H
#include <pattern.h>
#include <stdio.h>
#include <string.h>
#ifndef ENABLE_LUA_SUPPORT
#error Cannot use the Lua Pattern generator with no Lua support disabled!
#endif
extern "C" {
#include <lua.h>
}
class LuaPattern : public Pattern
{
private:
lua_State *L;
char funcName[50];
public:
LuaPattern(Colour a, Colour b) : Pattern(a, b), L(nullptr) { };
void setLua(lua_State *L) {
this->L = L;
};
void setLuaFunctionName(const char *name) {
strncpy(this->funcName, name, 50);
}
Colour patternAt(Tuple point)
{
int isnum;
double r, g, b;
lua_getglobal(this->L, this->funcName);
lua_pushnumber(this->L, point.x);
lua_pushnumber(this->L, point.y);
lua_pushnumber(this->L, point.z);
lua_createtable(L, 3, 0);
lua_pushnumber(L, this->a.x);
lua_setfield(L, -2, "r");
lua_pushnumber(L, this->a.y);
lua_setfield(L, -2, "g");
lua_pushnumber(L, this->a.z);
lua_setfield(L, -2, "b");
lua_createtable(L, 3, 0);
lua_pushnumber(L, this->b.x);
lua_setfield(L, -2, "r");
lua_pushnumber(L, this->b.y);
lua_setfield(L, -2, "g");
lua_pushnumber(L, this->b.z);
lua_setfield(L, -2, "b");
if (lua_pcall(this->L, 5, 3, 0) != LUA_OK)
{
printf("Error running the Lua function '%s': %s\n", this->funcName,
lua_tostring(this->L, -1));
return Colour(0, 0, 0);
}
r = lua_tonumberx(this->L, -3, &isnum);
if (!isnum)
{
printf("Error: function '%s' must return numbers\n", this->funcName);
lua_pop(this->L, 1);
return Colour(0, 0, 0);
}
g = lua_tonumberx(this->L, -2, &isnum);
if (!isnum)
{
printf("Error: function '%s' must return numbers\n", this->funcName);
lua_pop(this->L, 1);
return Colour(0, 0, 0);
}
b = lua_tonumberx(this->L, -1, &isnum);
if (!isnum)
{
printf("Error: function '%s' must return numbers\n", this->funcName);
lua_pop(this->L, 1);
return Colour(0, 0, 0);
}
lua_pop(this->L, 1);
return Colour(r, g, b);
}
void dumpMe(FILE *fp) {
fprintf(fp, "\"Type\": \"Lua\",\n");
Pattern::dumpMe(fp);
}
};
#endif /* DORAYME_LUAPATTERN_H */

View File

@@ -0,0 +1,35 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Ring Pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_RINGSUPPORT_H
#define DORAYME_RINGSUPPORT_H
#include <pattern.h>
class RingPattern : public Pattern
{
public:
RingPattern(Colour a, Colour b) : Pattern(a, b) { };
Colour patternAt(Tuple point)
{
double squared = (point.x * point.x) + (point.z * point.z);
double value = floor(sqrt(squared));
return (modulo(value, 2) == 0)?this->a:this->b;
}
void dumpMe(FILE *fp) {
fprintf(fp, "\"Type\": \"Ring\"\n");
Pattern::dumpMe(fp);
}
};
#endif /* DORAYME_RINGSUPPORT_H */

View File

@@ -0,0 +1,37 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Strip Pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_STRIPPATTERN_H
#define DORAYME_STRIPPATTERN_H
#include <pattern.h>
#include <stdio.h>
class StripPattern : public Pattern
{
public:
StripPattern(Colour a, Colour b) : Pattern(a, b) { };
Colour patternAt(Tuple point)
{
if (modulo(floor(point.x), 2) == 0)
{
return this->a;
}
return this->b;
}
void dumpMe(FILE *fp) {
fprintf(fp, "\"Type\": \"Strip\",\n");
Pattern::dumpMe(fp);
}
};
#endif /* DORAYME_STRIPPATTERN_H */

View File

@@ -0,0 +1,32 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Strip Pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_TESTPATTERN_H
#define DORAYME_TESTPATTERN_H
#include <pattern.h>
#include <stdio.h>
class TestPattern : public Pattern
{
public:
TestPattern() : Pattern(Colour(0, 0, 0), Colour(1, 1, 1)) { };
Colour patternAt(Tuple point)
{
return Colour(point.x, point.y, point.z);
}
void dumpMe(FILE *fp) {
fprintf(fp, "\"Type\": \"Test\",\n");
Pattern::dumpMe(fp);
}
};
#endif /* DORAYME_TESTPATTERN_H */

198
source/pattern/texturemap.h Normal file
View File

@@ -0,0 +1,198 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Texture Map header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_TEXTUREMAP_H
#define DORAYME_TEXTUREMAP_H
#include <math.h>
#include <tuple.h>
#include <uv_pattern.h>
#include <colour.h>
enum TextureMapType
{
SPHERICAL_MAP,
PLANAR_MAP,
CYLINDRICAL_MAP,
CUBIC_MAP
};
class TextureMap : public Pattern
{
private:
TextureMapType type;
UVPattern *pattern;
UVPattern *frontPat, *leftPat, *rightPat, *backPat, *upPat, *downPat;
public:
TextureMap(TextureMapType type, UVPattern *pattern) : Pattern(Colour(0, 0, 0), Colour(0, 0, 0)),
type(type), pattern(pattern) { };
static void sphericalMap(Tuple point, double &u, double &v) {
/* First compute the azimuthal angle
* -π < theta <= π
* angle increases clockwise as viewed from above,
* which is opposite of what we want, but we'll fix it later.
*/
double theta = atan2(point.x, point.z);
/* vec is the vector pointing from the sphere's origin (the world origin)
* to the point, which will also happen to be exactly equal to the sphere's
* radius.
*/
Tuple vec = Vector(point.x, point.y, point.z);
double radius = vec.magnitude();
/* Let's compute the polar angle
* 0 <= phi <= π
*/
double phi = acos(point.y / radius);
/* -0.5 < raw_u <= 0.5 */
double raw_u = theta / (2 * M_PI);
/* 0 <= u < 1
* here's also where we fix the direction of u. Subtract it from 1,
* so that it increases counterclockwise as viewed from above.
*/
u = 1 - (raw_u + 0.5);
/* We want v to be 0 at the south pole of the sphere,
* and 1 at the north pole, so we have to "flip it over"
* by subtracting it from 1.
*/
v = 1 - phi / M_PI;
}
static void planarMap(Tuple point, double &u, double &v) {
u = modulo(point.x, 1.0);
v = modulo(point.z, 1.0);
}
static void cylindricalMap(Tuple point, double &u, double &v) {
/* Let's get the azimuthal angle, same as with the spherical mapping */
double theta = atan2(point.x , point.z);
double raw_u = theta / (2 * M_PI);
u = 1 - (raw_u + 0.5);
v = modulo(point.y, 1.0);
}
enum CubeFaces {
CUBE_LEFT,
CUBE_RIGHT,
CUBE_FRONT,
CUBE_BACK,
CUBE_UP,
CUBE_DOWN,
};
static CubeFaces faceFromPoint(Tuple point) {
double abs_x = fabs(point.x);
double abs_y = fabs(point.y);
double abs_z = fabs(point.z);
double coord = max3(abs_x, abs_y, abs_z);
if (coord == point.x) { return CUBE_RIGHT; }
if (coord == -point.x) { return CUBE_LEFT; }
if (coord == point.y) { return CUBE_UP; }
if (coord == -point.y) { return CUBE_DOWN; }
if (coord == point.z) { return CUBE_FRONT; }
return CUBE_BACK;
}
static void cubeUBFront(Tuple point, double &u, double &v) {
u = modulo(point.x + 1, 2.0) / 2.0;
v = modulo(point.y + 1, 2.0) / 2.0;
}
static void cubeUBBack(Tuple point, double &u, double &v) {
u = modulo(1 - point.x, 2.0) / 2.0;
v = modulo(point.y + 1, 2.0) / 2.0;
}
static void cubeUBLeft(Tuple point, double &u, double &v) {
u = modulo(point.z + 1, 2.0) / 2.0;
v = modulo(point.y + 1, 2.0) / 2.0;
}
static void cubeUBRight(Tuple point, double &u, double &v) {
u = modulo(1 - point.z, 2.0) / 2.0;
v = modulo(point.y + 1, 2.0) / 2.0;
}
static void cubeUBUp(Tuple point, double &u, double &v) {
u = modulo(point.x + 1, 2.0) / 2.0;
v = modulo(1 - point.z, 2.0) / 2.0;
}
static void cubeUBDown(Tuple point, double &u, double &v) {
u = modulo(point.x + 1, 2.0) / 2.0;
v = modulo(point.z + 1, 2.0) / 2.0;
}
void setCubePattern(UVPattern *front, UVPattern *left, UVPattern *right,
UVPattern *back, UVPattern *up, UVPattern *down)
{
this->frontPat = front;
this->leftPat = left;
this->rightPat = right;
this->backPat = back;
this->upPat = up;
this->downPat = down;
}
Colour patternAt(Tuple point)
{
double u,v;
if (this->type == CUBIC_MAP)
{
CubeFaces face = TextureMap::faceFromPoint(point);
UVPattern *facePat;
switch(face)
{
default:
case CUBE_LEFT: facePat = this->leftPat; TextureMap::cubeUBLeft(point, u, v); break;
case CUBE_RIGHT: facePat = this->rightPat; TextureMap::cubeUBRight(point, u, v); break;
case CUBE_FRONT: facePat = this->frontPat; TextureMap::cubeUBFront(point, u, v); break;
case CUBE_BACK: facePat = this->backPat; TextureMap::cubeUBBack(point, u, v); break;
case CUBE_UP: facePat = this->upPat; TextureMap::cubeUBUp(point, u, v); break;
case CUBE_DOWN: facePat = this->downPat; TextureMap::cubeUBDown(point, u, v); break;
}
return facePat->uvPatternAt(u, v);
}
else
{
switch (this->type)
{
default:
case SPHERICAL_MAP:
this->sphericalMap(point, u, v);
break;
case PLANAR_MAP:
this->planarMap(point, u, v);
break;
case CYLINDRICAL_MAP:
this->cylindricalMap(point, u, v);
break;
}
return this->pattern->uvPatternAt(u, v);
}
}
void dumpMe(FILE *fp) {
fprintf(fp, "\"Type\": \"TextureMap\",\n");
Pattern::dumpMe(fp);
}
};
#endif /* DORAYME_TEXTUREMAP_H */

202
source/renderstat.cpp Normal file
View File

@@ -0,0 +1,202 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Render statistics implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <renderstat.h>
#include <stdio.h>
RenderStats stats;
#ifdef RENDER_STATS
void RenderStats::addCone()
{
#pragma omp atomic
this->coneCount++;
};
void RenderStats::addCylinder()
{
#pragma omp atomic
this->cylinderCount++;
};
void RenderStats::addCube()
{
#pragma omp atomic
this->cubeCount++;
};
void RenderStats::addGroup()
{
#pragma omp atomic
this->groupCount++;
};
void RenderStats::addLight()
{
#pragma omp atomic
this->lightCount++;
};
void RenderStats::addPlane()
{
#pragma omp atomic
this->planeCount++;
};
void RenderStats::addSphere()
{
#pragma omp atomic
this->sphereCount++;
};
void RenderStats::addTriangle()
{
#pragma omp atomic
this->triangleCount++;
};
void RenderStats::addSmoothTriangle()
{
#pragma omp atomic
this->smoothTriangleCount++;
};
void RenderStats::addOBJFile()
{
#pragma omp atomic
this->objfileCount++;
};
void RenderStats::addPixel()
{
#pragma omp atomic
this->pixelCount++;
};
void RenderStats::addRay()
{
#pragma omp atomic
this->rayCount++;
};
void RenderStats::addCastedRay()
{
#pragma omp atomic
this->rayCasted++;
};
void RenderStats::addLightRay()
{
this->addCastedRay();
#pragma omp atomic
this->lightRayEmitedCount++;
};
void RenderStats::addReflectRay()
{
this->addCastedRay();
#pragma omp atomic
this->reflectionRayCount++;
};
void RenderStats::addRefractRay()
{
this->addCastedRay();
#pragma omp atomic
this->refractedRayCount++;
};
void RenderStats::addIntersect()
{
#pragma omp atomic
this->intersectCount++;
};
void RenderStats::addIntersection()
{
#pragma omp atomic
this->intersectionCount++;
};
void RenderStats::addMalloc()
{
#pragma omp atomic
this->mallocCallCount++;
};
void RenderStats::addRealloc()
{
#pragma omp atomic
this->reallocCallCount++;
};
void RenderStats::addDiscardedIntersect()
{
#pragma omp atomic
this->discardedIntersectCount++;
};
void RenderStats::addCsg()
{
#pragma omp atomic
this->csgCount++;
};
void RenderStats::setMaxDepth(uint32_t depth)
{
if (this->maxDepthAttained > depth)
{
this->maxDepthAttained = depth;
}
};
void RenderStats::setMaxIntersect(uint32_t count)
{
if (this->maxIntersectOnARay < count)
{
this->maxIntersectOnARay = count;
}
};
void RenderStats::printStats()
{
printf("Rendering statistics:\n");
printf("Cones : %lld\n", this->coneCount);
printf("Cubes : %lld\n", this->cubeCount);
printf("Cylinders : %lld\n", this->cylinderCount);
printf("Groups : %lld\n", this->groupCount);
printf("Lights : %lld\n", this->lightCount);
printf("Planes : %lld\n", this->planeCount);
printf("Spheres : %lld\n", this->sphereCount);
printf("Triangles : %lld\n", this->triangleCount);
printf("Smooth Triangles : %lld\n", this->smoothTriangleCount);
printf("OBJ File : %lld\n", this->objfileCount);
printf("CSG : %lld\n", this->csgCount);
printf("==================================================\n");
printf("Pixel rendered : %lld\n", this->pixelCount);
printf("Ray created : %lld\n", this->rayCount);
printf("Ray casted : %lld\n", this->rayCasted);
printf("Light Ray casted : %lld\n", this->lightRayEmitedCount);
printf("Reflection ray casted : %lld\n", this->reflectionRayCount);
printf("Refraction ray casted : %lld\n", this->refractedRayCount);
printf("Intersect object created: %lld\n", this->intersectCount);
printf("Intersection created : %lld\n", this->intersectionCount);
printf("Malloc called : %lld\n", this->mallocCallCount);
printf("Realloc called : %lld\n", this->reallocCallCount);
printf("Bounding box missed : %lld\n", this->discardedIntersectCount);
printf("Min depth attained : %lld\n", this->maxDepthAttained);
printf("Max intersect count : %lld\n", this->maxIntersectOnARay);
printf("==================================================\n");
};
#endif

33
source/sequence.cpp Normal file
View File

@@ -0,0 +1,33 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Sequence implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <sequence.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <math_helper.h>
Sequence::Sequence() : list(nullptr), listPos(0), listSize(0) {
/* Need to bootstrap rand here */
srand(time(NULL));
}
Sequence::Sequence(double *list, uint32_t listSize) : list(list), listPos(0), listSize(listSize) { };
double Sequence::next() {
if (this->listSize == 0)
{
return frand();
}
else
{
uint32_t pos = this->listPos;
this->listPos = (this->listPos + 1) % this->listSize;
return this->list[pos];
}
}

146
source/shapes/cone.cpp Normal file
View File

@@ -0,0 +1,146 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Cone implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <tuple.h>
#include <ray.h>
#include <shape.h>
#include <cone.h>
#include <math_helper.h>
bool Cone::checkCap(Ray r, double t, double y)
{
/* Helping function to reduce duplication.
* Checks to see if the intersection ot t is within a radius
* of 1 (the radius of our Cone from the y axis
*/
double x = r.origin.x + t * r.direction.x;
double z = r.origin.z + t * r.direction.z;
return (x * x + z * z) <= fabs(y);
}
void Cone::intersectCaps(Ray r, Intersect &xs)
{
/* Caps only mattter is the Cone is closed, and might possibly be
* intersected by the ray
*/
if ((this->isClosed) && (fabs(r.direction.y) > getEpsilon()))
{
double t;
/* Check for an intersection with the lower end cap by intersecting
* the ray with the plan at y = this->minCap
*/
t = (this->minCap - r.origin.y) / r.direction.y;
if (this->checkCap(r, t, this->minCap))
{
xs.add(Intersection(t, this));
}
/* Check for an intersection with the upper end cap by intersecting
* the ray with the plan at y = this->maxCap
*/
t = (this->maxCap - r.origin.y) / r.direction.y;
if (this->checkCap(r, t, this->maxCap))
{
xs.add(Intersection(t, this));
}
}
}
void Cone::localIntersect(Ray r, Intersect &xs)
{
double A = (r.direction.x * r.direction.x) -
(r.direction.y * r.direction.y) +
(r.direction.z * r.direction.z);
double B = (2 * r.origin.x * r.direction.x) -
(2 * r.origin.y * r.direction.y) +
(2 * r.origin.z * r.direction.z);
double C = (r.origin.x * r.origin.x) -
(r.origin.y * r.origin.y) +
(r.origin.z * r.origin.z);
if ((fabs(A) <= getEpsilon()) && (fabs(B) >= getEpsilon()))
{
double t = -C / (2*B);
xs.add(Intersection(t, this));
}
else if (fabs(A) >= getEpsilon())
{
double disc = (B * B) - 4 * A * C;
if (disc >= 0)
{
double t0 = (-B - sqrt(disc)) / (2 * A);
double t1 = (-B + sqrt(disc)) / (2 * A);
double y0 = r.origin.y + t0 * r.direction.y;
if ((this->minCap < y0) && (y0 < this->maxCap))
{
xs.add(Intersection(t0, this));
}
double y1 = r.origin.y + t1 * r.direction.y;
if ((this->minCap < y1) && (y1 < this->maxCap))
{
xs.add(Intersection(t1, this));
}
}
}
this->intersectCaps(r, xs);
}
Tuple Cone::localNormalAt(Tuple point, Intersection *hit)
{
/* Compute the square of the distance from the Y axis */
double dist = point.x * point.x + point.z * point.z;
if ((dist < 1) && (point.y >= (this->maxCap - getEpsilon())))
{
return Vector(0, 1, 0);
}
if ((dist < 1) && (point.y <= this->minCap + getEpsilon()))
{
return Vector(0, -1, 0);
}
double y = sqrt(point.x * point.x + point.z * point.z);
if (point.y > 0)
{
y = -y;
}
return Vector(point.x, y, point.z);
}
BoundingBox Cone::getLocalBounds()
{
BoundingBox ret;
double a = fabs(this->minCap);
double b = fabs(this->maxCap);
double limit = (a > b)?a:b;
ret | Point(-limit, this->minCap, -limit);
ret | Point(limit, this->maxCap, limit);
return ret;
}
void Cone::dumpMe(FILE *fp)
{
fprintf(fp, "\"Type\": \"Cylinder\",\n");
Tuple t = this->transformMatrix * Point(0, 0, 0);
fprintf(fp, "\"pseudocenter\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
t = this->transformMatrix * Point(0, this->minCap, 0);
fprintf(fp, "\"min\": %f, \n", t.y);
t = this->transformMatrix * Point(1, this->maxCap, 1);
fprintf(fp, "\"max\": %f, \n", t.y);
Shape::dumpMe(fp);
}

146
source/shapes/csg.cpp Normal file
View File

@@ -0,0 +1,146 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Constructive Solid Geometry (CSG) implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <tuple.h>
#include <ray.h>
#include <shape.h>
#include <csg.h>
#include <math_helper.h>
CSG::CSG(OperationType operation, Shape *left, Shape *right) : Shape(Shape::CSG), operation(operation), left(left), right(right)
{
stats.addCsg();
this->left->setParent(this);
this->right->setParent(this);
this->bounds | this->left->getBounds();
this->bounds | this->right->getBounds();
}
void CSG::localIntersect(Ray r, Intersect &xs)
{
this->intersect(r, xs);
}
void CSG::intersect(Ray &r, Intersect &xs)
{
int i;
Intersect tmp = Intersect();
if (this->bounds.intesectMe(r))
{
this->left->intersect(r, tmp);
this->right->intersect(r, tmp);
this->filterIntersections(tmp, xs);
}
}
Tuple CSG::localNormalAt(Tuple point, Intersection *hit)
{
return Vector(1, 0, 0);
}
BoundingBox CSG::getLocalBounds()
{
return this->bounds;
}
BoundingBox CSG::getBounds()
{
if (this->bounds.isEmpty()) { this->updateBoundingBox(); }
return this->bounds;
}
void CSG::updateBoundingBox()
{
this->bounds.reset();
this->bounds | this->left->getBounds();
this->bounds | this->right->getBounds();
}
void CSG::updateTransform()
{
Shape::updateTransform();
this->left->updateTransform();
this->right->updateTransform();
/* Once the full stack being notified of the changes, let's update the
* bounding box
*/
this->updateBoundingBox();
}
bool CSG::includes(Shape *b)
{
if (this->left->includes(b)) { return true; }
if (this->right->includes(b)) { return true; }
if (this == b) { return true; }
return false;
}
bool CSG::intersectionAllowed(bool leftHit, bool inLeft, bool inRight)
{
switch(this->operation)
{
case CSG::UNION: return (leftHit && !inRight) || (!leftHit && !inLeft);
case CSG::INTERSECTION: return (!leftHit && inLeft) || (leftHit && inRight);
case CSG::DIFFERENCE: return (leftHit && !inRight) || (!leftHit && inLeft);
}
return false;
}
void CSG::filterIntersections(Intersect &xs, Intersect &ret)
{
bool inl = false;
bool inr = false;
int i;
for(i = 0; i < xs.count(); i++)
{
bool lhit = this->left->includes(xs[i].object);
if (this->intersectionAllowed(lhit, inl, inr))
{
ret.add(xs[i]);
}
if (lhit)
{
inl = !inl;
}
else
{
inr = !inr;
}
}
}
void CSG::lock()
{
Shape::lock();
if(this->left)
{
this->left->lock();
}
if(this->right)
{
this->right->lock();
}
}
void CSG::dumpMe(FILE *fp)
{
}

84
source/shapes/cube.cpp Normal file
View File

@@ -0,0 +1,84 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Cube implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <tuple.h>
#include <ray.h>
#include <shape.h>
#include <cube.h>
#include <math_helper.h>
void Cube::checkAxis(double axeOrigin, double axeDirection, double *axeMin, double *axeMax)
{
double tMinNumerator = (-1 - axeOrigin);
double tMaxNumerator = (1 - axeOrigin);
if (fabs(axeDirection) >= getEpsilon())
{
*axeMin = tMinNumerator / axeDirection;
*axeMax = tMaxNumerator / axeDirection;
}
else
{
*axeMin = tMinNumerator * INFINITY;
*axeMax = tMaxNumerator * INFINITY;
}
if (*axeMin > *axeMax)
{
double swap = *axeMax;
*axeMax = *axeMin;
*axeMin = swap;
}
}
void Cube::localIntersect(Ray r, Intersect &xs)
{
double xtMin, xtMax, ytMin, ytMax, ztMin, ztMax;
double tMin, tMax;
this->checkAxis(r.origin.x, r.direction.x, &xtMin, &xtMax);
this->checkAxis(r.origin.y, r.direction.y, &ytMin, &ytMax);
this->checkAxis(r.origin.z, r.direction.z, &ztMin, &ztMax);
tMin = max3(xtMin, ytMin, ztMin);
tMax = min3(xtMax, ytMax, ztMax);
if (tMin <= tMax)
{
xs.add(Intersection(tMin, this));
xs.add(Intersection(tMax, this));
}
}
Tuple Cube::localNormalAt(Tuple point, Intersection *hit)
{
double maxC = max3(fabs(point.x), fabs(point.y), fabs(point.z));
if (maxC == fabs(point.x))
{
return Vector(point.x, 0, 0);
}
else if (maxC == fabs(point.y))
{
return Vector(0, point.y, 0);
}
return Vector(0, 0, point.z);
}
void Cube::dumpMe(FILE *fp)
{
fprintf(fp, "\"Type\": \"Cube\",\n");
Tuple t = this->transformMatrix * Point(0, 0, 0);
fprintf(fp, "\"center\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
t = this->transformMatrix * Point(1, 1, 1);
fprintf(fp, "\"corner\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
Shape::dumpMe(fp);
}

128
source/shapes/cylinder.cpp Normal file
View File

@@ -0,0 +1,128 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Cylinder implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <tuple.h>
#include <ray.h>
#include <shape.h>
#include <cylinder.h>
#include <math_helper.h>
bool Cylinder::checkCap(Ray r, double t)
{
/* Helping function to reduce duplication.
* Checks to see if the intersection ot t is within a radius
* of 1 (the radius of our cylinder from the y axis
*/
double x = r.origin.x + t * r.direction.x;
double z = r.origin.z + t * r.direction.z;
return (x * x + z * z) <= 1;
}
void Cylinder::intersectCaps(Ray r, Intersect &xs)
{
/* Caps only matter if the cylinder is closed, and might possibly be
* intersected by the ray
*/
if ((this->isClosed) && (fabs(r.direction.y) > getEpsilon()))
{
double t;
/* Check for an intersection with the lower end cap by intersecting
* the ray with the plan at y = this->minCap
*/
t = (this->minCap - r.origin.y) / r.direction.y;
if (this->checkCap(r, t))
{
xs.add(Intersection(t, this));
}
/* Check for an intersection with the upper end cap by intersecting
* the ray with the plan at y = this->maxCap
*/
t = (this->maxCap - r.origin.y) / r.direction.y;
if (this->checkCap(r, t))
{
xs.add(Intersection(t, this));
}
}
}
void Cylinder::localIntersect(Ray r, Intersect &xs)
{
double A = r.direction.x * r.direction.x + r.direction.z * r.direction.z;
/* Ray is parallel to the Y axis */
if (A >= getEpsilon())
{
double B = 2 * r.origin.x * r.direction.x +
2 * r.origin.z * r.direction.z;
double C = r.origin.x * r.origin.x + r.origin.z * r.origin.z - 1;
double disc = B * B - 4 * A * C;
if (disc >= 0)
{
double t0 = (-B - sqrt(disc)) / (2 * A);
double t1 = (-B + sqrt(disc)) / (2 * A);
double y0 = r.origin.y + t0 * r.direction.y;
if ((this->minCap < y0) && (y0 < this->maxCap))
{
xs.add(Intersection(t0, this));
}
double y1 = r.origin.y + t1 * r.direction.y;
if ((this->minCap < y1) && (y1 < this->maxCap))
{
xs.add(Intersection(t1, this));
}
}
}
this->intersectCaps(r, xs);
}
Tuple Cylinder::localNormalAt(Tuple point, Intersection *hit)
{
/* Compute the square of the distance from the Y axis */
double dist = point.x * point.x + point.z * point.z;
if ((dist < 1) && (point.y >= (this->maxCap - getEpsilon())))
{
return Vector(0, 1, 0);
}
if ((dist < 1) && (point.y <= this->minCap + getEpsilon()))
{
return Vector(0, -1, 0);
}
return Vector(point.x, 0, point.z);
}
BoundingBox Cylinder::getLocalBounds()
{
BoundingBox ret;
ret | Point(-1, this->minCap, -1);
ret | Point(1, this->maxCap, 1);
return ret;
}
void Cylinder::dumpMe(FILE *fp)
{
fprintf(fp, "\"Type\": \"Cylinder\",\n");
Tuple t = this->transformMatrix * Point(0, 0, 0);
fprintf(fp, "\"pseudocenter\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
t = this->transformMatrix * Point(0, this->minCap, 0);
fprintf(fp, "\"min\": %f, \n", t.y);
t = this->transformMatrix * Point(1, this->maxCap, 1);
fprintf(fp, "\"max\": %f, \n", t.y);
Shape::dumpMe(fp);
}

279
source/shapes/group.cpp Normal file
View File

@@ -0,0 +1,279 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Group implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <tuple.h>
#include <ray.h>
#include <group.h>
#include <math_helper.h>
#include <renderstat.h>
#include <string.h>
#define MIN_ALLOC (2)
Group::Group(const char *name) : Shape(Shape::GROUP)
{
stats.addGroup();
this->allocatedObjectCount = MIN_ALLOC;
this->objectList = (Shape **)calloc(sizeof(Shape **), MIN_ALLOC);
this->objectCount = 0;
this->allocatedUnboxableObjectCount = MIN_ALLOC;
this->unboxableObjectList = (Shape **)calloc(sizeof(Shape **), MIN_ALLOC);
this->unboxableObjectCount = 0;
if (name != nullptr)
{
strncpy(this->name, name, 32);
}
else
{
strncpy(this->name, "untitled", 32);
}
}
void Group::intersect(Ray &r, Intersect &xs)
{
int i, j;
if (this->objectCount > 0)
{
if (this->bounds.intesectMe(r))
{
for (i = 0 ; i < this->objectCount ; i++)
{
this->objectList[i]->intersect(r, xs);
}
}
}
/* We are force to do them all the time */
if (this->unboxableObjectCount > 0)
{
for(i = 0; i < this->unboxableObjectCount; i++)
{
this->unboxableObjectList[i]->intersect(r, xs);
}
}
}
bool Group::includes(Shape *b)
{
if (this->objectCount > 0)
{
int i;
for (i = 0 ; i < this->objectCount ; i++)
{
if (this->objectList[i] == b)
{
return true;
}
}
}
if (this->unboxableObjectCount > 0)
{
int i;
for(i = 0; i < this->unboxableObjectCount; i++)
{
if (this->unboxableObjectList[i] == b)
{
return true;
}
}
}
return false;
}
void Group::localIntersect(Ray r, Intersect &xs)
{
this->intersect(r, xs);
}
Tuple Group::localNormalAt(Tuple point, Intersection *hit)
{
return Vector(1, 0, 0);
}
/* ONLY INSERT SHAPES THAT ARE NOT GOING TO CHANGE ELSE..! */
void Group::addObject(Shape *s)
{
if (s->haveFiniteBounds())
{
if ((this->objectCount + 1) > this->allocatedObjectCount)
{
this->allocatedObjectCount *= 2;
this->objectList = (Shape **)realloc(this->objectList, sizeof(Shape **) * this->allocatedObjectCount);
}
s->setParent(this);
s->updateTransform();
this->objectList[this->objectCount++] = s;
this->bounds | s->getBounds();
}
else
{
if ((this->unboxableObjectCount + 1) > this->allocatedUnboxableObjectCount)
{
this->allocatedUnboxableObjectCount *= 2;
this->unboxableObjectList = (Shape **)realloc(this->unboxableObjectList, sizeof(Shape **) * this->allocatedUnboxableObjectCount);
}
s->setParent(this);
s->updateTransform();
this->unboxableObjectList[this->unboxableObjectCount++] = s;
}
}
void Group::removeObject(Shape *s)
{
int i;
if (s->haveFiniteBounds())
{
for (i = 0; i < this->objectCount; i++)
{
if (this->objectList[i] == s)
{
this->objectCount --;
this->objectList[i] = this->objectList[this->objectCount];
this->objectList[this->objectCount] = nullptr;
break;
}
}
}
else
{
for (i = 0; i < this->unboxableObjectCount; i++)
{
if (this->unboxableObjectList[i] == s)
{
this->unboxableObjectCount --;
this->unboxableObjectList[i] = this->unboxableObjectList[this->unboxableObjectCount];
this->unboxableObjectList[this->unboxableObjectCount] = nullptr;
break;
}
}
}
}
bool Group::isEmpty()
{
return (this->objectCount == 0) && (this->unboxableObjectCount == 0);
}
BoundingBox Group::getLocalBounds()
{
return this->bounds;
}
BoundingBox Group::getBounds()
{
if (this->bounds.isEmpty()) { this->updateBoundingBox(); }
return this->bounds;
}
void Group::updateBoundingBox()
{
this->bounds.reset();
if (this->objectCount > 0)
{
int i;
for(i = 0; i < this->objectCount; i++)
{
if (this->objectList[i]->haveFiniteBounds())
{
BoundingBox objB = this->objectList[i]->getBounds();
this->bounds | objB;
}
}
}
}
void Group::updateTransform()
{
int i;
Shape::updateTransform();
if (this->objectCount > 0)
{
for (i = 0 ; i < this->objectCount ; i++)
{
this->objectList[i]->updateTransform();
}
}
if (this->unboxableObjectCount > 0)
{
for(i = 0; i < this->unboxableObjectCount; i++)
{
this->unboxableObjectList[i]->updateTransform();
}
}
/* Once the full stack being notified of the changes, let's update the
* bounding box
*/
this->updateBoundingBox();
}
void Group::dumpMe(FILE *fp)
{
int i;
fprintf(fp, "\"Type\": \"Group\",\n");
fprintf(fp, "\"Name\": \"%s\",\n", this->name);
if (this->objectCount > 0)
{
fprintf(fp, "\"Objects\": {\n");
for(i = 0; i < this->objectCount; i++)
{
fprintf(fp, "\"%d\": {\n", i);
this->objectList[i]->dumpMe(fp);
fprintf(fp, "},\n");
}
fprintf(fp, "},\n");
}
if (this->unboxableObjectCount > 0)
{
fprintf(fp, "\"UnboxableObjects\": {\n");
for(i = 0; i < this->objectCount; i++)
{
fprintf(fp, "\"%d\": {\n", i);
this->objectList[i]->dumpMe(fp);
fprintf(fp, "},\n");
}
fprintf(fp, "},\n");
}
Shape::dumpMe(fp);
}
void Group::lock()
{
Shape::lock();
/* Now notify included object they have to lock */
int i;
if (this->objectCount > 0)
{
for (i = 0 ; i < this->objectCount ; i++)
{
this->objectList[i]->lock();
}
}
if (this->unboxableObjectCount > 0)
{
for(i = 0; i < this->unboxableObjectCount; i++)
{
this->unboxableObjectList[i]->lock();
}
}
}

Some files were not shown because too many files have changed in this diff Show More