98 Commits

Author SHA1 Message Date
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
151 changed files with 22592 additions and 388 deletions

3
.gitmodules vendored
View File

@@ -1,9 +1,6 @@
[submodule "external/googletest"]
path = external/googletest
url = https://github.com/google/googletest.git
[submodule "external/nanogui"]
path = external/nanogui
url = https://github.com/Godzil/nanogui.git
[submodule "external/glfw"]
path = external/glfw
url = https://github.com/glfw/glfw.git

View File

@@ -19,7 +19,8 @@ script:
- cmake ..
- make
- make test
- ./tests/testMyRays
- cd tests
- ./testMyRays
jobs:
include:
@@ -33,4 +34,9 @@ jobs:
- cmake --build .
- cmake --build . --target coveralls
after_success:
- bash <(curl -s https://codecov.io/bash)
- bash <(curl -s https://codecov.io/bash)
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink python@2 ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install imagemagick ; fi

View File

@@ -10,18 +10,82 @@ 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" ON)
if (SHOW_STATS)
add_compile_options(-DRENDER_STATS)
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
add_library(LodePNG STATIC)
set(LODEPNG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/lodepng)
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
add_subdirectory(source)

View File

@@ -6,26 +6,94 @@ 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.
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.
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:
#### From chapter 05 - Sphere intersections:
![Chapter 5 rendering test](output/ch5_test.png)
From Chapter 06:
#### From Chapter 06 - Phong shading:
![Chapter 6 rendering test](output/ch6_test.png)
From Chapter 07:
#### From Chapter 07 - World / Camera / Scenes:
![Chapter 7 rendering test](output/ch7_test.png)
From Chapter 08:
#### From Chapter 08 - Shadows:
![Chapter 8 rendering test](output/ch8_test.png)
![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)

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/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

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

View File

@@ -1,21 +1,42 @@
# 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
add_library(rayonnement STATIC)
file(GLOB RAY_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
file(GLOB RAY_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/pattern/*.h
${CMAKE_CURRENT_SOURCE_DIR}/uvpattern/*.h)
file(GLOB RAY_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shapes/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/worldbuilder/*.cpp)
target_include_directories(rayonnement PUBLIC include)
target_sources(rayonnement PRIVATE ${RAY_HEADERS} ${RAY_SOURCES})
target_link_libraries(rayonnement LodePNG)
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_link_libraries(rayonnement LodePNG NanoJPEG)
if (USE_OPENMP)
target_link_libraries(rayonnement OpenMP::OpenMP_CXX)
endif()
# The main executable
#add_executable(dorayme main.cpp)
#add_dependencies(dorayme LuaCore)
#target_link_libraries(dorayme rayonnement ${LUA_LIBRARIES})
# Second we build the main executable
add_executable(dorayme main.cpp)
target_include_directories(rayonnement PUBLIC include ${LODEPNG_INCLUDE_FOLDER})
target_link_libraries(dorayme rayonnement)
if (COVERALLS)
set(COVERAGE_SRCS ${RAY_HEADERS} ${RAY_SOURCES} ${COVERAGE_SRCS} PARENT_SCOPE)

View File

@@ -12,6 +12,9 @@
#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)
{
double aspectRatio = (double)hsize / (double)vsize;
@@ -31,7 +34,6 @@ Camera::Camera(uint32_t hsize, uint32_t vsize, double fov) : verticalSize(vsize)
this->pixelSize = (this->halfWidth * 2) / this->horizontalSize;
this->setTransform(Matrix4().identity());
}
void Camera::setTransform(Matrix transform)
@@ -55,20 +57,28 @@ Ray Camera::rayForPixel(uint32_t pixelX, uint32_t pixelY)
return Ray(origin, direction);
}
Canvas Camera::render(World world)
Canvas Camera::render(World world, uint32_t depth)
{
uint32_t x, y;
Canvas image = Canvas(this->horizontalSize, this->verticalSize);
for(y = 0; y < this->verticalSize; y++)
#pragma omp parallel default(shared) private(x, y) shared(image, stats)
{
for(x = 0; x < this->horizontalSize; x++)
#pragma omp for schedule(dynamic, 5)
for (y = 0 ; y < this->verticalSize ; y++)
{
Ray r = this->rayForPixel(x, y);
Tuple colour = world.colourAt(r);
image.putPixel(x, y, colour);
for (x = 0 ; x < this->horizontalSize ; x++)
{
Ray r = this->rayForPixel(x, y);
Tuple 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 <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 BytePP (BPP / 8)
@@ -40,6 +50,80 @@ Canvas::Canvas(const Canvas *b)
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()
{
if (this->bitmap != nullptr)
@@ -48,12 +132,12 @@ Canvas::~Canvas()
}
}
void Canvas::putPixel(uint32_t x, uint32_t y, Tuple colour)
void Canvas::putPixel(uint32_t x, uint32_t y, Tuple c)
{
uint32_t offset = y * this->stride + x * BytePP;
this->bitmap[offset + 0] = MAX(MIN(colour.x * 255, 255), 0);
this->bitmap[offset + 1] = MAX(MIN(colour.y * 255, 255), 0);
this->bitmap[offset + 2] = MAX(MIN(colour.z * 255, 255), 0);
this->bitmap[offset + 0] = MAX(MIN(c.x * 255, 255), 0);
this->bitmap[offset + 1] = MAX(MIN(c.y * 255, 255), 0);
this->bitmap[offset + 2] = MAX(MIN(c.z * 255, 255), 0);
}
Colour Canvas::getPixel(uint32_t x, uint32_t y)
@@ -67,4 +151,4 @@ bool Canvas::SaveAsPNG(const char *filename)
uint32_t ret = lodepng_encode24_file(filename, this->bitmap, this->width, this->height);
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 */

View File

@@ -32,7 +32,7 @@ public:
Camera(uint32_t hsize, uint32_t vsize, double fov);
void setTransform(Matrix transform);
Ray rayForPixel(uint32_t pixelX, uint32_t pixelY);
Canvas render(World w);
Canvas render(World w, uint32_t depth = 5);
};
#endif /* DORAYME_CAMERA_H */

View File

@@ -23,6 +23,8 @@ public:
Canvas(uint32_t width, uint32_t height);
Canvas(const Canvas *c);
Canvas(const Canvas &c);
Canvas(const char *imgfile);
~Canvas();
void putPixel(uint32_t x, uint32_t y, Tuple c);

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:
Intersect localIntersect(Ray r);
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 */

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

@@ -0,0 +1,54 @@
/*
* 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:
Intersect localIntersect(Ray r);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
BoundingBox getLocalBounds();
bool intersectionAllowed(bool leftHit, bool inLeft, bool inRight);
Intersect filterIntersections(Intersect &xs);
void updateBoundingBox();
BoundingBox getBounds();
public:
CSG(OperationType operation, Shape *left, Shape *right);
Intersect intersect(Ray r);
bool includes(Shape *b);
void updateTransform();
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);
Intersect localIntersect(Ray r);
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:
Intersect localIntersect(Ray r);
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

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

@@ -0,0 +1,54 @@
/*
* 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;
protected:
Intersect localIntersect(Ray r);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
BoundingBox bounds;
public:
bool isEmpty();
void addObject(Shape *s);
Shape *operator[](const int p) { return this->objectList[p]; }
Intersect intersect(Ray r);
BoundingBox getLocalBounds();
BoundingBox getBounds();
void updateBoundingBox();
void updateTransform();
bool includes(Shape *b);
Group();
void dumpMe(FILE * fp);
};
#endif /* DORAYME_GROUP_H */

View File

@@ -21,6 +21,7 @@ private:
public:
Intersect();
~Intersect();
void reset();
void add(Intersection i);
int count() { return this->num; };
Intersection operator[](const int p) { return *this->list[p]; }

View File

@@ -11,20 +11,59 @@
#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) :
object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside), overHitPoint(overHitP) { };
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()
{
/* 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));
};
Shape *object;
double t;
Tuple hitPoint;
Tuple overHitPoint;
Tuple underHitPoint;
Tuple eyeVector;
Tuple normalVector;
Tuple reflectVector;
Material *material;
double n1;
double n2;
bool inside;
};
@@ -35,11 +74,13 @@ public:
double t;
Shape *object;
double u, v;
public:
Intersection(double t, Shape *object) : t(t), object(object) { };
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);
Computation prepareComputation(Ray r, Intersect *xs = nullptr);
bool operator==(const Intersection &b) const { return ((this->t == b.t) && (this->object == b.object)); };
};

View File

@@ -11,10 +11,17 @@
#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
@@ -24,13 +31,37 @@ public:
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) { };
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

View File

@@ -11,7 +11,11 @@
#include <tuple.h>
#include <colour.h>
#include <pattern.h>
#include <light.h>
#include <stdio.h>
class Shape;
class Material
{
@@ -21,17 +25,33 @@ public:
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) {};
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, bool inShadow = false);
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

@@ -18,4 +18,14 @@ bool double_equal(double a, double b);
double deg_to_rad(double deg);
double min3(double a, double b, double c);
double max3(double a, double b, double c);
double frand();
static double modulo(double a, double b)
{
return a - floor(a/b) * b;
}
#endif /* DORAYME_MATH_HELPER_H */

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

@@ -0,0 +1,72 @@
/*
* 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:
uint32_t allocatedFaceGroupCount;
Group* *faceGroupList;
uint32_t faceGroupCount;
uint32_t allocatedVertexCount;
Point* *vertexList;
uint32_t vertexCount;
uint32_t allocatedVertexNormalCount;
Vector* *vertexNormalList;
uint32_t vertexNormalCount;
private:
Intersect localIntersect(Ray r);
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);
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(uint32_t i) { return this->faceGroupList[i]; };
Intersect intersect(Ray r);
BoundingBox getLocalBounds();
BoundingBox getBounds();
bool includes(Shape *b);
void updateBoundingBox();
void updateTransform();
void dumpMe(FILE * fp);
};
#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:
Intersect localIntersect(Ray r);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
Plane() : Shape(SHAPE_PLANE) { stats.addPlane(); };
BoundingBox getLocalBounds();
bool haveFiniteBounds() { return false; };
};
#endif //DORAYME_PLANE_H

View File

@@ -10,6 +10,7 @@
#define DORAYME_RAY_H
#include <tuple.h>
#include <renderstat.h>
class Ray
{
@@ -17,7 +18,7 @@ public:
Tuple direction;
Tuple origin;
Ray(Tuple origin, Tuple direction) : origin(origin), direction(direction) { };
Ray(Tuple origin, Tuple direction) : origin(origin), direction(direction) { stats.addRay(); };
Tuple position(double t) { return this->origin + this->direction * t; };
};

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

@@ -0,0 +1,103 @@
/*
* 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 */
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) {};
#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 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 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 */

View File

@@ -11,39 +11,75 @@
class Shape;
#include <stdio.h>
#include <ray.h>
#include <tuple.h>
#include <matrix.h>
#include <intersect.h>
#include <material.h>
#include <boundingbox.h>
enum ShapeType
{
SHAPE_NONE,
SHAPE_SPHERE,
SHAPE_PLANE,
SHAPE_CUBE,
SHAPE_CYLINDER,
SHAPE_CONE,
SHAPE_GROUP,
SHAPE_TRIANGLE,
SHAPE_OBJFILE,
SHAPE_SMOOTHTRIANGLE,
SHAPE_CSG,
};
/* Base class for all object that can be presented in the world */
class Shape
{
private:
protected:
ShapeType type;
Matrix localTransformMatrix;
protected:
virtual Intersect localIntersect(Ray r) = 0;
virtual Tuple localNormalAt(Tuple point, Intersection *hit) = 0;
public:
Matrix transformMatrix;
Matrix inverseTransform;
Matrix transposedInverseTransform;
Material material;
bool dropShadow;
Shape *parent;
bool materialSet;
public:
Shape(ShapeType = SHAPE_NONE);
virtual Intersect intersect(Ray r);
virtual Tuple normalAt(Tuple point);
Tuple normalAt(Tuple point, Intersection *hit = nullptr);
/* 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);
Tuple worldToObject(Tuple point) { return this->inverseTransform * point; };
Tuple objectToWorld(Tuple point) { return this->transformMatrix * point; };
Tuple normalToWorld(Tuple normalVector);
void setTransform(Matrix transform);
void setMaterial(Material material) { this->material = material; };
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); };
void setMaterial(Material material) { this->material = material; this->materialSet = true; };
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 &&

View File

@@ -0,0 +1,28 @@
/*
* 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);
};
#endif /* DORAYME_SMOOTHTRIANGLE_H */

View File

@@ -12,14 +12,28 @@
#include <shape.h>
#include <ray.h>
#include <intersect.h>
#include <renderstat.h>
#include <stdio.h>
class Sphere : public Shape
{
protected:
Intersect localIntersect(Ray r);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
Sphere() : Shape(SHAPE_SPHERE) { };
Sphere() : Shape(SHAPE_SPHERE) { stats.addSphere(); };
/* All sphere are at (0, 0, 0) and radius 1 in the object space */
virtual Intersect intersect(Ray r);
virtual Tuple normalAt(Tuple point);
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:
Intersect localIntersect(Ray r);
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
public:
Ray localRay;
TestShape();
};
#endif //DORAYME_TESTSHAPE_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:
Intersect localIntersect(Ray r);
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

@@ -17,6 +17,7 @@ public:
double x, y, z, w;
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, double w) : x(x), y(y), z(z), w(w) {};
bool isPoint() { return (this->w == 1.0); };
@@ -26,6 +27,7 @@ public:
double_equal(this->y, b.y) &&
double_equal(this->z, b.z) &&
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,
this->z + b.z, this->w + b.w); };
@@ -38,6 +40,11 @@ public:
Tuple operator/(const double &b) const { return Tuple(this->x / b, this->y / b,
this->z / b, this->w / b); };
void fixPoint();
void fixVector();
bool isRepresentable();
void set(double nX, double nY, double nZ) { this->x = nX; this->y = nY; this->z = nZ; };
double magnitude();
Tuple normalise();
double dot(const Tuple &b);
@@ -48,12 +55,14 @@ public:
class Point: public Tuple
{
public:
Point() : Tuple(0, 0, 0, 1.0) {};
Point(double x, double y, double z) : Tuple(x, y, z, 1.0) {};
};
class Vector: public Tuple
{
public:
Vector() : Tuple(0, 0, 0, 0.0) {};
Vector(double x, double y, double z) : Tuple(x, y, z, 0.0) {};
};

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 */

View File

@@ -14,6 +14,13 @@
#include <shape.h>
#include <intersect.h>
#include <ray.h>
#include <stdio.h>
#ifdef ENABLE_LUA_SUPPORT
extern "C" {
#include <lua.h>
}
#endif
class World
{
@@ -28,6 +35,10 @@ private:
Light* *lightList;
Shape* *objectList;
#ifdef ENABLE_LUA_SUPPORT
lua_State *L;
#endif
public:
World();
~World();
@@ -40,13 +51,18 @@ public:
bool objectIsIn(Shape &s);
Shape *getObject(int i) { return this->objectList[i]; };
Light *getLight(int i) { return this->lightList[i]; };
Tuple shadeHit(Computation comps);;
Tuple colourAt(Ray r);
bool isShadowed(Tuple point);
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);
Intersect intersect(Ray r);
void dumpMe(FILE *fp);
};
#endif /* DORAYME_WORLD_H */

View File

@@ -10,6 +10,7 @@
#define DORAYME_WORLDBUILDER_H
#include <world.h>
#include <camera.h>
/* Let's keep a single header for now, will see later */
@@ -22,7 +23,30 @@ public:
/* 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);
};

View File

@@ -11,19 +11,41 @@
#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);
stats.addMalloc();
stats.addIntersect();
this->num = 0;
}
Intersect::~Intersect()
{
int i;
for(i = 0; i < this->num; i++)
{
delete this->list[i];
}
/* Free stuff */
if (this->list != nullptr)
{
free(this->list);
}
}
void Intersect::reset()
{
this->num = 0;
}
void Intersect::add(Intersection i)
@@ -34,9 +56,13 @@ void Intersect::add(Intersection i)
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);
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++)

View File

@@ -8,11 +8,26 @@
*/
#include <intersection.h>
#include <shape.h>
#include <list.h>
Computation Intersection::prepareComputation(Ray r)
Computation Intersection::prepareComputation(Ray r, Intersect *xs)
{
double n1 = 1.0;
double n2 = 1.0;
Tuple hitP = r.position(this->t);
Tuple normalV = this->object->normalAt(hitP);
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;
@@ -23,6 +38,52 @@ Computation Intersection::prepareComputation(Ray r)
}
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->material.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()->material.refractiveIndex;
}
}
if (containers.doesInclude(i.object))
{
containers.remove(i.object);
}
else
{
containers.append(i.object);
}
if (*this == i)
{
if (!containers.isEmpty())
{
n2 = containers.last()->material.refractiveIndex;
}
/* End the loop */
break;
}
}
}
Shape *s = this->object;
/* For now don't get root group material */
while((!s->materialSet) && (s->parent != nullptr)) { s = s->parent; }
return Computation(this->object,
this->t,
@@ -30,5 +91,10 @@ Computation Intersection::prepareComputation(Ray r)
eyeV,
normalV,
overHitP,
inside);
inside,
reflectV,
n1,
n2,
underHitP,
&s->material);
}

View File

@@ -8,10 +8,45 @@
*
*/
#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[])
{
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;
}
}
#endif

View File

@@ -7,6 +7,7 @@
*
*/
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <math_helper.h>
@@ -25,10 +26,46 @@ double getEpsilon()
bool double_equal(double a, double b)
{
if (isinf(a) && isinf(b))
return true;
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);
}

View File

@@ -101,6 +101,7 @@ Matrix Matrix::operator*(const Matrix &b) const
return ret;
}
/* TODO: Check if we can optimise this function. It is called a lot */
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),
@@ -123,6 +124,7 @@ Matrix Matrix::transpose()
{
int x, y;
Matrix ret = Matrix(this->size);
for (y = 0 ; y < this->size ; y++)
{
for (x = 0 ; x < this->size ; x++)
@@ -138,6 +140,7 @@ Matrix Matrix::submatrix(int row, int column)
int i, j;
int x = 0, y = 0;
Matrix ret = Matrix(this->size - 1);
for (i = 0 ; i < this->size ; i++)
{
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 */

189
source/renderstat.cpp Normal file
View File

@@ -0,0 +1,189 @@
/*
* 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::addLightRay()
{
#pragma omp atomic
this->lightRayEmitedCount++;
};
void RenderStats::addReflectRay()
{
#pragma omp atomic
this->reflectionRayCount++;
};
void RenderStats::addRefractRay()
{
#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 casted : %lld\n", this->rayCount);
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 atteined : %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];
}
}

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

@@ -0,0 +1,150 @@
/*
* 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));
}
}
}
Intersect Cone::localIntersect(Ray r)
{
Intersect ret;
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);
ret.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))
{
ret.add(Intersection(t0, this));
}
double y1 = r.origin.y + t1 * r.direction.y;
if ((this->minCap < y1) && (y1 < this->maxCap))
{
ret.add(Intersection(t1, this));
}
}
}
this->intersectCaps(r, ret);
return ret;
}
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);
}

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

@@ -0,0 +1,138 @@
/*
* 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->parent = this;
this->right->parent = this;
this->bounds | this->left->getBounds();
this->bounds | this->right->getBounds();
}
Intersect CSG::localIntersect(Ray r)
{
int i;
Intersect leftxs = this->left->intersect(r);
Intersect rightxs = this->right->intersect(r);
for(i = 0; i < rightxs.count(); i++)
{
leftxs.add(rightxs[i]);
}
Intersect ret = this->filterIntersections(leftxs);
return ret;
}
Intersect CSG::intersect(Ray r)
{
return localIntersect(r);
}
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;
}
Intersect CSG::filterIntersections(Intersect &xs)
{
bool inl = false;
bool inr = false;
Intersect ret = Intersect();
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;
}
}
return ret;
}
void CSG::dumpMe(FILE *fp)
{
}

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

@@ -0,0 +1,88 @@
/*
* 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;
}
}
Intersect Cube::localIntersect(Ray r)
{
Intersect ret;
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)
{
ret.add(Intersection(tMin, this));
ret.add(Intersection(tMax, this));
}
return ret;
}
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);
}

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

@@ -0,0 +1,132 @@
/*
* 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 mattter is 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));
}
}
}
Intersect Cylinder::localIntersect(Ray r)
{
Intersect ret;
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))
{
ret.add(Intersection(t0, this));
}
double y1 = r.origin.y + t1 * r.direction.y;
if ((this->minCap < y1) && (y1 < this->maxCap))
{
ret.add(Intersection(t1, this));
}
}
}
this->intersectCaps(r, ret);
return ret;
}
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);
}

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

@@ -0,0 +1,231 @@
/*
* 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>
#define MIN_ALLOC (2)
Group::Group() : 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;
}
Intersect Group::intersect(Ray r)
{
Intersect ret;
int i, j;
if (this->objectCount > 0)
{
if (this->bounds.intesectMe(r))
{
for (i = 0 ; i < this->objectCount ; i++)
{
Intersect xs = this->objectList[i]->intersect(r);
if (xs.count() > 0)
{
for (j = 0 ; j < xs.count() ; j++)
{
ret.add(xs[j]);
}
}
}
}
}
/* We are force to do them all the time */
if (this->unboxableObjectCount > 0)
{
for(i = 0; i < this->unboxableObjectCount; i++)
{
Intersect xs = this->unboxableObjectList[i]->intersect(r);
if (xs.count() > 0)
{
for(j = 0; j < xs.count(); j++)
{
ret.add(xs[j]);
}
}
}
}
return ret;
}
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;
}
}
}
/* We are force to do them all the time */
if (this->unboxableObjectCount > 0)
{
int i;
for(i = 0; i < this->unboxableObjectCount; i++)
{
if (this->unboxableObjectList[i] == b)
{
return true;
}
}
}
return false;
}
Intersect Group::localIntersect(Ray r)
{
return Intersect();
}
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->parent = 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->parent = this;
s->updateTransform();
this->unboxableObjectList[this->unboxableObjectCount++] = s;
}
}
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");
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);
}

View File

@@ -6,3 +6,51 @@
* Copyright (c) 2020 986-Studio.
*
*/
#include <stdio.h>
#include <light.h>
#include <world.h>
void Light::dumpMe(FILE *fp)
{
fprintf(fp, "\"Colour\": {\"red\": %f, \"green\": %f, \"blue\": %f},\n",
this->intensity.x, this->intensity.y, this->intensity.z);
fprintf(fp, "\"Position\": {\"x\": %f, \"y\": %f, \"z\":%f},\n",
this->position.x, this->position.y, this->position.z);
fprintf(fp, "\"Type\": \"PointLight\",\n");
}
double Light::intensityAt(World &w, Tuple point)
{
switch(this->type)
{
case POINT_LIGHT:
default:
return (w.isShadowed(point, this->position))?0.0:1.0;
case AREA_LIGHT:
double total = 0.0;
uint32_t v, u;
for(v = 0; v < this->vSteps; v++)
{
for(u = 0; u < this->uSteps; u++)
{
if (!w.isShadowed(point, this->pointOnLight(u, v)))
{
total = total + 1.0;
}
}
}
return total / this->samples;
}
}
Tuple Light::pointOnLight(uint32_t u, uint32_t v)
{
if (this->jitter)
{
return this->corner +
this->uVec * (u + this->jitterBy.next()) +
this->vVec * (v + this->jitterBy.next());
}
return this->corner + this->uVec * (u + 0.5) + this->vVec * (v + 0.5);
}

View File

@@ -9,14 +9,24 @@
#include <tuple.h>
#include <material.h>
#include <colour.h>
#include <shape.h>
Colour Material::lighting(Light light, Tuple point, Tuple eyeVector, Tuple normalVector, bool inShadow)
Colour Material::lighting(Light light, Tuple point, Tuple eyeVector, Tuple normalVector, Shape *hitObject,
double lightIntensity)
{
Colour pointColor = this->colour;
if (this->pattern != nullptr)
{
pointColor = this->pattern->patternAtObject(hitObject, point);
}
Tuple lightVector = (light.position - point).normalise();
Tuple reflectVector = Tuple(0, 0, 0, 0);
Tuple effectiveColour = this->colour * light.intensity;
Tuple effectiveColour = pointColor * light.intensity;
Tuple ambientColour = Colour(0, 0, 0);
Tuple emissiveColour = Colour(0, 0, 0);
Tuple diffuseColour = Colour(0, 0, 0);
Tuple specularColour = Colour(0, 0, 0);
Tuple finalColour = Colour(0, 0, 0);
@@ -25,34 +35,56 @@ Colour Material::lighting(Light light, Tuple point, Tuple eyeVector, Tuple norma
ambientColour = effectiveColour * this->ambient;
if (!inShadow)
{
lightDotNormal = lightVector.dot(normalVector);
emissiveColour = pointColor * this->emissive;
if (lightDotNormal < 0)
lightDotNormal = lightVector.dot(normalVector);
if (lightDotNormal < 0)
{
diffuseColour = Colour(0, 0, 0);
specularColour = Colour(0, 0, 0);
}
else
{
diffuseColour = effectiveColour * this->diffuse * lightDotNormal;
reflectVector = -lightVector.reflect(normalVector);
reflectDotEye = reflectVector.dot(eyeVector);
if (reflectDotEye < 0)
{
diffuseColour = Colour(0, 0, 0);
specularColour = Colour(0, 0, 0);
}
else
{
diffuseColour = effectiveColour * this->diffuse * lightDotNormal;
reflectVector = -lightVector.reflect(normalVector);
reflectDotEye = reflectVector.dot(eyeVector);
if (reflectDotEye < 0)
{
specularColour = Colour(0, 0, 0);
}
else
{
double factor = pow(reflectDotEye, this->shininess);
specularColour = light.intensity * this->specular * factor;
}
double factor = pow(reflectDotEye, this->shininess);
specularColour = light.intensity * this->specular * factor;
}
}
finalColour = ambientColour + diffuseColour + specularColour;
diffuseColour = diffuseColour * lightIntensity;
specularColour = specularColour * lightIntensity;
finalColour = emissiveColour + ambientColour + diffuseColour + specularColour;
return Colour(finalColour.x, finalColour.y, finalColour.z);
}
void Material::dumpMe(FILE *fp)
{
fprintf(fp, "\"Colour\": {\"red\": %f, \"green\": %f, \"blue\": %f},\n", this->colour.x, this->colour.y, this->colour.z);
fprintf(fp, "\"Ambient\": %f,\n", this->ambient);
fprintf(fp, "\"Diffuse\": %f,\n", this->diffuse);
fprintf(fp, "\"Specular\": %f,\n", this->specular);
fprintf(fp, "\"Shininess\": %f,\n", this->shininess);
fprintf(fp, "\"Reflective\": %f,\n", this->reflective);
fprintf(fp, "\"Transparency\": %f,\n", this->transparency);
fprintf(fp, "\"Emissive\": %f,\n", this->emissive);
fprintf(fp, "\"RefractiveIndex\": %f,\n", this->refractiveIndex);
if (this->pattern)
{
fprintf(fp, "\"Pattern\": {\n");
this->pattern->dumpMe(fp);
fprintf(fp, "},\n");
}
}

440
source/shapes/objfile.cpp Normal file
View File

@@ -0,0 +1,440 @@
/*
* DoRayMe - a quick and dirty Raytracer
* OBJ File implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tuple.h>
#include <ray.h>
#include <shape.h>
#include <objfile.h>
#include <math_helper.h>
#include <group.h>
#include <triangle.h>
#include <smoothtriangle.h>
#define MIN_ALLOC (2)
#define DEFAULT_GROUP (0)
OBJFile::OBJFile() : Shape(SHAPE_OBJFILE), ignoredLines(0)
{
stats.addOBJFile();
this->allocatedFaceGroupCount = MIN_ALLOC;
this->faceGroupList = (Group **)calloc(sizeof(Group **), MIN_ALLOC);
this->faceGroupCount = 0;
this->allocatedVertexCount = MIN_ALLOC;
this->vertexList = (Point **)calloc(sizeof(Point **), MIN_ALLOC);
this->vertexCount = 0;
this->allocatedVertexNormalCount = MIN_ALLOC;
this->vertexNormalList = (Vector **)calloc(sizeof(Vector **), MIN_ALLOC);
this->vertexNormalCount = 0;
/* There is always a default group */
this->addGroup(new Group());
};
OBJFile::OBJFile(const char *filepath) : OBJFile()
{
FILE *fp;
size_t fileSize;
char *fileBuff;
fp = fopen(filepath, "rt");
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);
this->parseOBJFile(fileBuff);
free(fileBuff);
}
else
{
printf("ERROR: Can't open/find the file '%s'.\n", filepath);
}
}
void OBJFile::addGroup(Group *group)
{
if ((this->faceGroupCount + 1) > this->allocatedFaceGroupCount)
{
this->allocatedFaceGroupCount *= 2;
this->faceGroupList = (Group **)realloc(this->faceGroupList, sizeof(Group **) * this->allocatedFaceGroupCount);
}
group->parent = this;
group->updateTransform();
this->faceGroupList[this->faceGroupCount++] = group;
this->bounds | group->getBounds();
}
void OBJFile::addVertex(Point *vertex)
{
if ((this->vertexCount + 1) > this->allocatedVertexCount)
{
this->allocatedVertexCount *= 2;
this->vertexList = (Point **)realloc(this->vertexList, sizeof(Point **) * this->allocatedVertexCount);
}
this->vertexList[this->vertexCount++] = vertex;
}
void OBJFile::addVertexNormal(Vector *vertexNormal)
{
if ((this->vertexNormalCount + 1) > this->allocatedVertexNormalCount)
{
this->allocatedVertexNormalCount *= 2;
this->vertexNormalList = (Vector **)realloc(this->vertexNormalList, sizeof(Vector **) * this->allocatedVertexNormalCount);
}
this->vertexNormalList[this->vertexNormalCount++] = vertexNormal;
}
Intersect OBJFile::intersect(Ray r)
{
Intersect ret;
int i, j;
if (this->faceGroupCount > 0)
{
if (this->bounds.intesectMe(r))
{
for (i = 0 ; i < this->faceGroupCount ; i++)
{
Intersect xs = this->faceGroupList[i]->intersect(r);
if (xs.count() > 0)
{
for (j = 0 ; j < xs.count() ; j++)
{
ret.add(xs[j]);
}
}
}
}
}
return ret;
}
bool OBJFile::includes(Shape *b)
{
int i;
if (this->faceGroupCount > 0)
{
for (i = 0 ; i < this->faceGroupCount ; i++)
{
if (this->faceGroupList[i] == b)
{
return true;
}
}
}
return false;
}
Intersect OBJFile::localIntersect(Ray r)
{
return Intersect();
}
Tuple OBJFile::localNormalAt(Tuple point, Intersection *hit)
{
return Vector(0, 1, 0);
}
BoundingBox OBJFile::getLocalBounds()
{
return this->bounds;
}
BoundingBox OBJFile::getBounds()
{
if (this->bounds.isEmpty()) { this->updateBoundingBox(); }
return this->bounds;
}
void OBJFile::updateBoundingBox()
{
int i;
this->bounds.reset();
for(i = 0; i < this->faceGroupCount; i++)
{
if (this->faceGroupList[i]->haveFiniteBounds())
{
BoundingBox objB = this->faceGroupList[i]->getBounds();
this->bounds | objB;
}
}
}
void OBJFile::updateTransform()
{
int i;
Shape::updateTransform();
for (i = 0 ; i < this->faceGroupCount ; i++)
{
this->faceGroupList[i]->updateTransform();
}
/* Once the full stack being notified of the changes, let's update the
* bounding box
*/
this->updateBoundingBox();
}
void OBJFile::dumpMe(FILE * fp)
{
int i;
fprintf(fp, "\"Type\": \"OBJFile\",\n");
fprintf(fp, "\"Objects\": {\n");
for(i = 0; i < this->faceGroupCount; i++)
{
fprintf(fp, "\"%d\": {\n", i);
this->faceGroupList[i]->dumpMe(fp);
fprintf(fp, "},\n");
}
fprintf(fp, "},\n");
Shape::dumpMe(fp);
}
#define MAX_LINE_LENGTH (512)
/* Here start the fun! */
int OBJFile::parseOBJFile(const char *content)
{
/* I don't think we will handle lines of more than 512 characters... */
char lineBuff[MAX_LINE_LENGTH];
uint32_t currentLineNum = 1;
/* Need to process line by line */
const char *bufferPos = content;
const char *lineNewline;
while(*bufferPos != '\0')
{
uint32_t lineLength;
lineNewline = strchr(bufferPos, '\n');
if (lineNewline == nullptr)
{
/* We are on the last line */
lineLength = strlen(bufferPos);
}
else
{
lineLength = (lineNewline - bufferPos);
}
if (lineLength >= MAX_LINE_LENGTH)
{
printf("ERROR: Line %d is too long! (%d)\n", currentLineNum, lineLength);
return -1;
}
memset(lineBuff, 0, MAX_LINE_LENGTH);
strncpy(lineBuff, bufferPos, lineLength);
this->parseLine(lineBuff, currentLineNum);
bufferPos += lineLength + 1;
currentLineNum++;
}
return 0;
}
#define MAX_ARGS (15)
/* Parse the line into a couple ofr argc/argv using space as argument separator */
void OBJFile::parseLine(char *line, uint32_t currentLine)
{
char *argv[MAX_ARGS];
uint32_t argc = 0;
char *buffer = line;
uint32_t lineLength = strlen(line);
uint32_t linePos = 0;
/* First argument */
argv[argc++] = line;
while(linePos < lineLength)
{
char *next = strchr(buffer, ' ');
if (next != nullptr)
{
*next = '\0';
linePos = next - line;
buffer = next + 1;
/* Skip empty strings as it mean multiple spaces */
if (strlen(buffer) > 0)
{
argv[argc++] = buffer;
}
}
else
{
linePos = lineLength;
}
}
if (this->execLine(argc, argv, currentLine))
{
this->ignoredLines++;
}
}
static int parseFaceVertex(char *buf, uint32_t &v, uint32_t &vt, uint32_t &vn)
{
uint32_t bufPos = 0;
uint32_t lineLength = strlen(buf);
vt = INT32_MAX;
vn = INT32_MAX;
int ret = 0;
int token = 0;
while(bufPos < lineLength)
{
char *next = strchr(buf, '/');
if (next != nullptr)
{
*next = '\0';
bufPos = next - buf;
}
else
{
bufPos = lineLength;
}
if (strlen(buf) > 0)
{
switch(token)
{
case 0: v = atol(buf); break;
case 1: vt = atol(buf); break;
case 2: vn = atol(buf); break;
default: printf("ERROR: Too many entry for a face vertice!"); ret = 1;
}
}
buf = next + 1;
token++;
}
return ret;
}
/* Actually execute the line */
int OBJFile::execLine(int argc, char *argv[], uint32_t currentLine)
{
int ret = 1;
if (strncmp(argv[0], "v", 2) == 0)
{
/* Vertice entry */
if (argc != 4)
{
printf("ERROR: Malformed file at line %d: Vertices expect 3 parameters!\n", currentLine);
}
else
{
this->addVertex(new Point(atof(argv[1]), atof(argv[2]), atof(argv[3])));
ret = 0;
}
}
else if (strncmp(argv[0], "vn", 3) == 0)
{
/* Vertice Normal entry */
if (argc != 4)
{
printf("ERROR: Malformed file at line %d: Vertices normal expect 3 parameters!\n", currentLine);
}
else
{
this->addVertexNormal(new Vector(atof(argv[1]), atof(argv[2]), atof(argv[3])));
ret = 0;
}
}
else if (strncmp(argv[0], "f", 2) == 0)
{
/* Faces entry */
int i;
uint32_t v[MAX_ARGS], vt[MAX_ARGS], vn[MAX_ARGS];
for(i = 1; i < argc; i++)
{
parseFaceVertex(argv[i], v[i], vt[i], vn[i]);
}
if (argc == 4)
{
Shape *t;
if (vn[1] == INT32_MAX)
{
t = new Triangle(this->vertices(v[1]),
this->vertices(v[2]),
this->vertices(v[3]));
}
else
{
t = new SmoothTriangle(this->vertices(v[1]),
this->vertices(v[2]),
this->vertices(v[3]),
this->verticesNormal(vn[1]),
this->verticesNormal(vn[2]),
this->verticesNormal(vn[3]));
}
this->faceGroupList[this->faceGroupCount - 1]->addObject(t);
ret = 0;
}
else if (argc > 4)
{
for(i = 2; i < (argc - 1); i++)
{
Shape *t;
if (vn[1] == INT32_MAX)
{
t = new Triangle(this->vertices(v[1]),
this->vertices(v[i]),
this->vertices(v[i + 1]));
}
else
{
t = new SmoothTriangle(this->vertices(v[1]),
this->vertices(v[i]),
this->vertices(v[i + 1]),
this->verticesNormal(vn[1]),
this->verticesNormal(vn[i]),
this->verticesNormal(vn[i + 1]));
}
this->faceGroupList[this->faceGroupCount - 1]->addObject(t);
}
ret = 0;
}
else
{
printf("ERROR: Malformed file at line %d: Too few/many parameters!\n", currentLine);
}
}
else if (strncmp(argv[0], "g", 2) == 0)
{
if (argc == 2)
{
this->addGroup(new Group());
}
else
{
printf("ERROR: Malformed file at line %d: Too few/many parameters!\n", currentLine);
}
}
return ret;
}

46
source/shapes/plane.cpp Normal file
View File

@@ -0,0 +1,46 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Plane implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <tuple.h>
#include <ray.h>
#include <shape.h>
#include <plane.h>
#include <math_helper.h>
Intersect Plane::localIntersect(Ray r)
{
double t;
Intersect ret = Intersect();
if (fabs(r.direction.y) < getEpsilon())
{
/* With a direction == 0, the ray can't intersect the plane */
return ret;
}
t = -r.origin.y / r.direction.y;
ret.add(Intersection(t, this));
return ret;
}
Tuple Plane::localNormalAt(Tuple point, Intersection *hit)
{
return Vector(0, 1, 0);
}
BoundingBox Plane::getLocalBounds()
{
BoundingBox ret;
ret | Point(-INFINITY, 0-getEpsilon(), -INFINITY);
ret | Point(INFINITY, 0+getEpsilon(), INFINITY);
return ret;
}

View File

@@ -15,23 +15,87 @@
Shape::Shape(ShapeType type)
{
this->parent = nullptr;
this->dropShadow = true;
this->type = type;
this->transformMatrix = Matrix4().identity();
this->inverseTransform = this->transformMatrix.inverse();
this->localTransformMatrix = Matrix4().identity();
this->updateTransform();
this->materialSet = false;
}
Intersect Shape::intersect(Ray r)
{
return Intersect();
return this->localIntersect(this->invTransform(r));
};
Tuple Shape::normalAt(Tuple point)
Tuple Shape::normalToWorld(Tuple normalVector)
{
return Vector(0, 0, 0);
Tuple world_normal = this->transposedInverseTransform * normalVector;
/* W may get wrong, so hack it. This is perfectly normal as we are using a 4x4 matrix instead of a 3x3 */
world_normal.w = 0;
return world_normal.normalise();
};
Tuple Shape::normalAt(Tuple point, Intersection *hit)
{
Tuple local_point = this->worldToObject(point);
Tuple local_normal = this->localNormalAt(local_point, hit);
Tuple world_normal = this->normalToWorld(local_normal);
return world_normal;
}
void Shape::updateTransform()
{
this->transformMatrix = this->localTransformMatrix;
if (this->parent != nullptr)
{
this->transformMatrix = this->parent->transformMatrix * this->transformMatrix;
}
this->inverseTransform = this->transformMatrix.inverse();
this->transposedInverseTransform = this->inverseTransform.transpose();
}
void Shape::setTransform(Matrix transform)
{
this->transformMatrix = transform;
this->inverseTransform = transform.inverse();
this->localTransformMatrix = transform;
this->updateTransform();
}
BoundingBox Shape::getLocalBounds()
{
return BoundingBox(Point(-1, -1, -1), Point(1,1,1));
}
BoundingBox Shape::getBounds()
{
BoundingBox ret;
BoundingBox me = this->getLocalBounds();
ret | this->objectToWorld(Point(me.min.x, me.min.y, me.min.z));
ret | this->objectToWorld(Point(me.min.x, me.min.y, me.max.z));
ret | this->objectToWorld(Point(me.min.x, me.max.y, me.min.z));
ret | this->objectToWorld(Point(me.max.x, me.min.y, me.min.z));
ret | this->objectToWorld(Point(me.max.x, me.max.y, me.min.z));
ret | this->objectToWorld(Point(me.max.x, me.min.y, me.max.z));
ret | this->objectToWorld(Point(me.min.x, me.max.y, me.max.z));
ret | this->objectToWorld(Point(me.max.x, me.max.y, me.max.z));
return ret;
}
void Shape::dumpMe(FILE *fp)
{
fprintf(fp, "\"Material\": {\n");
this->material.dumpMe(fp);
fprintf(fp, "},\n");
fprintf(fp, "\"DropShadow\": %d,\n", this->dropShadow);
fprintf(fp, "\"BoundingBox\": {\n");
this->getBounds().dumpMe(fp);
fprintf(fp, "},\n");
}

View File

@@ -0,0 +1,28 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Smooth Triangle implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <ray.h>
#include <shape.h>
#include <triangle.h>
#include <smoothtriangle.h>
#include <math_helper.h>
#include <renderstat.h>
SmoothTriangle::SmoothTriangle(Point p1, Point p2, Point p3, Vector n1, Vector n2, Vector n3) : Triangle(p1, p2, p3),
n1(n1), n2(n2), n3(n3)
{
this->type = SHAPE_SMOOTHTRIANGLE;
stats.addSmoothTriangle();
}
Tuple SmoothTriangle::localNormalAt(Tuple point, Intersection *hit)
{
return (this->n2 * hit->u +
this->n3 * hit->v +
this->n1 * (1 - hit->u - hit->v)).normalise();
}

View File

@@ -13,17 +13,15 @@
#include <tuple.h>
#include <intersect.h>
Intersect Sphere::intersect(Ray r)
Intersect Sphere::localIntersect(Ray r)
{
Intersect ret;
double a, b, c, discriminant;
Ray transRay = this->invTransform(r);
Tuple sphere_to_ray = r.origin - Point(0, 0, 0);
Tuple sphere_to_ray = transRay.origin - Point(0, 0, 0);
a = transRay.direction.dot(transRay.direction);
b = 2 * transRay.direction.dot(sphere_to_ray);
a = r.direction.dot(r.direction);
b = 2 * r.direction.dot(sphere_to_ray);
c = sphere_to_ray.dot(sphere_to_ray) - 1;
discriminant = b * b - 4 * a * c;
@@ -37,14 +35,19 @@ Intersect Sphere::intersect(Ray r)
return ret;
}
Tuple Sphere::normalAt(Tuple point)
Tuple Sphere::localNormalAt(Tuple point, Intersection *hit)
{
Tuple object_point = this->inverseTransform * point;
Tuple object_normal = (object_point - Point(0, 0, 0)).normalise();
Tuple world_normal = this->inverseTransform.transpose() * object_normal;
return (point - Point(0, 0, 0)).normalise();
}
/* W may get wrong, so hack it. This is perfectly normal as we are using a 4x4 matrix instead of a 3x3 */
world_normal.w = 0;
return world_normal.normalise();
void Sphere::dumpMe(FILE *fp)
{
fprintf(fp, "\"Type\": \"Sphere\",\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, "\"radius\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
Shape::dumpMe(fp);
}

View File

@@ -0,0 +1,25 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Test shape implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <shape.h>
#include <testshape.h>
TestShape::TestShape() : localRay(Point(0, 0, 0), Vector(0, 0, 0))
{
}
Intersect TestShape::localIntersect(Ray r)
{
this->localRay = r;
return Intersect();
}
Tuple TestShape::localNormalAt(Tuple point, Intersection *hit)
{
return Vector(point.x, point.y, point.z);
}

View File

@@ -0,0 +1,86 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Triangle implementation
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <ray.h>
#include <shape.h>
#include <triangle.h>
#include <math_helper.h>
#include <renderstat.h>
Triangle::Triangle(Point p1, Point p2, Point p3) : Shape(SHAPE_TRIANGLE), p1(p1), p2(p2), p3(p3)
{
stats.addTriangle();
this->e1 = p2 - p1;
this->e2 = p3 - p1;
this->normal = e2.cross(e1).normalise();
}
Intersect Triangle::localIntersect(Ray r)
{
Intersect ret;
Tuple dirCrossE2 = r.direction.cross(this->e2);
double determinant = this->e1.dot(dirCrossE2);
if (fabs(determinant) < getEpsilon())
{
return ret;
}
double f = 1.0 / determinant;
Tuple p1ToOrigin = r.origin - this->p1;
Tuple originCrossE1 = p1ToOrigin.cross(this->e1);
double u = f * p1ToOrigin.dot(dirCrossE2);
double v = f * r.direction.dot(originCrossE1);
if ((u < 0) || (u > 1))
{
return ret;
}
if ((v < 0) || ((u + v) > 1))
{
return ret;
}
double t = f * this->e2.dot(originCrossE1);
ret.add(Intersection(t, this, u, v));
return ret;
}
Tuple Triangle::localNormalAt(Tuple point, Intersection *hit)
{
return this->normal;
}
BoundingBox Triangle::getLocalBounds()
{
BoundingBox ret;
ret | p1;
ret | p2;
ret | p3;
return ret;
}
void Triangle::dumpMe(FILE *fp)
{
fprintf(fp, "\"Type\": \"Triangle\",\n");
Tuple t = this->transformMatrix * this->p1;
fprintf(fp, "\"p1\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
t = this->transformMatrix * this->p2;
fprintf(fp, "\"p2\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
t = this->transformMatrix * this->p3;
fprintf(fp, "\"p3\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
t.x, t.y, t.z);
Shape::dumpMe(fp);
}

View File

@@ -19,6 +19,11 @@ double Tuple::magnitude()
Tuple Tuple::normalise()
{
double mag = this->magnitude();
if (mag == 0)
{
return Tuple(0, 0, 0, 0);
}
return Tuple(this->x / mag, this->y / mag, this->z / mag, this->w / mag);
}
@@ -38,4 +43,28 @@ Tuple Tuple::cross(const Tuple &b) const
Tuple Tuple::reflect(const Tuple &normal)
{
return *this - normal * 2 * this->dot(normal);
}
void Tuple::fixPoint()
{
if (isnan(this->x) || isnan(this->y) || isnan(this->z))
{
/* w is probably broken, so fix it */
this->w = 1;
}
}
void Tuple::fixVector()
{
if (isnan(this->x) || isnan(this->y) || isnan(this->z))
{
/* w is probably broken, so fix it */
this->w = 0;
}
}
bool Tuple::isRepresentable()
{
return !(isnan(this->x) || isnan(this->y) || isnan(this->z) ||
isinf(this->x) || isinf(this->y) || isinf(this->z));
}

View File

@@ -0,0 +1,39 @@
/*
* DoRayMe - a quick and dirty Raytracer
* UV Align Check test pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_UV_ALIGNCHECK_H
#define DORAYME_UV_ALIGNCHECK_H
class UVAlignCheck : public UVPattern
{
public:
Colour ul, ur, bl, br;
UVAlignCheck(Colour main, Colour ul, Colour ur, Colour bl, Colour br) : UVPattern(1, 1, main, main),
ul(ul), ur(ur), bl(bl), br(br) {};
Colour uvPatternAt(double u, double v) {
/* Remember that v=0 is at the bottom, v=1 at the top */
if (v > 0.8)
{
if (u < 0.2) { return this->ul; }
if (u > 0.8) { return this->ur; }
}
else if (v < 0.2)
{
if (u < 0.2) { return this->bl; }
if (u > 0.8) { return this->br; }
}
/* main is stored in A or B */
return this->a;
};
};
#endif /* DORAYME_UV_ALIGNCHECK_H */

View File

@@ -0,0 +1,32 @@
/*
* DoRayMe - a quick and dirty Raytracer
* UV Checkers header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_UV_CHECKERS_H
#define DORAYME_UV_CHECKERS_H
#include <uv_pattern.h>
#include <math.h>
class UVCheckers : public UVPattern
{
public:
UVCheckers(double width, double height, Colour a, Colour b) : UVPattern(width, height, a, b) {};
Colour uvPatternAt(double u, double v) {
double u2 = floor(u * this->width);
double v2 = floor(v * this->height);
if (modulo((u2 + v2), 2) == 0)
{
return this->a;
}
return this->b;
};
};
#endif /* DORAYME_UV_CHECKERS_H */

View File

@@ -0,0 +1,43 @@
/*
* DoRayMe - a quick and dirty Raytracer
* UV Image pattern header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_UV_IMAGE_H
#define DORAYME_UV_IMAGE_H
#include <stdint.h>
#include <uv_pattern.h>
#include <canvas.h>
#include <tuple.h>
class UVImage : public UVPattern
{
public:
Canvas *image;
UVImage(Canvas *image) : UVPattern(1, 1, Colour(0, 0, 0), Colour(0, 0, 0)),
image(image) {};
UVImage(const char *filepath) : UVPattern(1, 1, Colour(0, 0, 0), Colour(0, 0, 0)) {
this->image = new Canvas(filepath);
this->width = this->image->width;
this->height = this->image->height;
};
Colour uvPatternAt(double u, double v) {
v = 1 - v;
double x = u * (this->image->width - 1);
double y = v * (this->image->height - 1);
Colour ret = this->image->getPixel(round(x), round(y));
return ret;
};
};
#endif /* DORAYME_UV_IMAGE_H */

View File

@@ -9,6 +9,16 @@
#include <world.h>
#include <light.h>
#include <shape.h>
#include <stdio.h>
#include <string.h>
#ifdef ENABLE_LUA_SUPPORT
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#endif
#define MIN_ALLOC (2)
@@ -21,6 +31,11 @@ World::World() : objectCount(0), lightCount(0)
this->allocatedObjectCount = MIN_ALLOC;
this->objectList = (Shape **)calloc(sizeof(Shape *), MIN_ALLOC);
this->objectCount = 0;
#ifdef ENABLE_LUA_SUPPORT
this->L = luaL_newstate(); /* opens Lua */
luaL_openlibs(L); /* opens the basic library */
#endif
};
World::~World()
@@ -92,19 +107,38 @@ Intersect World::intersect(Ray r)
return ret;
}
Tuple World::shadeHit(Computation comps)
Tuple World::shadeHit(Computation comps, uint32_t depthCount)
{
/* TODO: Add support for more than one light */
uint32_t lightIndex;
Tuple surface = Colour(0, 0, 0);
bool isThereAnObstacle = this->isShadowed(comps.overHitPoint);
for(lightIndex = 0; lightIndex < this->lightCount; lightIndex++)
{
double lightLevel = this->lightList[lightIndex]->intensityAt(*this, comps.overHitPoint);
return comps.object->material.lighting(*this->lightList[0], comps.overHitPoint, comps.eyeVector,
comps.normalVector, isThereAnObstacle);
surface = surface + comps.material->lighting(*this->lightList[lightIndex], comps.overHitPoint, comps.eyeVector,
comps.normalVector, comps.object, lightLevel);
}
Tuple reflected = this->reflectColour(comps, depthCount);
Tuple refracted = this->refractedColour(comps, depthCount);
if ((comps.material->reflective > 0) && (comps.material->transparency > 0))
{
double reflectance = comps.schlick();
return surface + reflected * reflectance + refracted * (1 - reflectance);
}
return surface + reflected + refracted;
}
Tuple World::colourAt(Ray r)
Tuple World::colourAt(Ray r, uint32_t depthCount)
{
Intersection hit = this->intersect(r).hit();
Intersect allHits = this->intersect(r);
Intersection hit = allHits.hit();
stats.setMaxDepth(depthCount);
if (hit.nothing())
{
@@ -112,25 +146,98 @@ Tuple World::colourAt(Ray r)
}
else
{
return this->shadeHit(hit.prepareComputation(r));
return this->shadeHit(hit.prepareComputation(r, &allHits), depthCount);
}
}
bool World::isShadowed(Tuple point)
bool World::isShadowed(Tuple point, Tuple lightPosition)
{
/* TODO: Add support for more than one light */
Tuple v = this->lightList[0]->position - point;
Tuple v = lightPosition - point;
double distance = v.magnitude();
Tuple direction = v.normalise();
Ray r = Ray(point, direction);
Intersection h = this->intersect(r).hit();
stats.addLightRay();
Intersect xs = this->intersect(r);
if (!h.nothing() && (h.t < distance))
int i;
for(i = 0; i < xs.count(); i++)
{
return true;
}
Intersection h = xs[i];
if (h.t < 0) continue;
if ((h.object->dropShadow == true) && (h.t < distance))
{
return true;
}
}
return false;
}
Colour World::reflectColour(Computation comps, uint32_t depthCount)
{
if ((depthCount == 0) || (comps.material->reflective == 0))
{
return Colour(0, 0, 0);
}
/* So it is reflective, even just a bit. Let'sr reflect the ray! */
Ray reflectedRay = Ray(comps.overHitPoint, comps.reflectVector);
stats.addReflectRay();
Tuple hitColour = this->colourAt(reflectedRay, depthCount - 1);
hitColour = hitColour * comps.material->reflective;
return Colour(hitColour.x, hitColour.y, hitColour.z);
}
Colour World::refractedColour(Computation comps, uint32_t depthCount)
{
double nRatio = comps.n1 / comps.n2;
double cos_i = comps.eyeVector.dot(comps.normalVector);
double sin2_t = (nRatio*nRatio) * (1 - cos_i * cos_i);
if ((sin2_t > 1 ) || (depthCount == 0) || (comps.material->transparency == 0))
{
return Colour(0, 0, 0);
}
double cos_t = sqrt(1.0 - sin2_t);
Tuple direction = comps.normalVector * (nRatio * cos_i - cos_t) - comps.eyeVector * nRatio;
Ray refractedRay = Ray(comps.underHitPoint, direction);
stats.addRefractRay();
Tuple hitColour = this->colourAt(refractedRay, depthCount - 1) * comps.material->transparency;
return Colour(hitColour.x, hitColour.y, hitColour.z);
}
void World::dumpMe(FILE *fp)
{
int i;
/* JSON Opening */
fprintf(fp, "{\n");
fprintf(fp, "\"Lights\": {\n");
for(i = 0; i < this->lightCount; i++)
{
fprintf(fp, "\"%d\": {\n", i);
this->lightList[i]->dumpMe(fp);
fprintf(fp, "},\n");
}
fprintf(fp, "},\n");
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");
/* JSON Closing */
fprintf(fp, "}\n");
}

View File

@@ -7,18 +7,20 @@
*
*/
/* Don't build for now */
#if 0
/* This file is parsing a text format from another raytracer I made in the past. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <math.h>
#include <worldbuilder.h>
#include <sphere.h>
#include <matrix.h>
#include <transformation.h>
#define IS_CMD(_cmd) (strncmp(buffer, _cmd, sizeof(_cmd)) == 0)
typedef void (*cmdFunc)(scene *sc, uint32_t curLine, char *first, float argv[15]);
typedef void (*cmdFunc)(Hw3File *w, uint32_t curLine, double argv[15]);
typedef struct cmd_def
{
@@ -27,111 +29,127 @@ typedef struct cmd_def
cmdFunc f;
} cmd_def;
void cmdCamera (scene *sc, uint32_t curLine, char *first, float argv[15])
static void cmdCamera (Hw3File *w, uint32_t curLine, double argv[15])
{
sc->cam.seteye(point(argv[0], argv[1], argv[2]));
sc->cam.setat(point(argv[3], argv[4], argv[5]));
sc->cam.setup(vector(argv[6], argv[7], argv[8]));
sc->cam.setfovy(argv[9]);
w->cam = viewTransform(Point(argv[0], argv[1], argv[2]),
Point(argv[3], argv[4], argv[5]),
Vector(argv[6], argv[7], argv[8]));
w->camFoV = deg_to_rad(argv[9]);
}
void cmdSphere (scene *sc, uint32_t curLine, char *first, float argv[15])
/* 0: X, 1: Y, 2: Z
* 3: Radius
*/
static void cmdSphere (Hw3File *w, uint32_t curLine, double argv[15])
{
printf("Adding a sphere...\n");
/* Instanciate a sphere */
sphere *sp = new sphere(point(argv[0], argv[1], argv[2]), argv[3], sc->getMatrix());
sp->ambient = sc->ambient;
sp->diffuse = sc->diffuse;
sp->specular = sc->specular;
sp->emission = sc->emission;
sp->shininess = sc->shininess;
sp->sourceLine = curLine;
sc->o[sc->o_count] = sp;
sc->o_count++;
Sphere *shape = new Sphere();
Matrix pos = translation(argv[0], argv[1], argv[2]) * scaling(argv[3], argv[3], argv[3]);
shape->setTransform(w->getTransformMatrix() * pos);
shape->material.ambient = w->currentAmbient;
shape->material.reflective = w->currentReflective;
shape->material.shininess = w->currentShininess;
shape->material.specular = w->currentSpecular;
shape->material.diffuse = w->currentDiffuse;
shape->material.colour = w->currentColour;
shape->material.transparency = w->currentTransparency;
shape->material.refractiveIndex = w->currentRefIndex;
w->addObject(shape);
}
void cmdCube (scene *sc, uint32_t curLine, char *first, float argv[15])
static void cmdCube (Hw3File *w, uint32_t curLine, double argv[15])
{
}
static void cmdTrans (Hw3File *w, uint32_t curLine, double argv[15])
{
Matrix m = translation(argv[0], argv[1], argv[2]);
w->applyTransformMatrix(m);
}
static void cmdRotate (Hw3File *w, uint32_t curLine, double argv[15])
{
Matrix m = Matrix4().identity();
if (argv[2] != 0)
{
m = m * rotationZ(argv[3]);
}
if (argv[1] != 0)
{
m = m * rotationY(argv[3]);
}
if (argv[0] != 0)
{
m = m * rotationX(argv[3]);
}
w->applyTransformMatrix(m);
}
static void cmdScale (Hw3File *w, uint32_t curLine, double argv[15])
{
Matrix m = scaling(argv[0], argv[1], argv[2]);
w->applyTransformMatrix(m);
}
static void cmdPushT (Hw3File *w, uint32_t curLine, double argv[15])
{
w->pushTransformMatrix();
}
static void cmdPopT (Hw3File *w, uint32_t curLine, double argv[15])
{
w->popTransformMatrix();
}
static void cmdLPoint (Hw3File *w, uint32_t curLine, double argv[15])
{
/* create point light */
Light *l = new Light(POINT_LIGHT, Point(argv[0], argv[1], argv[2]), Colour(argv[3], argv[4], argv[5]));
w->addLight(l);
}
static void cmdAmbient (Hw3File *w, uint32_t curLine, double argv[15])
{
//w->currentAmbient = (argv[0] + argv[1] + argv[2]) / 3;
w->currentColour = Colour(argv[0], argv[1], argv[2]);
}
static void cmdColour (Hw3File *w, uint32_t curLine, double argv[15])
{
w->currentColour = Colour(argv[0], argv[1], argv[2]);
}
static void cmdDiffuse (Hw3File *w, uint32_t curLine, double argv[15])
{
w->currentDiffuse = (argv[0] + argv[1] + argv[2]) / 3;
}
static void cmdSpecular (Hw3File *w, uint32_t curLine, double argv[15])
{
w->currentSpecular = (argv[0] + argv[1] + argv[2]) / 3;
}
static void cmdShine (Hw3File *w, uint32_t curLine, double argv[15])
{
w->currentReflective = argv[0];
}
static void cmdEmission (Hw3File *w, uint32_t curLine, double argv[15])
{
w->currentEmission = (argv[0] + argv[1] + argv[2]) / 3;
}
#if 0
void cmdMaxVerts (scene *sc, uint32_t curLine, char *first, float argv[15])
{
sc->vertexCount = (uint32_t) argv[0];
sc->vertex = new point[sc->vertexCount];
sc->curVertex = 0;
}
void cmdMaxVertN (scene *sc, uint32_t curLine, char *first, float argv[15])
{
/* ignore for now */
}
void cmdVertex (scene *sc, uint32_t curLine, char *first, float argv[15])
{
sc->vertex[sc->curVertex].set(argv[0], argv[1], argv[2]);
sc->curVertex++;
}
void cmdVertexN (scene *sc, uint32_t curLine, char *first, float argv[15])
{
/* ignore for now */
}
void cmdTri (scene *sc, uint32_t curLine, char *first, float argv[15])
{
/* arg are vertex numbers */
triangle *tr = new triangle(sc->vertex[(int)argv[0]], sc->vertex[(int)argv[1]], sc->vertex[(int)argv[2]], sc->getMatrix());
tr->ambient = sc->ambient;
tr->diffuse = sc->diffuse;
tr->specular = sc->specular;
tr->emission = sc->emission;
tr->shininess = sc->shininess;
tr->sourceLine = curLine;
sc->o[sc->o_count] = tr;
sc->o_count++;
}
void cmdTriN (scene *sc, uint32_t curLine, char *first, float argv[15])
{
/* ignore for noz */
}
#endif
void cmdTrans (scene *sc, uint32_t curLine, char *first, float argv[15])
{
matrix m;
m.translation(argv[0], argv[1], argv[2]);
sc->applyTransform(m);
}
void cmdRotate (scene *sc, uint32_t curLine, char *first, float argv[15])
{
matrix m;
vector axis;
axis.set(argv[0], argv[1], argv[2]);
m.rotation(axis, argv[3]);
sc->applyTransform(m);
}
void cmdScale (scene *sc, uint32_t curLine, char *first, float argv[15])
{
matrix m;
m.scale(argv[0], argv[1], argv[2]);
sc->applyTransform(m);
}
void cmdPushT (scene *sc, uint32_t curLine, char *first, float argv[15])
{
sc->pushMatrix();
}
void cmdPopT (scene *sc, uint32_t curLine, char *first, float argv[15])
{
sc->popMatrix();
}
#if 0
void cmdLDire (scene *sc, uint32_t curLine, char *first, float argv[15])
static void cmdLDire (Hw3File *w, uint32_t curLine, double argv[15])
{
/* create directional light */
light *cur = new light();
@@ -145,163 +163,184 @@ void cmdLDire (scene *sc, uint32_t curLine, char *first, float argv[15])
sc->l[sc->l_count] = cur;
sc->l_count++;
}
#endif
void cmdLPoint (scene *sc, uint32_t curLine, char *first, float argv[15])
static void cmdAtten (Hw3File *w, uint32_t curLine, double argv[15])
{
/* create point light */
light *cur = new light();
cur->type = LIGHT_POINT;
cur->attenuation = sc->attenuation;
cur->position.set(argv[0], argv[1], argv[2]);
cur->lightcolor.set(argv[3], argv[4], argv[5]);
sc->l[sc->l_count] = cur;
sc->l_count++;
sc->attenuation = Vector(argv[0], argv[1], argv[2]);
}
#if 0
void cmdAtten (scene *sc, uint32_t curLine, char *first, float argv[15])
static void cmdMaxVerts (Hw3File *w, uint32_t curLine, double argv[15])
{
sc->attenuation = vector(argv[0], argv[1], argv[2]);
sc->vertexCount = (uint32_t) argv[0];
sc->vertex = new point[sc->vertexCount];
sc->curVertex = 0;
}
static void cmdMaxVertN (Hw3File *w, uint32_t curLine, double argv[15])
{
/* ignore for now */
}
static void cmdVertex (Hw3File *w, uint32_t curLine, double argv[15])
{
sc->vertex[sc->curVertex].set(argv[0], argv[1], argv[2]);
sc->curVertex++;
}
static void cmdVertexN (Hw3File *w, uint32_t curLine, double argv[15])
{
/* ignore for now */
}
static void cmdTri (Hw3File *w, uint32_t curLine, double argv[15])
{
/* arg are vertex numbers */
triangle *tr = new triangle(sc->vertex[(int)argv[0]], sc->vertex[(int)argv[1]], sc->vertex[(int)argv[2]], sc->getMatrix());
tr->ambient = sc->ambient;
tr->diffuse = sc->diffuse;
tr->specular = sc->specular;
tr->emission = sc->emission;
tr->shininess = sc->shininess;
tr->sourceLine = curLine;
sc->o[sc->o_count] = tr;
sc->o_count++;
}
#endif
void cmdAmbient (scene *sc, uint32_t curLine, char *first, float argv[15])
static cmd_def commandList[] =
{
sc->ambient = color(argv[0], argv[1], argv[2]);
}
void cmdDiffuse (scene *sc, uint32_t curLine, char *first, float argv[15])
{
sc->diffuse = color(argv[0], argv[1], argv[2]);
}
void cmdSpecular (scene *sc, uint32_t curLine, char *first, float argv[15])
{
sc->specular = color(argv[0], argv[1], argv[2]);
}
void cmdShine (scene *sc, uint32_t curLine, char *first, float argv[15])
{
sc->shininess = argv[0];
}
void cmdEmission (scene *sc, uint32_t curLine, char *first, float argv[15])
{
sc->emission = color(argv[0], argv[1], argv[2]);
}
cmd_def commandList[] =
{
/* Camera */
{ "camera", 10, cmdCamera },
/* Geometry */
{ "sphere", 4, cmdSphere },
//{ "maxverts", 1, cmdMaxVerts },
//{ "maxvertnorms", 1, cmdMaxVertN },
//{ "vertex", 3, cmdVertex },
//{ "vertexnormal", 6, cmdVertexN },
//{ "tri", 3, cmdTri },
//{ "trinormal", 3, cmdTriN },
//{ "cube", 1, cmdCube },
/* transformation */
{ "translate", 3, cmdTrans },
{ "rotate", 4, cmdRotate },
{ "scale", 3, cmdScale },
{ "pushTransform", 0, cmdPushT },
{ "popTransform", 0, cmdPopT },
/* Lights */
//{ "directional", 6, cmdLDire },
{ "point", 6, cmdLPoint },
//{ "attenuation", 3, cmdAtten },
/* Materials */
{ "ambient", 3, cmdAmbient },
{ "diffuse", 3, cmdDiffuse },
{ "specular", 3, cmdSpecular },
{ "shininess", 1, cmdShine },
{ "emission", 3, cmdEmission },
};
/* Camera */
{"camera", 10, cmdCamera},
/* Geometry */
{"sphere", 4, cmdSphere},
//{ "maxverts", 1, cmdMaxVerts },
//{ "maxvertnorms", 1, cmdMaxVertN },
//{ "vertex", 3, cmdVertex },
//{ "vertexnormal", 6, cmdVertexN },
//{ "tri", 3, cmdTri },
//{ "trinormal", 3, cmdTriN },
//{ "cube", 1, cmdCube },
/* transformation */
{"translate", 3, cmdTrans},
{"rotate", 4, cmdRotate},
{"scale", 3, cmdScale},
{"pushTransform", 0, cmdPushT},
{"popTransform", 0, cmdPopT},
/* Lights */
//{ "directional", 6, cmdLDire },
{"point", 6, cmdLPoint},
//{ "attenuation", 3, cmdAtten },
/* Materials */
{"color", 3, cmdColour},
{"ambient", 3, cmdAmbient},
{"diffuse", 3, cmdDiffuse},
{"specular", 3, cmdSpecular},
{"shininess", 1, cmdShine},
{"emission", 3, cmdEmission},
};
#define CMD_COUNT (sizeof(commandList) / sizeof(cmd_def))
scene *readfile::read(char *filename)
Hw3File::Hw3File(const char *filename) : transStackCount(0), currentColour(Colour(1, 1, 1)),
currentEmission(0), currentShininess(200), currentAmbient(0.1),
currentDiffuse(0.9), currentSpecular(0.9), camFoV(0)
{
FILE *fp;
scene *sc = new scene;
if (sc != NULL)
this->popTransformMatrix();
fp = fopen(filename, "rt");
if (fp != NULL)
{
fp = fopen(filename, "rt");
if (fp == NULL)
char buffer[512];
int line = 0;
while(!feof(fp))
{
delete sc;
sc = NULL;
}
else
{
char buffer[512];
int line = 0;
while(!feof(fp))
uint32_t i;
line++;
memset(buffer, 0, 512);
fgets(buffer, 512, fp);
if ((buffer[0] == '#') || (strlen(buffer) < 2))
{
uint32_t i;
line++;
memset(buffer, 0, 512);
fgets(buffer, 512, fp);
if ((buffer[0] == '#') || (strlen(buffer) < 2))
continue; /* Ingore empty line or commented lines */
//printf("::%d:> %s", strlen(buffer), buffer);
for (i = 0; i < CMD_COUNT; i++)
continue; /* Ingore empty line or commented lines */
}
for (i = 0; i < CMD_COUNT; i++)
{
if (strncmp(buffer, commandList[i].name, strlen(commandList[i].name)) == 0)
{
if (strncmp(buffer, commandList[i].name, strlen(commandList[i].name)) == 0)
char first[512];
double value[15];
if (commandList[i].numparam != 0)
{
char first[512];
float value[15];
if (commandList[i].numparam != 0)
size_t j;
int k = 0, l = 0;
char buff[512];
for(j = strlen(commandList[i].name); j < strlen(buffer); j++)
{
size_t j;
int k = 0, l = 0;
char buff[512];
for(j = strlen(commandList[i].name); j < strlen(buffer); j++)
if (!isspace(buffer[j]))
{
if (!isspace(buffer[j]))
{
buff[l++] = buffer[j];
}
else
{
buff[l] = 0;
l = 0;
if (k == 0)
{
strcpy(first, buff);
}
if (strlen(buff) > 0)
{
value[k++] = atof(buff);
}
}
buff[l++] = buffer[j];
}
if (k != abs(commandList[i].numparam))
else
{
printf("line %d malformed: given %d parameter, expected %d\n%s", line, k, abs(commandList[i].numparam), buffer);
sc = NULL;
goto exit;
buff[l] = 0;
l = 0;
if (k == 0)
{
strcpy(first, buff);
}
if (strlen(buff) > 0)
{
value[k++] = atof(buff);
}
}
}
commandList[i].f(sc, line, first, value);
break;
if (k != abs(commandList[i].numparam))
{
printf("line %d malformed: given %d parameter, expected %d\n%s", line, k, abs(commandList[i].numparam), buffer);
goto exit;
}
}
commandList[i].f(this, line, value);
break;
}
}
#ifdef USE_OCTREE
sc->createOctree();
#endif
}
}
exit:
return sc;
return;
}
#endif
Matrix Hw3File::getTransformMatrix()
{
return this->transformStack[this->transStackCount];
}
void Hw3File::popTransformMatrix()
{
if (this->transStackCount == 0)
{
this->transformStack[0] = Matrix4().identity();
}
else
{
this->transformStack[this->transStackCount] = Matrix4().identity();
this->transStackCount --;
}
}
void Hw3File::pushTransformMatrix()
{
this->transStackCount ++;
this->transformStack[this->transStackCount] = this->transformStack[this->transStackCount - 1];
}
void Hw3File::applyTransformMatrix(Matrix t)
{
this->transformStack[this->transStackCount] = this->transformStack[this->transStackCount] * t;
}

View File

@@ -3,36 +3,165 @@ project(DoRayTested)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(TESTS_SRC tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp ray_test.cpp
intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp world_test.cpp camera_test.cpp)
#Every executable here need these include folders and library
include_directories(../source/include ../source/pattern ../source/uvpattern)
link_libraries(rayonnement)
set(TESTS_SRC math_test.cpp tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp
ray_test.cpp intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp world_test.cpp camera_test.cpp
shape_test.cpp plane_test.cpp pattern_test.cpp cube_test.cpp cylinder_test.cpp cone_test.cpp group_test.cpp
boundingbox_test.cpp triangle_test.cpp sequence_test.cpp objfile_test.cpp smoothtriangle_test.cpp csg_test.cpp)
add_executable(testMyRays)
target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
target_include_directories(testMyRays PUBLIC ../source/include)
target_sources(testMyRays PRIVATE ${TESTS_SRC})
target_link_libraries(testMyRays gtest gtest_main rayonnement Threads::Threads)
target_link_libraries(testMyRays gtest gtest_main Threads::Threads)
add_custom_command(
TARGET testMyRays POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/triangles.obj
${CMAKE_CURRENT_BINARY_DIR}/
)
gtest_discover_tests(testMyRays
WORKING_DIRECTORY ${PROJECT_DIR}
PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_DIR}"
)
)
add_executable(hw3render)
target_sources(hw3render PRIVATE hw3render.cpp)
add_executable(test_render)
target_sources(test_render PRIVATE test_render.cpp)
add_executable(ch5_test)
target_include_directories(ch5_test PUBLIC ../source/include)
target_sources(ch5_test PRIVATE ch5_test.cpp)
target_link_libraries(ch5_test rayonnement)
add_executable(ch6_test)
target_include_directories(ch6_test PUBLIC ../source/include)
target_sources(ch6_test PRIVATE ch6_test.cpp)
target_link_libraries(ch6_test rayonnement)
add_executable(ch7_test)
target_include_directories(ch6_test PUBLIC ../source/include)
target_sources(ch7_test PRIVATE ch7_test.cpp)
target_link_libraries(ch7_test rayonnement)
add_executable(ch9_test)
target_sources(ch9_test PRIVATE ch9_test.cpp)
add_executable(ch10_test)
target_sources(ch10_test PRIVATE ch10_test.cpp)
add_executable(ch11_reflection)
target_sources(ch11_reflection PRIVATE ch11_reflection.cpp)
add_executable(ch11_refraction)
target_sources(ch11_refraction PRIVATE ch11_refraction.cpp)
add_executable(ch11_test)
target_sources(ch11_test PRIVATE ch11_test.cpp)
add_executable(ch12_test)
target_sources(ch12_test PRIVATE ch12_test.cpp)
add_executable(ch13_test)
target_sources(ch13_test PRIVATE ch13_test.cpp)
add_executable(ch13_cone)
target_sources(ch13_cone PRIVATE ch13_cone.cpp)
add_executable(ch14_test)
target_sources(ch14_test PRIVATE ch14_test.cpp)
add_executable(ch15_teapot_objfile)
target_sources(ch15_teapot_objfile PRIVATE ch15_teapot_objfile.cpp)
add_custom_command(
TARGET ch15_teapot_objfile POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/external/teapot*.obj
${CMAKE_CURRENT_BINARY_DIR}/
)
add_executable(ch16_test)
target_sources(ch16_test PRIVATE ch16_test.cpp)
add_executable(arealight_test)
target_sources(arealight_test PRIVATE arealight_test.cpp)
add_executable(triangle_rendertest)
target_sources(triangle_rendertest PRIVATE triangle_rendertest.cpp)
add_executable(christmasball_render)
target_sources(christmasball_render PRIVATE christmasball_render.cpp)
add_executable(uvmap_checkeredsphere)
target_sources(uvmap_checkeredsphere PRIVATE uvmap_checkeredsphere.cpp)
add_executable(uvmap_checkeredplane)
target_sources(uvmap_checkeredplane PRIVATE uvmap_checkeredplane.cpp)
add_executable(uvmap_checkeredcylinder)
target_sources(uvmap_checkeredcylinder PRIVATE uvmap_checkeredcylinder.cpp)
add_executable(uvmap_checkeredcube)
target_sources(uvmap_checkeredcube PRIVATE uvmap_checkeredcube.cpp)
add_executable(uvmap_aligncheckplane)
target_sources(uvmap_aligncheckplane PRIVATE uvmap_aligncheckplane.cpp)
add_executable(uvmap_earth)
target_sources(uvmap_earth PRIVATE uvmap_earth.cpp)
file(DOWNLOAD
http://planetpixelemporium.com/download/download.php?earthmap1k.jpg
${CMAKE_SOURCE_DIR}/external/earthmap1k.jpg
EXPECTED_HASH MD5=49c3b412cfa448ec819412fb3ca089d2
)
add_custom_command(
TARGET uvmap_earth POST_BUILD
COMMAND convert ${CMAKE_SOURCE_DIR}/external/earthmap1k.jpg ${CMAKE_CURRENT_BINARY_DIR}/earthmap1k.png)
add_executable(uvmap_skybox)
target_sources(uvmap_skybox PRIVATE uvmap_skybox.cpp)
file(DOWNLOAD
http://www.humus.name/Textures/LancellottiChapel.zip
${CMAKE_SOURCE_DIR}/external/LancellottiChapel.zip
EXPECTED_HASH MD5=cd16610b00a4ace6baf1f0aff80f5685
)
add_custom_command(
TARGET uvmap_skybox POST_BUILD
COMMAND unzip -o ${CMAKE_SOURCE_DIR}/external/LancellottiChapel.zip -d LancellottiChapel
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/external/
)
add_custom_command(
TARGET uvmap_skybox POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/external/LancellottiChapel/*.jpg
${CMAKE_CURRENT_BINARY_DIR}/
)
add_test(NAME Chapter05_Test COMMAND $<TARGET_FILE:ch5_test>)
add_test(NAME Chapter06_Test COMMAND $<TARGET_FILE:ch6_test>)
add_test(NAME Chapter07_Test COMMAND $<TARGET_FILE:ch7_test>)
add_test(NAME Chapter07_Test COMMAND $<TARGET_FILE:ch7_test>)
add_test(NAME Chapter09_Test COMMAND $<TARGET_FILE:ch9_test>)
add_test(NAME Chapter10_Test COMMAND $<TARGET_FILE:ch10_test>)
add_test(NAME Chapter11_Reflection COMMAND $<TARGET_FILE:ch11_reflection>)
add_test(NAME Chapter11_Refraction COMMAND $<TARGET_FILE:ch11_refraction>)
add_test(NAME Chapter11_Test COMMAND $<TARGET_FILE:ch11_test>)
add_test(NAME Chapter12_Test COMMAND $<TARGET_FILE:ch12_test>)
add_test(NAME Chapter13_Test COMMAND $<TARGET_FILE:ch13_test>)
add_test(NAME Chapter13_ConeBonus COMMAND $<TARGET_FILE:ch13_cone>)
add_test(NAME Chapter14_Test COMMAND $<TARGET_FILE:ch14_test>)
add_test(NAME Chapter15_Teapots COMMAND $<TARGET_FILE:ch15_teapot_objfile>)
add_test(NAME Chapter16_Test COMMAND $<TARGET_FILE:ch16_test>)
add_test(NAME AreaLight_Test COMMAND $<TARGET_FILE:arealight_test>)
add_test(NAME UVMap_CheckeredSphere COMMAND $<TARGET_FILE:uvmap_checkeredsphere>)
add_test(NAME UVMap_CheckeredPlane COMMAND $<TARGET_FILE:uvmap_checkeredplane>)
add_test(NAME UVMap_CheckeredCylinder COMMAND $<TARGET_FILE:uvmap_checkeredcylinder>)
add_test(NAME UVMap_AlignCheckPlane COMMAND $<TARGET_FILE:uvmap_aligncheckplane>)
add_test(NAME UVMap_CheckeredCube COMMAND $<TARGET_FILE:uvmap_checkeredcube>)
add_test(NAME UVMap_Earth COMMAND $<TARGET_FILE:uvmap_earth>)
add_test(NAME UVMap_Skybox COMMAND $<TARGET_FILE:uvmap_skybox>)
add_test(NAME Test_Rendering COMMAND $<TARGET_FILE:test_render>)
add_test(NAME Triangle_RenderTest COMMAND $<TARGET_FILE:triangle_rendertest>)
add_test(NAME ChristmasBall_Rendering COMMAND $<TARGET_FILE:christmasball_render>)
add_test(NAME Hw3Render COMMAND $<TARGET_FILE:hw3render> ${CMAKE_CURRENT_SOURCE_DIR}/test.hw3scene)
add_test(NAME Hw3RenderAllCmds COMMAND $<TARGET_FILE:hw3render> ${CMAKE_CURRENT_SOURCE_DIR}/test_keys.hw3scene)

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