Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e188a0594 | ||
|
|
c1f41cb6f6 | ||
|
|
50143076ab | ||
|
|
c33cdabdec | ||
|
|
ad16643111 | ||
|
|
45f5f8098e | ||
|
|
28b619c566 | ||
|
|
4f512405b2 | ||
|
|
fe80488c5e | ||
|
|
f8f4d7b21a | ||
|
|
5651570c2b | ||
|
|
71c236abb0 | ||
|
|
c0fc061834 | ||
|
|
61ce9d3543 | ||
|
|
9849c16f66 | ||
|
|
aacd4f6c9e | ||
|
|
5b6b627a43 | ||
|
|
4f2e327533 | ||
|
|
c858b4dcde | ||
|
|
7a43a98816 | ||
|
|
47e31714f3 | ||
|
|
424d58c59b | ||
|
|
5996e38e6e | ||
|
|
b00bb75189 | ||
|
|
0aa949c60b | ||
|
|
420203e95d | ||
|
|
c667ce26d7 | ||
|
|
13cc2c0ff9 | ||
|
|
1c4018e47a | ||
|
|
083a5b600f | ||
|
|
3a2d21b787 | ||
|
|
441d758845 | ||
|
|
5da0c10182 | ||
|
|
b89f9ec331 | ||
|
|
add3d7c861 | ||
|
|
4e241a1871 | ||
|
|
15a861802a | ||
|
|
66a8b98aeb | ||
|
|
0f945b69cc | ||
|
|
314da11005 | ||
|
|
8437ab8753 | ||
|
|
d514219ae6 | ||
|
|
efa47f28ca | ||
|
|
e653855556 | ||
|
|
1510de3b36 | ||
|
|
8550d4068f | ||
|
|
cd93b67274 | ||
|
|
18965fe1bd | ||
|
|
57eff4830e | ||
|
|
b5ee92c544 | ||
|
|
e57b5715e8 | ||
|
|
73012b6dd1 | ||
|
|
2488cc6319 | ||
|
|
518ac260e1 | ||
|
|
2725b5f657 | ||
|
|
c17bfadc76 | ||
|
|
6bef6a1b77 | ||
|
|
e33cf0d5f0 | ||
|
|
c41cbaeea8 | ||
|
|
3a8600d274 | ||
|
|
f8aa5cc920 | ||
|
|
30db4d7ca1 | ||
|
|
317148a37d | ||
|
|
5c6a5afef6 | ||
|
|
90e79576a2 | ||
|
|
a31ae5b2ef | ||
|
|
2ebc177d9d | ||
|
|
6a2c5a77ae | ||
|
|
d6ae062f7f | ||
|
|
3ebe403de0 | ||
|
|
f5685a45e1 | ||
|
|
7209244f48 | ||
|
|
1b6c14691b | ||
|
|
107b612130 | ||
|
|
5bbd036fc5 | ||
|
|
1ceabe7e62 | ||
|
|
3e37b5ca44 | ||
|
|
5c10d65c8d | ||
|
|
83c12dbd83 | ||
|
|
3cfbb604b0 | ||
|
|
36962275f6 | ||
|
|
a1c53fc9cc | ||
|
|
0be3236a03 | ||
|
|
344c36cd78 | ||
|
|
478b1f0af1 | ||
|
|
1cebcd4f8b | ||
|
|
aab9df0802 | ||
|
|
d05a0fb4d0 | ||
|
|
21749695b6 | ||
|
|
1fbe682572 | ||
|
|
ace7d53571 | ||
|
|
0ac44c3539 | ||
|
|
c4b680789e | ||
|
|
53f66b554b | ||
|
|
307c125eba | ||
|
|
b4ae737b40 | ||
|
|
8ceb68fdff | ||
|
|
c369d2fe2d | ||
|
|
2926166ce6 | ||
|
|
e61382a129 | ||
|
|
a6f0422bd1 | ||
|
|
a4ddfddbf3 | ||
|
|
f1849cdbc1 | ||
|
|
9174424d91 | ||
|
|
0369bee306 | ||
|
|
ed347e304d | ||
|
|
7a96d42874 | ||
|
|
1c00077949 | ||
|
|
5e4cfb84e6 | ||
|
|
aded6bb943 | ||
|
|
2ea4abdce7 | ||
|
|
831a096281 | ||
|
|
3011544e8f | ||
|
|
d1965caf8d | ||
|
|
7bbe5e843b | ||
|
|
7c794f0496 | ||
|
|
80f59efa43 | ||
|
|
f226664fe3 | ||
|
|
0650ac7b44 | ||
|
|
d87bbb184e | ||
|
|
b9bacd3ac9 | ||
|
|
1d685de8fd | ||
|
|
9c35cfc4f3 | ||
|
|
56095169eb | ||
|
|
60db274214 | ||
|
|
566be9bcf6 | ||
|
|
dac74007ea | ||
|
|
b251b632ac | ||
|
|
81e323fdf4 | ||
|
|
c9021974f6 | ||
|
|
4d4c4a7453 | ||
|
|
935c8ebff7 | ||
|
|
4cdf7a4264 |
44
.github/workflows/cmake.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
name: CMake
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
continue-on-error: ${{ matrix.allow_failure }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-latest ]
|
||||||
|
allow_failure: [false]
|
||||||
|
# include:
|
||||||
|
# - os: macos-latest
|
||||||
|
# allow_failure: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
- name: Test round 1
|
||||||
|
working-directory: ${{github.workspace}}/build
|
||||||
|
run: make test
|
||||||
|
|
||||||
|
- name: Test round 2
|
||||||
|
working-directory: ${{github.workspace}}/build/tests
|
||||||
|
run: make test
|
||||||
|
|
||||||
69
.travis.yml
@@ -1,17 +1,13 @@
|
|||||||
dist: bionic
|
|
||||||
language: c
|
language: c
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- lcov
|
- lcov
|
||||||
|
- imagemagick
|
||||||
os:
|
homebrew:
|
||||||
- linux
|
packages:
|
||||||
- osx
|
- imagemagick
|
||||||
compiler:
|
|
||||||
- clang
|
|
||||||
- gcc
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- mkdir build
|
- mkdir build
|
||||||
@@ -19,12 +15,61 @@ script:
|
|||||||
- cmake ..
|
- cmake ..
|
||||||
- make
|
- make
|
||||||
- make test
|
- make test
|
||||||
- ./tests/testMyRays
|
- cd tests
|
||||||
|
- ./testMyRays
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink python@2 ; fi
|
||||||
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install imagemagick ; fi
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
|
- os: linux
|
||||||
|
dist: bionic
|
||||||
|
arch: amd64
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
dist: bionic
|
||||||
|
arch: amd64
|
||||||
|
compiler: clang
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
dist: focal
|
||||||
|
arch: amd64
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
dist: focal
|
||||||
|
arch: amd64
|
||||||
|
compiler: clang
|
||||||
|
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
osx_image: xcode12.2
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
dist: focal
|
||||||
|
arch: arm64
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
osx_image: xcode10.3
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
osx_image: xcode11.6
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
osx_image: xcode12
|
||||||
|
|
||||||
- stage: "Coverage"
|
- stage: "Coverage"
|
||||||
os: linux
|
os: linux
|
||||||
|
dist: bionic
|
||||||
|
arch: amd64
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
script:
|
script:
|
||||||
- mkdir coverage
|
- mkdir coverage
|
||||||
@@ -34,3 +79,9 @@ jobs:
|
|||||||
- cmake --build . --target coveralls
|
- cmake --build . --target coveralls
|
||||||
after_success:
|
after_success:
|
||||||
- bash <(curl -s https://codecov.io/bash)
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
||||||
|
allow_failures:
|
||||||
|
- os: linux
|
||||||
|
arch: arm64
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.11)
|
||||||
|
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
|
|
||||||
@@ -10,18 +10,88 @@ option(COVERALLS "Generate coveralls data" OFF)
|
|||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/external/coveralls-cmake/cmake)
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/external/coveralls-cmake/cmake)
|
||||||
|
|
||||||
option(PACKAGE_TESTS "Build the tests" ON)
|
option(PACKAGE_TESTS "Build the tests" ON)
|
||||||
|
option(ENABLE_COVERAGE "Build for code coverage" OFF)
|
||||||
|
|
||||||
|
option(SHOW_STATS "Show rendering stat" OFF)
|
||||||
|
if (SHOW_STATS)
|
||||||
|
add_compile_options(-DRENDER_STATS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(USE_GPROF "Enable profiling" OFF)
|
||||||
|
if (USE_GPROF)
|
||||||
|
add_compile_options(-pg)
|
||||||
|
add_link_options(-pg)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(USE_LUA "Enable the use of Lua" ON)
|
||||||
|
if (USE_LUA)
|
||||||
|
add_compile_options(-DENABLE_LUA_SUPPORT)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_COVERAGE AND COVERALLS)
|
||||||
|
message(FATAL_ERROR "You can't enable both ENABLE_COVERAGE and COVERALLS at the same time")
|
||||||
|
endif()
|
||||||
|
|
||||||
if (COVERALLS)
|
if (COVERALLS)
|
||||||
include(Coveralls)
|
include(Coveralls)
|
||||||
coveralls_turn_on_coverage()
|
coveralls_turn_on_coverage()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_COVERAGE)
|
||||||
|
if("${CMAKE_C_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang" OR
|
||||||
|
"${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
||||||
|
message("Building with LLVM Code Coverage Tools")
|
||||||
|
set(CMAKE_CXX_FLAGS "-fprofile-instr-generate -fcoverage-mapping")
|
||||||
|
elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
message("Building with lcov Code Coverage Tools")
|
||||||
|
set(CMAKE_CXX_FLAGS "--coverage")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Compiler ${CMAKE_C_COMPILER_ID} is not supported for code coverage")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
# LodePNG don't make a .a or .so, so let's build a library here
|
# LodePNG don't make a .a or .so, so let's build a library here
|
||||||
add_library(LodePNG STATIC)
|
add_library(LodePNG STATIC)
|
||||||
set(LODEPNG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/lodepng)
|
set(LODEPNG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/lodepng)
|
||||||
target_sources(LodePNG PRIVATE external/lodepng/lodepng.cpp external/lodepng/lodepng.h)
|
target_sources(LodePNG PRIVATE external/lodepng/lodepng.cpp external/lodepng/lodepng.h)
|
||||||
|
|
||||||
|
if (USE_LUA)
|
||||||
|
if (CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
|
||||||
|
set(LUA_MAKE_TARGET linux)
|
||||||
|
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
|
||||||
|
set(LUA_MAKE_TARGET macosx)
|
||||||
|
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
|
||||||
|
set(LUA_MAKE_TARGET posix)
|
||||||
|
else()
|
||||||
|
set(LUA_MAKE_TARGET posix)
|
||||||
|
endif()
|
||||||
|
message("-- Lua: Building Lua for ${LUA_MAKE_TARGET}")
|
||||||
|
|
||||||
|
ExternalProject_Add(LuaCore
|
||||||
|
URL "https://www.lua.org/ftp/lua-5.3.5.tar.gz"
|
||||||
|
URL_HASH SHA1=112eb10ff04d1b4c9898e121d6bdf54a81482447
|
||||||
|
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/lua
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_IN_SOURCE True
|
||||||
|
BUILD_COMMAND make ${LUA_MAKE_TARGET}
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LUA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/lua/src")
|
||||||
|
set(LUA_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/external/lua/src/liblua.a" -ldl)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# NanoJPEG
|
||||||
|
file(DOWNLOAD
|
||||||
|
http://svn.emphy.de/nanojpeg/trunk/nanojpeg/nanojpeg.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/external/nanojpeg/nanojpeg.c
|
||||||
|
EXPECTED_HASH MD5=03ce304a71ae0ad1c43663fb386cc233
|
||||||
|
)
|
||||||
|
add_library(NanoJPEG STATIC)
|
||||||
|
set(NANOJPEG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/nanojpeg)
|
||||||
|
target_sources(NanoJPEG PRIVATE external/nanojpeg/nanojpeg.c)
|
||||||
|
|
||||||
# Main app
|
# Main app
|
||||||
add_subdirectory(source)
|
add_subdirectory(source)
|
||||||
|
|
||||||
|
|||||||
89
README.md
@@ -1,4 +1,4 @@
|
|||||||
[](https://codecov.io/gh/Godzil/DoRayMe) [](https://www.codacy.com/manual/Godzil/DoRayMe?utm_source=github.com&utm_medium=referral&utm_content=Godzil/DoRayMe&utm_campaign=Badge_Grade) [](https://coveralls.io/github/Godzil/DoRayMe?branch=master) [](https://travis-ci.org/Godzil/DoRayMe)
|
[](https://codecov.io/gh/Godzil/DoRayMe) [](https://www.codacy.com/manual/Godzil/DoRayMe?utm_source=github.com&utm_medium=referral&utm_content=Godzil/DoRayMe&utm_campaign=Badge_Grade) [](https://coveralls.io/github/Godzil/DoRayMe?branch=master) [](https://github.com/Godzil/DoRayMe/actions/workflows/cmake.yml)
|
||||||
|
|
||||||
DoRayMe
|
DoRayMe
|
||||||
=======
|
=======
|
||||||
@@ -6,42 +6,97 @@ DoRayMe
|
|||||||
A Quick and dirty raytracer.
|
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
|
Examples outputs
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
From chapter 05:
|
#### From chapter 05 - Sphere intersections:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
From Chapter 06:
|
#### From Chapter 06 - Phong shading:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
From Chapter 07:
|
#### From Chapter 07 - World / Camera / Scenes:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
From Chapter 08:
|
#### From Chapter 08 - Shadows:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
From Chapter 09:
|
#### From Chapter 09 - Planes:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
From Chapter 10:
|
#### From Chapter 10 - Patterns:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
From Chapter 11:
|
#### From Chapter 11 - Reflections, Transparency & Refractions:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
###### Bonus: Zooming on a reflective ball:
|
||||||
|

|
||||||
|
|
||||||
|
###### Zooming on a reflection on that ball:
|
||||||
|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
#### From Chapter 12 - Cubes:
|
||||||
|

|
||||||
|
|
||||||
|
#### From Chapter 13 - Cylinders:
|
||||||
|

|
||||||
|
###### Bonus:
|
||||||
|

|
||||||
|
|
||||||
|
#### From Chapter 14 - Groups & Bounding boxes:
|
||||||
|

|
||||||
|
|
||||||
|
#### From Chapter 15 - Triangles, Wavefrom OBJ files - Smooth trianges:
|
||||||
|

|
||||||
|
|
||||||
|
#### From Chapter 16 - Constructive Solid Geomety:
|
||||||
|

|
||||||
|
|
||||||
|
#### Bonus (from the forum):
|
||||||
|
[Merry Christmas](https://forum.raytracerchallenge.com/thread/16/merry-christmas-scene-description)
|
||||||
|

|
||||||
|
(about 1min render time using OpenMP on a 2.6Ghz Core i7 3720QM)
|
||||||
|
|
||||||
|
#### Bonus chapter - Soft shadow / Area light
|
||||||
|
###### Without jitter:
|
||||||
|

|
||||||
|
###### With jitter:
|
||||||
|

|
||||||
|
|
||||||
|
#### Bonus chapter - Texture mapping
|
||||||
|
###### Spherical mapping:
|
||||||
|

|
||||||
|
|
||||||
|
###### Planar mapping:
|
||||||
|

|
||||||
|
|
||||||
|
###### Cylindrical mapping:
|
||||||
|

|
||||||
|
|
||||||
|
###### Aligncheck plane:
|
||||||
|

|
||||||
|
|
||||||
|
###### Cubical mapping:
|
||||||
|

|
||||||
|
|
||||||
|
###### Image mapping:
|
||||||
|

|
||||||
|
|
||||||
|
###### Skybox:
|
||||||
|

|
||||||
|
|
||||||
|
###### Large OBJ file:
|
||||||
|

|
||||||
|
|||||||
2
external/googletest
vendored
494
external/teapot-low.obj
vendored
Normal 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
@@ -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
BIN
output/arealight_test.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
output/arealight_test_nojitter.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
output/ch11_reflection_on_ball.png
Normal file
|
After Width: | Height: | Size: 949 KiB |
BIN
output/ch11_zooming_on_reflective_ball.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
output/ch12_test.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
output/ch13_cone.png
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
output/ch13_test.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
output/ch14_test.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
output/ch15_teapot_objfile.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
output/ch16_test.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
output/christmasball.png
Normal file
|
After Width: | Height: | Size: 598 KiB |
BIN
output/dragon_scene.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
output/uvmap_aligncheckplane.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
output/uvmap_checkeredcube.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
output/uvmap_checkeredcylinder.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
output/uvmap_checkeredplane.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
output/uvmap_checkeredsphere.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
output/uvmap_earth.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
output/uvmap_skybox.png
Normal file
|
After Width: | Height: | Size: 453 KiB |
685
samplescenes/orrery.yml
Normal file
@@ -0,0 +1,685 @@
|
|||||||
|
# ======================================================
|
||||||
|
# orrery.yml
|
||||||
|
#
|
||||||
|
# This file describes the title image for the "Texture
|
||||||
|
# Mapping" bonus chapter at:
|
||||||
|
#
|
||||||
|
# http://www.raytracerchallenge.com/bonus/texture-mapping.html
|
||||||
|
#
|
||||||
|
# It requires several additional resources, provided as a
|
||||||
|
# separate download. The resources were found on the following
|
||||||
|
# sites:
|
||||||
|
#
|
||||||
|
# * https://www.bittbox.com/freebies/free-hi-resolution-wood-textures
|
||||||
|
# : the wooden texture for the table
|
||||||
|
# * https://astrogeology.usgs.gov/search/map/Mercury/Messenger/Global/Mercury_MESSENGER_MDIS_Basemap_LOI_Mosaic_Global_166m
|
||||||
|
# : the map of Mercury
|
||||||
|
# * http://planetpixelemporium.com/planets.html
|
||||||
|
# : maps of Earth, Mars, Jupiter, Saturn, Uranus, and Neptune
|
||||||
|
# * https://hdrihaven.com/hdri/?c=indoor&h=artist_workshop
|
||||||
|
# : the "artist workshop" environment map
|
||||||
|
#
|
||||||
|
# by Jamis Buck <jamis@jamisbuck.org>
|
||||||
|
# ======================================================
|
||||||
|
|
||||||
|
- add: camera
|
||||||
|
width: 800
|
||||||
|
height: 400
|
||||||
|
field-of-view: 1.2
|
||||||
|
from: [ 2, 4, -10]
|
||||||
|
to: [ -1, -1, 0 ]
|
||||||
|
up: [ 0, 1, 0 ]
|
||||||
|
|
||||||
|
# The scene as shown in the bonus chapter is rendered using an area light,
|
||||||
|
# precisely as described in the "Rendering soft shadows" bonus chapter,
|
||||||
|
# here: http://www.raytracerchallenge.com/bonus/area-light.html
|
||||||
|
#
|
||||||
|
# if you haven't implemented area lights, you can replace this with a point
|
||||||
|
# light located at [0, 2.5, -10].
|
||||||
|
|
||||||
|
- add: light
|
||||||
|
corner: [-5, 0, -10 ]
|
||||||
|
uvec: [ 10, 0, 0 ]
|
||||||
|
vvec: [ 0, 5, 0 ]
|
||||||
|
usteps: 10
|
||||||
|
vsteps: 5
|
||||||
|
jitter: true
|
||||||
|
intensity: [ 1, 1, 1 ]
|
||||||
|
|
||||||
|
# -------------------------------------------
|
||||||
|
# some common textures
|
||||||
|
# -------------------------------------------
|
||||||
|
|
||||||
|
- define: GOLD
|
||||||
|
value:
|
||||||
|
color: [ 1, 0.8, 0.1 ]
|
||||||
|
ambient: 0.1
|
||||||
|
diffuse: 0.6
|
||||||
|
specular: 0.3
|
||||||
|
shininess: 15
|
||||||
|
|
||||||
|
- define: SILVER
|
||||||
|
value:
|
||||||
|
color: [ 1, 1, 1 ]
|
||||||
|
ambient: 0.1
|
||||||
|
diffuse: 0.7
|
||||||
|
specular: 0.3
|
||||||
|
shininess: 15
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# CSG definition for the gears used to construct
|
||||||
|
# the orrery.
|
||||||
|
#
|
||||||
|
# NOTCH is a helper object used to create the
|
||||||
|
# teeth for the gears.
|
||||||
|
#
|
||||||
|
# GEAR is the actual gear object itself.
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
- define: NOTCH
|
||||||
|
value:
|
||||||
|
add: csg
|
||||||
|
operation: difference
|
||||||
|
left:
|
||||||
|
type: cube
|
||||||
|
transform:
|
||||||
|
- [ scale, 1, 0.25, 1 ]
|
||||||
|
- [ translate, 1, 0, 1 ]
|
||||||
|
- [ rotate-y, 0.7854 ]
|
||||||
|
- [ scale, 1, 1, 0.1 ]
|
||||||
|
right:
|
||||||
|
type: cylinder
|
||||||
|
min: -0.26
|
||||||
|
max: 0.26
|
||||||
|
closed: true
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.8, 1, 0.8 ]
|
||||||
|
|
||||||
|
- define: GEAR
|
||||||
|
value:
|
||||||
|
add: csg
|
||||||
|
operation: difference
|
||||||
|
left:
|
||||||
|
type: cylinder
|
||||||
|
min: -0.025
|
||||||
|
max: 0.025
|
||||||
|
closed: true
|
||||||
|
right:
|
||||||
|
type: group
|
||||||
|
children:
|
||||||
|
# center hole
|
||||||
|
- add: cylinder
|
||||||
|
min: -0.06
|
||||||
|
max: 0.06
|
||||||
|
closed: true
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.1, 1, 0.1 ]
|
||||||
|
# crescents
|
||||||
|
- add: csg
|
||||||
|
operation: difference
|
||||||
|
left:
|
||||||
|
type: cylinder
|
||||||
|
min: -0.06
|
||||||
|
max: 0.06
|
||||||
|
closed: true
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.7, 1, 0.7 ]
|
||||||
|
right:
|
||||||
|
type: cube
|
||||||
|
transform:
|
||||||
|
- [ scale, 1, 0.1, 0.2 ]
|
||||||
|
# teeth
|
||||||
|
- add: NOTCH
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 0.31415 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 0.6283 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 0.94245 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 1.2566 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 1.57075 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 1.8849 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 2.19905 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 2.5132 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 2.82735 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 3.1415 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -0.31415 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -0.6283 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -0.94245 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -1.2566 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -1.57075 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -1.8849 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -2.19905 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -2.5132 ]
|
||||||
|
- add: NOTCH
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -2.82735 ]
|
||||||
|
|
||||||
|
# mechanism: top plate
|
||||||
|
- add: csg
|
||||||
|
operation: difference
|
||||||
|
material: GOLD
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -1 ]
|
||||||
|
left:
|
||||||
|
type: cylinder
|
||||||
|
min: -1.51
|
||||||
|
max: -1.5
|
||||||
|
closed: true
|
||||||
|
right:
|
||||||
|
type: group
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -1.52
|
||||||
|
max: -1.49
|
||||||
|
closed: true
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.1, 1, 0.1 ]
|
||||||
|
- add: csg
|
||||||
|
operation: difference
|
||||||
|
left:
|
||||||
|
type: cylinder
|
||||||
|
min: -1.52
|
||||||
|
max: -1.49
|
||||||
|
closed: true
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.75, 1, 0.75 ]
|
||||||
|
right:
|
||||||
|
type: cube
|
||||||
|
transform:
|
||||||
|
- [ scale, 1, 0.1, 0.2 ]
|
||||||
|
- [ translate, 0, -1.5, 0 ]
|
||||||
|
|
||||||
|
# mechanism: gear
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.5, 0.5, 0.5 ]
|
||||||
|
- [ translate, 0.4, -1.45, -0.4 ]
|
||||||
|
|
||||||
|
# mechanism: gear
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 0.8 ]
|
||||||
|
- [ scale, 0.4, 0.4, 0.4 ]
|
||||||
|
- [ translate, -0.4, -1.45, 0.2 ]
|
||||||
|
|
||||||
|
# sun
|
||||||
|
- add: group
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
shadow: false
|
||||||
|
material:
|
||||||
|
color: [1, 1, 0]
|
||||||
|
ambient: 0.1
|
||||||
|
diffuse: 0.6
|
||||||
|
specular: 0 # count on the skybox reflection being the specular highlight
|
||||||
|
reflective: 0.2
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -4
|
||||||
|
max: -0.5
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
|
||||||
|
# base
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ translate, 0, -4, 0 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: checkers
|
||||||
|
width: 16
|
||||||
|
height: 8
|
||||||
|
colors:
|
||||||
|
- [ 0, 0, 0 ]
|
||||||
|
- [ 0.5, 0.5, 0.5 ]
|
||||||
|
diffuse: 0.6
|
||||||
|
specular: 0 # count on the skybox reflection being the specular highlight
|
||||||
|
ambient: 0.1
|
||||||
|
reflective: 0.2
|
||||||
|
|
||||||
|
# table
|
||||||
|
- add: cube
|
||||||
|
transform:
|
||||||
|
- [ scale, 5, 0.1, 5 ]
|
||||||
|
- [ translate, 0, -4, 0 ]
|
||||||
|
material:
|
||||||
|
diffuse: 0.9
|
||||||
|
ambient: 0.1
|
||||||
|
specular: 0
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: planar
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/wood.ppm
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.5, 0.5, 0.5 ]
|
||||||
|
|
||||||
|
# mechanism: gear-plate between top & mercury
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -0.4 ]
|
||||||
|
- [ scale, 0.9, 0.9, 0.9 ]
|
||||||
|
- [ translate, 0, -1.75, 0 ]
|
||||||
|
|
||||||
|
# mercury
|
||||||
|
- add: group
|
||||||
|
transform:
|
||||||
|
- [ translate, 2, 0, 0 ]
|
||||||
|
- [ rotate-y, 0.7 ]
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.25, 0.25, 0.25 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/mercury-small.ppm
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -2
|
||||||
|
max: 0
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 0.025, 0.025 ]
|
||||||
|
- [ translate, 0, -2, 0 ]
|
||||||
|
- add: cylinder
|
||||||
|
min: 0
|
||||||
|
max: 2
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- [ rotate-z, 1.5708 ]
|
||||||
|
- [ translate, 0, -2, 0 ]
|
||||||
|
|
||||||
|
# mechanism: gear-plate between mercury & venus
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, 1.3 ]
|
||||||
|
- [ translate, 0, -2.05, 0 ]
|
||||||
|
|
||||||
|
# venus
|
||||||
|
- add: group
|
||||||
|
transform:
|
||||||
|
- [ translate, 3, 0, 0 ]
|
||||||
|
- [ rotate-y, 0.3 ]
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.25, 0.25, 0.25 ]
|
||||||
|
material:
|
||||||
|
color: [ 1, 1, 0.8 ]
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -2.1
|
||||||
|
max: 0
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 0.025, 0.025 ]
|
||||||
|
- [ translate, 0, -2.1, 0 ]
|
||||||
|
- add: cylinder
|
||||||
|
min: 0
|
||||||
|
max: 3
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- [ rotate-z, 1.5708 ]
|
||||||
|
- [ translate, 0, -2.1, 0 ]
|
||||||
|
|
||||||
|
# mechanism: gear-plate between venus & earth
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.9, 0.9, 0.9 ]
|
||||||
|
- [ rotate-y, -2.2 ]
|
||||||
|
- [ translate, 0, -2.15, 0 ]
|
||||||
|
|
||||||
|
# earth
|
||||||
|
- add: group
|
||||||
|
transform:
|
||||||
|
- [ translate, 4, 0, 0 ]
|
||||||
|
- [ rotate-y, 2 ]
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.25, 0.25, 0.25 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/earthmap-small.ppm
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -2.2
|
||||||
|
max: 0
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 0.025, 0.025 ]
|
||||||
|
- [ translate, 0, -2.2, 0 ]
|
||||||
|
- add: cylinder
|
||||||
|
min: 0
|
||||||
|
max: 4
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- [ rotate-z, 1.5708 ]
|
||||||
|
- [ translate, 0, -2.2, 0 ]
|
||||||
|
|
||||||
|
# mechanism: gear-plate between earth & mars
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.8, 0.8, 0.8 ]
|
||||||
|
- [ rotate-y, 1.7 ]
|
||||||
|
- [ translate, 0, -2.25, 0 ]
|
||||||
|
|
||||||
|
# mars
|
||||||
|
- add: group
|
||||||
|
transform:
|
||||||
|
- [ translate, 5, 0, 0 ]
|
||||||
|
- [ rotate-y, -2 ]
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.25, 0.25, 0.25 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/mars-small.ppm
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -2.3
|
||||||
|
max: 0
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 0.025, 0.025 ]
|
||||||
|
- [ translate, 0, -2.3, 0 ]
|
||||||
|
- add: cylinder
|
||||||
|
min: 0
|
||||||
|
max: 5
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- [ rotate-z, 1.5708 ]
|
||||||
|
- [ translate, 0, -2.3, 0 ]
|
||||||
|
|
||||||
|
# mechanism: gear-plate between mars & jupiter
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -0.9 ]
|
||||||
|
- [ translate, 0, -2.35, 0 ]
|
||||||
|
|
||||||
|
# jupiter
|
||||||
|
- add: group
|
||||||
|
transform:
|
||||||
|
- [ translate, 6.5, 0, 0 ]
|
||||||
|
- [ rotate-y, -0.75 ]
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.67, 0.67, 0.67 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/jupitermap-small.ppm
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -2.4
|
||||||
|
max: 0
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 0.025, 0.025 ]
|
||||||
|
- [ translate, 0, -2.4, 0 ]
|
||||||
|
- add: cylinder
|
||||||
|
min: 0
|
||||||
|
max: 6.5
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- [ rotate-z, 1.5708 ]
|
||||||
|
- [ translate, 0, -2.4, 0 ]
|
||||||
|
|
||||||
|
# mechanism: gear-plate between jupiter & saturn
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.95, 0.95, 0.95 ]
|
||||||
|
- [ rotate-y, -1.1 ]
|
||||||
|
- [ translate, 0, -2.45, 0 ]
|
||||||
|
|
||||||
|
# saturn
|
||||||
|
- add: group
|
||||||
|
transform:
|
||||||
|
- [ translate, 8, 0, 0 ]
|
||||||
|
- [ rotate-y, -2.5 ]
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.5, 0.5, 0.5 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/saturnmap-small.ppm
|
||||||
|
# rings
|
||||||
|
- add: csg
|
||||||
|
operation: difference
|
||||||
|
transform:
|
||||||
|
- [ rotate-z, 0.2 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: rings
|
||||||
|
colors:
|
||||||
|
- [ 1, 1, 0.5 ]
|
||||||
|
- [ 1, 1, 0 ]
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.05, 1, 0.05 ]
|
||||||
|
left:
|
||||||
|
type: cylinder
|
||||||
|
min: -0.01
|
||||||
|
max: 0.01
|
||||||
|
closed: true
|
||||||
|
transform:
|
||||||
|
- [ scale, 1.2, 1, 1.2 ]
|
||||||
|
right:
|
||||||
|
type: cylinder
|
||||||
|
min: -0.02
|
||||||
|
max: 0.02
|
||||||
|
closed: true
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.75, 1, 0.75 ]
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -2.5
|
||||||
|
max: 0
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 0.025, 0.025 ]
|
||||||
|
- [ translate, 0, -2.5, 0 ]
|
||||||
|
- add: cylinder
|
||||||
|
min: 0
|
||||||
|
max: 8
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- [ rotate-z, 1.5708 ]
|
||||||
|
- [ translate, 0, -2.5, 0 ]
|
||||||
|
|
||||||
|
# mechanism: gear-plate between saturn & uranus
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.9, 0.9, 0.9 ]
|
||||||
|
- [ rotate-y, 1 ]
|
||||||
|
- [ translate, 0, -2.55, 0 ]
|
||||||
|
|
||||||
|
# uranus
|
||||||
|
- add: group
|
||||||
|
transform:
|
||||||
|
- [ translate, 9, 0, 0 ]
|
||||||
|
- [ rotate-y, -3 ]
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.4, 0.4, 0.4 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/uranusmap-small.ppm
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -2.6
|
||||||
|
max: 0
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 0.025, 0.025 ]
|
||||||
|
- [ translate, 0, -2.6, 0 ]
|
||||||
|
- add: cylinder
|
||||||
|
min: 0
|
||||||
|
max: 9
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- [ rotate-z, 1.5708 ]
|
||||||
|
- [ translate, 0, -2.6, 0 ]
|
||||||
|
|
||||||
|
# mechanism: gear-plate between uranus & neptune
|
||||||
|
- add: GEAR
|
||||||
|
material: SILVER
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -1 ]
|
||||||
|
- [ translate, 0, -2.65, 0 ]
|
||||||
|
|
||||||
|
# neptune
|
||||||
|
- add: group
|
||||||
|
transform:
|
||||||
|
- [ translate, 10, 0, 0 ]
|
||||||
|
- [ rotate-y, -1.25 ]
|
||||||
|
children:
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.4, 0.4, 0.4 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/neptunemap-small.ppm
|
||||||
|
- add: group
|
||||||
|
material: GOLD
|
||||||
|
children:
|
||||||
|
- add: cylinder
|
||||||
|
min: -2.7
|
||||||
|
max: 0
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 0.025, 0.025 ]
|
||||||
|
- [ translate, 0, -2.7, 0 ]
|
||||||
|
- add: cylinder
|
||||||
|
min: 0
|
||||||
|
max: 10
|
||||||
|
transform:
|
||||||
|
- [ scale, 0.025, 1, 0.025 ]
|
||||||
|
- [ rotate-z, 1.5708 ]
|
||||||
|
- [ translate, 0, -2.7, 0 ]
|
||||||
|
|
||||||
|
# outer sphere as the surrounding environment
|
||||||
|
- add: sphere
|
||||||
|
transform:
|
||||||
|
- [ scale, 1000, 1000, 1000 ]
|
||||||
|
material:
|
||||||
|
pattern:
|
||||||
|
type: map
|
||||||
|
mapping: spherical
|
||||||
|
uv_pattern:
|
||||||
|
type: image
|
||||||
|
file: res/artist_workshop.ppm
|
||||||
|
transform:
|
||||||
|
- [ rotate-y, -2.7 ]
|
||||||
|
diffuse: 0
|
||||||
|
specular: 0
|
||||||
|
ambient: 1
|
||||||
@@ -1,21 +1,42 @@
|
|||||||
# To simplify testing, the app is build in two passes,
|
# To simplify testing, the app is build in two passes,
|
||||||
|
option(USE_OPENMP "Build using OpenMP" OFF)
|
||||||
|
|
||||||
|
if (USE_OPENMP)
|
||||||
|
find_package(OpenMP REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
# First most is build as a library
|
# First most is build as a library
|
||||||
add_library(rayonnement STATIC)
|
add_library(rayonnement STATIC)
|
||||||
|
|
||||||
file(GLOB RAY_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/pattern/*.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
|
file(GLOB RAY_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shapes/*.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/worldbuilder/*.cpp)
|
${CMAKE_CURRENT_SOURCE_DIR}/worldbuilder/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/worldoptimiser/*.cpp)
|
||||||
|
|
||||||
target_include_directories(rayonnement PUBLIC include pattern)
|
target_include_directories(rayonnement PUBLIC include pattern)
|
||||||
target_sources(rayonnement PRIVATE ${RAY_HEADERS} ${RAY_SOURCES})
|
|
||||||
target_link_libraries(rayonnement LodePNG)
|
|
||||||
|
|
||||||
# Second we build the main executable
|
if (USE_LUA)
|
||||||
add_executable(dorayme main.cpp)
|
add_dependencies(rayonnement LuaCore)
|
||||||
target_include_directories(rayonnement PUBLIC include ${LODEPNG_INCLUDE_FOLDER})
|
target_link_libraries(rayonnement ${LUA_LIBRARIES})
|
||||||
target_link_libraries(dorayme rayonnement)
|
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})
|
||||||
|
|
||||||
|
|
||||||
if (COVERALLS)
|
if (COVERALLS)
|
||||||
set(COVERAGE_SRCS ${RAY_HEADERS} ${RAY_SOURCES} ${COVERAGE_SRCS} PARENT_SCOPE)
|
set(COVERAGE_SRCS ${RAY_HEADERS} ${RAY_SOURCES} ${COVERAGE_SRCS} PARENT_SCOPE)
|
||||||
|
|||||||
@@ -12,10 +12,14 @@
|
|||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
#include <camera.h>
|
#include <camera.h>
|
||||||
|
|
||||||
Camera::Camera(uint32_t hsize, uint32_t vsize, double fov) : verticalSize(vsize), horizontalSize(hsize), fieldOfView(fov)
|
#include <stdio.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
|
||||||
|
Camera::Camera(uint32_t hsize, uint32_t vsize, double fov) : verticalSize(vsize),
|
||||||
|
horizontalSize(hsize), fieldOfView(fov), focalDistance(1), apertureSize(0), rayCount(1)
|
||||||
{
|
{
|
||||||
double aspectRatio = (double)hsize / (double)vsize;
|
double aspectRatio = (double)hsize / (double)vsize;
|
||||||
double halfView = tan(fov / 2.0);
|
double halfView = tan(fov / 2.0) * this->focalDistance;
|
||||||
|
|
||||||
if (aspectRatio >= 1)
|
if (aspectRatio >= 1)
|
||||||
{
|
{
|
||||||
@@ -31,7 +35,6 @@ Camera::Camera(uint32_t hsize, uint32_t vsize, double fov) : verticalSize(vsize)
|
|||||||
this->pixelSize = (this->halfWidth * 2) / this->horizontalSize;
|
this->pixelSize = (this->halfWidth * 2) / this->horizontalSize;
|
||||||
|
|
||||||
this->setTransform(Matrix4().identity());
|
this->setTransform(Matrix4().identity());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setTransform(Matrix transform)
|
void Camera::setTransform(Matrix transform)
|
||||||
@@ -40,7 +43,7 @@ void Camera::setTransform(Matrix transform)
|
|||||||
this->inverseTransform = transform.inverse();
|
this->inverseTransform = transform.inverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ray Camera::rayForPixel(uint32_t pixelX, uint32_t pixelY)
|
Ray Camera::rayForPixel(uint32_t pixelX, uint32_t pixelY, double horzOffset, double vertOffset)
|
||||||
{
|
{
|
||||||
double xOffset = ((double)pixelX + 0.5) * this->pixelSize;
|
double xOffset = ((double)pixelX + 0.5) * this->pixelSize;
|
||||||
double yOffset = ((double)pixelY + 0.5) * this->pixelSize;
|
double yOffset = ((double)pixelY + 0.5) * this->pixelSize;
|
||||||
@@ -48,10 +51,11 @@ Ray Camera::rayForPixel(uint32_t pixelX, uint32_t pixelY)
|
|||||||
double worldX = this->halfWidth - xOffset;
|
double worldX = this->halfWidth - xOffset;
|
||||||
double worldY = this->halfHeight - yOffset;
|
double worldY = this->halfHeight - yOffset;
|
||||||
|
|
||||||
Tuple pixel = this->inverseTransform * Point(worldX, worldY, -1);
|
Tuple pixel = this->inverseTransform * Point(worldX, worldY, -this->focalDistance);
|
||||||
Tuple origin = this->inverseTransform * Point(0, 0, 0);
|
Tuple origin = this->inverseTransform * Point(horzOffset, vertOffset, 0);
|
||||||
Tuple direction = (pixel - origin).normalise();
|
Tuple direction = (pixel - origin).normalise();
|
||||||
|
|
||||||
|
stats.addCastedRay();
|
||||||
return Ray(origin, direction);
|
return Ray(origin, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,15 +64,39 @@ Canvas Camera::render(World world, uint32_t depth)
|
|||||||
uint32_t x, y;
|
uint32_t x, y;
|
||||||
Canvas image = Canvas(this->horizontalSize, this->verticalSize);
|
Canvas image = Canvas(this->horizontalSize, this->verticalSize);
|
||||||
|
|
||||||
|
#pragma omp parallel default(shared) private(x, y) shared(image, stats)
|
||||||
|
{
|
||||||
|
#pragma omp for schedule(dynamic, 5)
|
||||||
for (y = 0 ; y < this->verticalSize ; y++)
|
for (y = 0 ; y < this->verticalSize ; y++)
|
||||||
{
|
{
|
||||||
for (x = 0 ; x < this->horizontalSize ; x++)
|
for (x = 0 ; x < this->horizontalSize ; x++)
|
||||||
|
{
|
||||||
|
Tuple colour;
|
||||||
|
if (this->apertureSize > 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0 ; i < this->rayCount ; i++)
|
||||||
|
{
|
||||||
|
double horz = frandclip(-this->apertureSize/2, this->apertureSize / 2);
|
||||||
|
double vert = frandclip(-this->apertureSize/2, this->apertureSize / 2);
|
||||||
|
Ray r = this->rayForPixel(x, y, horz, vert);
|
||||||
|
colour = colour + world.colourAt(r, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
colour = colour / this->rayCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Ray r = this->rayForPixel(x, y);
|
Ray r = this->rayForPixel(x, y);
|
||||||
Tuple colour = world.colourAt(r, depth);
|
colour = world.colourAt(r, depth);
|
||||||
|
}
|
||||||
|
stats.addPixel();
|
||||||
image.putPixel(x, y, colour);
|
image.putPixel(x, y, colour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.printStats();
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,16 @@
|
|||||||
|
|
||||||
#include <canvas.h>
|
#include <canvas.h>
|
||||||
#include <lodepng.h>
|
#include <lodepng.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* NanoJPEG is a bit interesting to include as a header */
|
||||||
|
extern "C" {
|
||||||
|
#define _NJ_INCLUDE_HEADER_ONLY
|
||||||
|
#include <nanojpeg.c>
|
||||||
|
#undef _NJ_INCLUDE_HEADER_ONLY
|
||||||
|
}
|
||||||
|
|
||||||
#define BPP (24)
|
#define BPP (24)
|
||||||
#define BytePP (BPP / 8)
|
#define BytePP (BPP / 8)
|
||||||
@@ -40,6 +50,80 @@ Canvas::Canvas(const Canvas *b)
|
|||||||
memcpy(this->bitmap, b->bitmap, 4 * b->width * b->height);
|
memcpy(this->bitmap, b->bitmap, 4 * b->width * b->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Canvas::Canvas(const char *imgfile)
|
||||||
|
{
|
||||||
|
/* Try to determine the file type in a really lazy way */
|
||||||
|
const char *fileExt = strrchr(imgfile, '.');
|
||||||
|
|
||||||
|
this->bitmap = NULL;
|
||||||
|
|
||||||
|
if (fileExt == NULL)
|
||||||
|
{
|
||||||
|
printf("ERROR: Invalid file name '%s' - Can't determine the file format\n", imgfile);
|
||||||
|
}
|
||||||
|
else if (strncasecmp(fileExt, ".png", strlen(fileExt)) == 0)
|
||||||
|
{
|
||||||
|
uint32_t ret = lodepng_decode24_file(&this->bitmap, &this->width, &this->height, imgfile);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
printf("ERROR: %s\n", lodepng_error_text(ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( (strncasecmp(fileExt, ".jpg", strlen(fileExt)) == 0) || (strncasecmp(fileExt, ".jpeg", strlen(fileExt)) == 0) )
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char *fileBuff;
|
||||||
|
size_t fileSize;
|
||||||
|
|
||||||
|
fp = fopen(imgfile, "rb");
|
||||||
|
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
fileSize = ftell(fp);
|
||||||
|
fileBuff = (char *)calloc(fileSize, 1);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
fileSize = fread(fileBuff, 1, fileSize, fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
njInit();
|
||||||
|
if (!njDecode(fileBuff, fileSize))
|
||||||
|
{
|
||||||
|
this->width = njGetWidth();
|
||||||
|
this->height = njGetHeight();
|
||||||
|
/* Need to do a local copy */
|
||||||
|
|
||||||
|
this->bitmap = (uint8_t *)calloc(1, njGetImageSize());
|
||||||
|
memcpy(this->bitmap, njGetImage(), njGetImageSize());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ERROR: Error while decoding the file '%s'\n", imgfile);
|
||||||
|
}
|
||||||
|
free(fileBuff);
|
||||||
|
|
||||||
|
njDone();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ERROR: Can't open/find the file '%s'.\n", imgfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ERROR: File extention '%s' is not a recognized one.\n", fileExt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->bitmap == NULL)
|
||||||
|
{
|
||||||
|
printf("ABORT: Opening image file '%s' failed\n", imgfile);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->stride = BytePP * width;
|
||||||
|
}
|
||||||
|
|
||||||
Canvas::~Canvas()
|
Canvas::~Canvas()
|
||||||
{
|
{
|
||||||
if (this->bitmap != nullptr)
|
if (this->bitmap != nullptr)
|
||||||
@@ -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;
|
uint32_t offset = y * this->stride + x * BytePP;
|
||||||
this->bitmap[offset + 0] = MAX(MIN(colour.x * 255, 255), 0);
|
this->bitmap[offset + 0] = MAX(MIN(c.x * 255, 255), 0);
|
||||||
this->bitmap[offset + 1] = MAX(MIN(colour.y * 255, 255), 0);
|
this->bitmap[offset + 1] = MAX(MIN(c.y * 255, 255), 0);
|
||||||
this->bitmap[offset + 2] = MAX(MIN(colour.z * 255, 255), 0);
|
this->bitmap[offset + 2] = MAX(MIN(c.z * 255, 255), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Colour Canvas::getPixel(uint32_t x, uint32_t y)
|
Colour Canvas::getPixel(uint32_t x, uint32_t y)
|
||||||
|
|||||||
134
source/include/boundingbox.h
Normal 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 */
|
||||||
@@ -21,6 +21,10 @@ private:
|
|||||||
double halfWidth;
|
double halfWidth;
|
||||||
double halfHeight;
|
double halfHeight;
|
||||||
public:
|
public:
|
||||||
|
double focalDistance;
|
||||||
|
double apertureSize;
|
||||||
|
uint32_t rayCount;
|
||||||
|
|
||||||
uint32_t verticalSize;
|
uint32_t verticalSize;
|
||||||
uint32_t horizontalSize;
|
uint32_t horizontalSize;
|
||||||
double fieldOfView;
|
double fieldOfView;
|
||||||
@@ -30,8 +34,13 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Camera(uint32_t hsize, uint32_t vsize, double fov);
|
Camera(uint32_t hsize, uint32_t vsize, double fov);
|
||||||
|
void setFocal(double focal, double aperture, uint32_t rayCount) {
|
||||||
|
this->focalDistance = focal;
|
||||||
|
this->apertureSize = aperture;
|
||||||
|
this->rayCount = rayCount;
|
||||||
|
}
|
||||||
void setTransform(Matrix transform);
|
void setTransform(Matrix transform);
|
||||||
Ray rayForPixel(uint32_t pixelX, uint32_t pixelY);
|
Ray rayForPixel(uint32_t pixelX, uint32_t pixelY, double horzOffset = 0, double vertOffset = 0);
|
||||||
Canvas render(World w, uint32_t depth = 5);
|
Canvas render(World w, uint32_t depth = 5);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ public:
|
|||||||
Canvas(uint32_t width, uint32_t height);
|
Canvas(uint32_t width, uint32_t height);
|
||||||
Canvas(const Canvas *c);
|
Canvas(const Canvas *c);
|
||||||
Canvas(const Canvas &c);
|
Canvas(const Canvas &c);
|
||||||
|
Canvas(const char *imgfile);
|
||||||
|
|
||||||
~Canvas();
|
~Canvas();
|
||||||
|
|
||||||
void putPixel(uint32_t x, uint32_t y, Tuple c);
|
void putPixel(uint32_t x, uint32_t y, Tuple c);
|
||||||
|
|||||||
39
source/include/cone.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Cone header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_CONE_H
|
||||||
|
#define DORAYME_CONE_H
|
||||||
|
|
||||||
|
#include <shape.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <intersect.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
class Cone : public Shape {
|
||||||
|
protected:
|
||||||
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
|
|
||||||
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
|
bool checkCap(Ray r, double t, double y);
|
||||||
|
void intersectCaps(Ray r, Intersect &xs);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isClosed;
|
||||||
|
double minCap;
|
||||||
|
double maxCap;
|
||||||
|
|
||||||
|
Cone() : minCap(-INFINITY), maxCap(INFINITY), isClosed(false), Shape(Shape::CONE) { stats.addCone(); };
|
||||||
|
BoundingBox getLocalBounds();
|
||||||
|
bool haveFiniteBounds() { return !(isinf(this->minCap) || isinf(this->maxCap)); };
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_CONE_H */
|
||||||
56
source/include/csg.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* CSG header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_CSG_H
|
||||||
|
#define DORAYME_CSG_H
|
||||||
|
|
||||||
|
#include <shape.h>
|
||||||
|
|
||||||
|
class CSG : public Shape
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum OperationType
|
||||||
|
{
|
||||||
|
UNION,
|
||||||
|
DIFFERENCE,
|
||||||
|
INTERSECTION
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Shape *left;
|
||||||
|
Shape *right;
|
||||||
|
OperationType operation;
|
||||||
|
BoundingBox bounds;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
BoundingBox getLocalBounds();
|
||||||
|
|
||||||
|
bool intersectionAllowed(bool leftHit, bool inLeft, bool inRight);
|
||||||
|
|
||||||
|
void filterIntersections(Intersect &xs, Intersect &ret);
|
||||||
|
|
||||||
|
void updateBoundingBox();
|
||||||
|
BoundingBox getBounds();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CSG(OperationType operation, Shape *left, Shape *right);
|
||||||
|
|
||||||
|
void intersect(Ray &r, Intersect &xs);
|
||||||
|
|
||||||
|
bool includes(Shape *b);
|
||||||
|
|
||||||
|
void updateTransform();
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_CSG_H */
|
||||||
32
source/include/cube.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Cube header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_CUBE_H
|
||||||
|
#define DORAYME_CUBE_H
|
||||||
|
|
||||||
|
#include <shape.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <intersect.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
class Cube : public Shape {
|
||||||
|
protected:
|
||||||
|
void checkAxis(double axeOrigin, double axeDirection, double *axeMin, double *axeMax);
|
||||||
|
|
||||||
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
|
|
||||||
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Cube() : Shape(Shape::CUBE) { stats.addCube(); };
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_CUBE_H */
|
||||||
41
source/include/cylinder.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Cylinder header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_CYLINDER_H
|
||||||
|
#define DORAYME_CYLINDER_H
|
||||||
|
|
||||||
|
#include <shape.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <intersect.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
class Cylinder : public Shape {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
|
|
||||||
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
|
bool checkCap(Ray r, double t);
|
||||||
|
void intersectCaps(Ray r, Intersect &xs);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isClosed;
|
||||||
|
double minCap;
|
||||||
|
double maxCap;
|
||||||
|
|
||||||
|
Cylinder() : minCap(-INFINITY), maxCap(INFINITY), isClosed(false), Shape(Shape::CYLINDER) { stats.addCylinder(); };
|
||||||
|
|
||||||
|
BoundingBox getLocalBounds();
|
||||||
|
bool haveFiniteBounds() { return !(isinf(this->minCap) || isinf(this->maxCap)); };
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //DORAYME_CYLINDER_H
|
||||||
69
source/include/group.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Group header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_GROUP_H
|
||||||
|
#define DORAYME_GROUP_H
|
||||||
|
|
||||||
|
#include <shape.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* TODO: Add a way to force(?) material from group to be applied on childs */
|
||||||
|
|
||||||
|
class Group : public Shape
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint32_t allocatedObjectCount;
|
||||||
|
Shape* *objectList;
|
||||||
|
uint32_t objectCount;
|
||||||
|
|
||||||
|
uint32_t allocatedUnboxableObjectCount;
|
||||||
|
Shape* *unboxableObjectList;
|
||||||
|
uint32_t unboxableObjectCount;
|
||||||
|
|
||||||
|
char name[32 + 1];
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
|
BoundingBox bounds;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isEmpty();
|
||||||
|
|
||||||
|
void addObject(Shape *s);
|
||||||
|
void removeObject(Shape *s);
|
||||||
|
|
||||||
|
Shape *operator[](const int p) { return this->getObject(p); };
|
||||||
|
Shape *getObject(const int p) { return this->objectList[p]; };
|
||||||
|
Shape *getUnboxable(const int p) { return this->unboxableObjectList[p]; };
|
||||||
|
|
||||||
|
void intersect(Ray &r, Intersect &xs);
|
||||||
|
BoundingBox getLocalBounds();
|
||||||
|
BoundingBox getBounds();
|
||||||
|
|
||||||
|
void updateBoundingBox();
|
||||||
|
void updateTransform();
|
||||||
|
|
||||||
|
bool includes(Shape *b);
|
||||||
|
|
||||||
|
uint32_t getObjectCount() { return this->objectCount; };
|
||||||
|
uint32_t getUnboxableCount() { return this->unboxableObjectCount; };
|
||||||
|
|
||||||
|
Group(const char *name = nullptr);
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
|
||||||
|
void setBounds(BoundingBox &bb) { this->bounds | bb; };
|
||||||
|
|
||||||
|
const char *getName() { return this->name; };
|
||||||
|
|
||||||
|
void dumpMe(FILE * fp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_GROUP_H */
|
||||||
@@ -21,6 +21,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
Intersect();
|
Intersect();
|
||||||
~Intersect();
|
~Intersect();
|
||||||
|
void reset();
|
||||||
void add(Intersection i);
|
void add(Intersection i);
|
||||||
int count() { return this->num; };
|
int count() { return this->num; };
|
||||||
Intersection operator[](const int p) { return *this->list[p]; }
|
Intersection operator[](const int p) { return *this->list[p]; }
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
|
#include <material.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
|
||||||
class Shape;
|
class Shape;
|
||||||
class Intersect;
|
class Intersect;
|
||||||
@@ -19,35 +21,11 @@ struct Computation
|
|||||||
{
|
{
|
||||||
Computation(Shape *object, double t, Tuple point, Tuple eyev, Tuple normalv, Tuple 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,
|
bool inside, Tuple reflectV = Vector(0, 0, 0), double n1 = 1.0, double n2 = 1.0,
|
||||||
Tuple underHitP = Point(0, 0, 0)) :
|
Tuple underHitP = Point(0, 0, 0), Material *objMat = nullptr) :
|
||||||
object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside),
|
object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside),
|
||||||
overHitPoint(overHitP), underHitPoint(underHitP), reflectVector(reflectV), n1(n1), n2(n2) { };
|
overHitPoint(overHitP), underHitPoint(underHitP), reflectVector(reflectV), n1(n1), n2(n2), material(objMat) { };
|
||||||
|
|
||||||
double schlick()
|
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;
|
Shape *object;
|
||||||
double t;
|
double t;
|
||||||
@@ -58,6 +36,8 @@ struct Computation
|
|||||||
Tuple normalVector;
|
Tuple normalVector;
|
||||||
Tuple reflectVector;
|
Tuple reflectVector;
|
||||||
|
|
||||||
|
Material *material;
|
||||||
|
|
||||||
double n1;
|
double n1;
|
||||||
double n2;
|
double n2;
|
||||||
|
|
||||||
@@ -69,9 +49,10 @@ class Intersection
|
|||||||
public:
|
public:
|
||||||
double t;
|
double t;
|
||||||
Shape *object;
|
Shape *object;
|
||||||
|
double u, v;
|
||||||
|
|
||||||
public:
|
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); };
|
bool nothing() { return (this->object == nullptr); };
|
||||||
|
|
||||||
Computation prepareComputation(Ray r, Intersect *xs = nullptr);
|
Computation prepareComputation(Ray r, Intersect *xs = nullptr);
|
||||||
|
|||||||
@@ -11,10 +11,17 @@
|
|||||||
|
|
||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
#include <colour.h>
|
#include <colour.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
#include <sequence.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
class World;
|
||||||
|
|
||||||
enum LightType
|
enum LightType
|
||||||
{
|
{
|
||||||
POINT_LIGHT = 0,
|
POINT_LIGHT = 0,
|
||||||
|
AREA_LIGHT,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Light
|
class Light
|
||||||
@@ -24,13 +31,37 @@ public:
|
|||||||
Tuple position;
|
Tuple position;
|
||||||
LightType type;
|
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:
|
public:
|
||||||
Light(LightType type = POINT_LIGHT, Tuple position=Point(0, 0, 0),
|
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 &&
|
bool operator==(const Light &b) const { return this->intensity == b.intensity &&
|
||||||
this->position == b.position &&
|
this->position == b.position &&
|
||||||
this->type == b.type; };
|
this->type == b.type; };
|
||||||
|
|
||||||
|
Tuple pointOnLight(uint32_t u, uint32_t v);
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DORAYME_LIGHT_H */
|
#endif /* DORAYME_LIGHT_H */
|
||||||
|
|||||||
@@ -31,6 +31,14 @@ public:
|
|||||||
if (p == nullptr) { return; }
|
if (p == nullptr) { return; }
|
||||||
|
|
||||||
/* clear up the list */
|
/* clear up the list */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ChainList *next = p->next;
|
||||||
|
free(p);
|
||||||
|
p = next;
|
||||||
|
}
|
||||||
|
while(p != nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Shape *last()
|
Shape *last()
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <colour.h>
|
#include <colour.h>
|
||||||
#include <pattern.h>
|
#include <pattern.h>
|
||||||
#include <light.h>
|
#include <light.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
class Shape;
|
class Shape;
|
||||||
|
|
||||||
@@ -26,21 +27,30 @@ public:
|
|||||||
double shininess;
|
double shininess;
|
||||||
double reflective;
|
double reflective;
|
||||||
double transparency;
|
double transparency;
|
||||||
|
double emissive;
|
||||||
double refractiveIndex;
|
double refractiveIndex;
|
||||||
|
|
||||||
Pattern *pattern;
|
Pattern *pattern;
|
||||||
|
|
||||||
public:
|
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), refractiveIndex(1.0), pattern(nullptr) {};
|
reflective(0.0), transparency(0.0), emissive(0), refractiveIndex(1.0), pattern(nullptr) {};
|
||||||
|
|
||||||
Colour lighting(Light light, Tuple point, Tuple eyeVector, Tuple normalVector, Shape *hitObject, 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) &&
|
bool operator==(const Material &b) const { return double_equal(this->ambient, b.ambient) &&
|
||||||
double_equal(this->diffuse, b.diffuse) &&
|
double_equal(this->diffuse, b.diffuse) &&
|
||||||
double_equal(this->specular, b.specular) &&
|
double_equal(this->specular, b.specular) &&
|
||||||
double_equal(this->shininess, b.shininess) &&
|
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); };
|
(this->colour == b.colour); };
|
||||||
|
bool operator!=(const Material &b) const { return !(*this == b); };
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,4 +18,15 @@ bool double_equal(double a, double b);
|
|||||||
|
|
||||||
double deg_to_rad(double deg);
|
double deg_to_rad(double deg);
|
||||||
|
|
||||||
|
double min3(double a, double b, double c);
|
||||||
|
double max3(double a, double b, double c);
|
||||||
|
|
||||||
|
double frand();
|
||||||
|
double frandclip(double min, double max);
|
||||||
|
|
||||||
|
static double modulo(double a, double b)
|
||||||
|
{
|
||||||
|
return a - floor(a/b) * b;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* DORAYME_MATH_HELPER_H */
|
#endif /* DORAYME_MATH_HELPER_H */
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#undef minor
|
#undef minor
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FastGet4(_x, _y) (this->data[4 * (_x) + (_y)])
|
||||||
|
|
||||||
class Matrix
|
class Matrix
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@@ -46,7 +48,12 @@ public:
|
|||||||
bool isInvertible() { return this->determinant() != 0; }
|
bool isInvertible() { return this->determinant() != 0; }
|
||||||
|
|
||||||
Matrix operator*(const Matrix &b) const;
|
Matrix operator*(const Matrix &b) const;
|
||||||
Tuple operator*(const Tuple &b) const;
|
Tuple operator*(const Tuple &b) const {
|
||||||
|
return Tuple(b.x * FastGet4(0, 0) + b.y * FastGet4(0, 1) + b.z * FastGet4(0, 2) + b.w * FastGet4(0, 3),
|
||||||
|
b.x * FastGet4(1, 0) + b.y * FastGet4(1, 1) + b.z * FastGet4(1, 2) + b.w * FastGet4(1, 3),
|
||||||
|
b.x * FastGet4(2, 0) + b.y * FastGet4(2, 1) + b.z * FastGet4(2, 2) + b.w * FastGet4(2, 3),
|
||||||
|
b.x * FastGet4(3, 0) + b.y * FastGet4(3, 1) + b.z * FastGet4(3, 2) + b.w * FastGet4(3, 3));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Matrix4: public Matrix
|
class Matrix4: public Matrix
|
||||||
|
|||||||
80
source/include/objfile.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* OBJ File header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_OBJFILE_H
|
||||||
|
#define DORAYME_OBJFILE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <tuple.h>
|
||||||
|
#include <shape.h>
|
||||||
|
#include <group.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
|
||||||
|
class OBJFile : public Shape
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Group *baseGroup;
|
||||||
|
|
||||||
|
Group *currentGroup;
|
||||||
|
|
||||||
|
uint32_t allocatedVertexCount;
|
||||||
|
Point* *vertexList;
|
||||||
|
uint32_t vertexCount;
|
||||||
|
|
||||||
|
uint32_t allocatedVertexNormalCount;
|
||||||
|
Vector* *vertexNormalList;
|
||||||
|
uint32_t vertexNormalCount;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/* Some stats */
|
||||||
|
uint32_t ignoredLines;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void addGroup(Group *group);
|
||||||
|
void addVertex(Point *vertex);
|
||||||
|
void addVertexNormal(Vector *vertexNormal);
|
||||||
|
|
||||||
|
void parseLine(char *line, uint32_t currentLine);
|
||||||
|
int execLine(int argc, char *argv[], uint32_t currentLine);
|
||||||
|
BoundingBox bounds;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OBJFile();
|
||||||
|
OBJFile(const char *filepath);
|
||||||
|
|
||||||
|
~OBJFile();
|
||||||
|
|
||||||
|
int parseOBJFile(const char *content);
|
||||||
|
|
||||||
|
/* OBJ file expect the first vertice to be 1 and not 0 */
|
||||||
|
Point vertices(uint32_t i) { return *this->vertexList[i - 1]; };
|
||||||
|
Vector verticesNormal(uint32_t i) { return *this->vertexNormalList[i - 1]; };
|
||||||
|
Group *groups(const char *groupName);
|
||||||
|
void intersect(Ray &r, Intersect &xs);
|
||||||
|
BoundingBox getLocalBounds();
|
||||||
|
BoundingBox getBounds();
|
||||||
|
|
||||||
|
Shape *getBaseGroup() { return this->baseGroup; };
|
||||||
|
|
||||||
|
bool includes(Shape *b);
|
||||||
|
|
||||||
|
void updateBoundingBox();
|
||||||
|
void updateTransform();
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
|
||||||
|
void dumpMe(FILE * fp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OBJ_DEFAULT_GROUP "_DefaultObjGroup_"
|
||||||
|
|
||||||
|
#endif /* DORAYME_OBJFILE_H */
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <colour.h>
|
#include <colour.h>
|
||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
#include <matrix.h>
|
#include <matrix.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
class Shape;
|
class Shape;
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ public:
|
|||||||
Pattern(Colour a, Colour b);
|
Pattern(Colour a, Colour b);
|
||||||
|
|
||||||
virtual Colour patternAt(Tuple point) = 0;
|
virtual Colour patternAt(Tuple point) = 0;
|
||||||
|
virtual void dumpMe(FILE *fp);
|
||||||
|
|
||||||
void setTransform(Matrix transform);
|
void setTransform(Matrix transform);
|
||||||
Colour patternAtObject(Shape *object, Tuple point);
|
Colour patternAtObject(Shape *object, Tuple point);
|
||||||
|
|||||||
@@ -9,14 +9,18 @@
|
|||||||
#ifndef DORAYME_PLANE_H
|
#ifndef DORAYME_PLANE_H
|
||||||
#define DORAYME_PLANE_H
|
#define DORAYME_PLANE_H
|
||||||
|
|
||||||
|
#include <renderstat.h>
|
||||||
|
|
||||||
class Plane : public Shape
|
class Plane : public Shape
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
Intersect localIntersect(Ray r);
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
Tuple localNormalAt(Tuple point);
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Plane() : Shape(SHAPE_PLANE) { };
|
Plane() : Shape(Shape::PLANE) { stats.addPlane(); };
|
||||||
|
BoundingBox getLocalBounds();
|
||||||
|
bool haveFiniteBounds() { return false; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DORAYME_PLANE_H
|
#endif //DORAYME_PLANE_H
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#define DORAYME_RAY_H
|
#define DORAYME_RAY_H
|
||||||
|
|
||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
|
||||||
class Ray
|
class Ray
|
||||||
{
|
{
|
||||||
@@ -17,7 +18,7 @@ public:
|
|||||||
Tuple direction;
|
Tuple direction;
|
||||||
Tuple origin;
|
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; };
|
Tuple position(double t) { return this->origin + this->direction * t; };
|
||||||
};
|
};
|
||||||
|
|||||||
107
source/include/renderstat.h
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Render statistics header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_RENDERSTAT_H
|
||||||
|
#define DORAYME_RENDERSTAT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class RenderStats
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint64_t coneCount; /* Total number of cones */
|
||||||
|
uint64_t cylinderCount; /* Total number of cylinder */
|
||||||
|
uint64_t cubeCount; /* Total number of cubes */
|
||||||
|
uint64_t groupCount; /* Total number of groups */
|
||||||
|
uint64_t lightCount; /* Total number of light */
|
||||||
|
uint64_t planeCount; /* Total number of plane */
|
||||||
|
uint64_t sphereCount; /* Total number of sphere */
|
||||||
|
uint64_t triangleCount; /* Total number of triangle */
|
||||||
|
uint64_t smoothTriangleCount; /* Total number of smooth triangle */
|
||||||
|
uint64_t objfileCount; /* Total number of OBJ File */
|
||||||
|
uint64_t csgCount; /* Total number of CSG */
|
||||||
|
|
||||||
|
uint64_t pixelCount; /* Total number of rendered pixels */
|
||||||
|
uint64_t rayCount; /* Total number of rays object created */
|
||||||
|
uint64_t rayCasted; /* Total number of rays actually casted */
|
||||||
|
uint64_t lightRayEmitedCount; /* Total number of ray launched for light tests */
|
||||||
|
uint64_t reflectionRayCount; /* Total number of reflection ray launched */
|
||||||
|
uint64_t refractedRayCount; /* Total number of refracted ray launched */
|
||||||
|
uint64_t intersectCount; /* Total number of intersect object created */
|
||||||
|
uint64_t intersectionCount; /* Total number of intersection for all casted rays, including light and reflections */
|
||||||
|
uint64_t reallocCallCount; /* Total number of time realloc being called */
|
||||||
|
uint64_t mallocCallCount; /* Total number of time malloc/calloc being called */
|
||||||
|
uint64_t discardedIntersectCount; /* Number of time a bounding box check said "no need to test me" */
|
||||||
|
uint64_t maxDepthAttained; /* Report the lowest depth attained during ray recursion */
|
||||||
|
uint64_t maxIntersectOnARay; /* Biggest intersect done */
|
||||||
|
|
||||||
|
public:
|
||||||
|
RenderStats() : coneCount(0), cylinderCount(0), cubeCount(0), groupCount(0), lightCount(0), planeCount(0), sphereCount(0), triangleCount(0),
|
||||||
|
pixelCount(0), rayCount(0), lightRayEmitedCount(0), reflectionRayCount(0), refractedRayCount(0),
|
||||||
|
intersectCount(0), intersectionCount(0), reallocCallCount(0), mallocCallCount(0), smoothTriangleCount(0),
|
||||||
|
discardedIntersectCount(0), maxDepthAttained(UINT64_MAX), maxIntersectOnARay(0), objfileCount(0),
|
||||||
|
csgCount(0), rayCasted(0) {};
|
||||||
|
#ifdef RENDER_STATS
|
||||||
|
void addCone();
|
||||||
|
void addCylinder();
|
||||||
|
void addCube();
|
||||||
|
void addGroup();
|
||||||
|
void addLight();
|
||||||
|
void addPlane();
|
||||||
|
void addSphere();
|
||||||
|
void addCsg();
|
||||||
|
void addOBJFile();
|
||||||
|
void addTriangle();
|
||||||
|
void addSmoothTriangle();
|
||||||
|
void printStats();
|
||||||
|
void addPixel();
|
||||||
|
void addRay();
|
||||||
|
void addCastedRay();
|
||||||
|
void addLightRay();
|
||||||
|
void addReflectRay();
|
||||||
|
void addRefractRay();
|
||||||
|
void addIntersection();
|
||||||
|
void addDiscardedIntersect();
|
||||||
|
void setMaxDepth(uint32_t depth);
|
||||||
|
void addIntersect();
|
||||||
|
void addMalloc();
|
||||||
|
void addRealloc();
|
||||||
|
void setMaxIntersect(uint32_t count);
|
||||||
|
#else
|
||||||
|
static void addCone() {};
|
||||||
|
static void addCylinder() {};
|
||||||
|
static void addCube() {};
|
||||||
|
static void addGroup() {};
|
||||||
|
static void addLight() {};
|
||||||
|
static void addPlane() {};
|
||||||
|
static void addSphere() {};
|
||||||
|
static void addTriangle() {};
|
||||||
|
static void addSmoothTriangle() {};
|
||||||
|
static void printStats() {};
|
||||||
|
static void addPixel() {};
|
||||||
|
static void addRay() {};
|
||||||
|
static void addCastedRay() {};
|
||||||
|
static void addLightRay() {};
|
||||||
|
static void addReflectRay() {};
|
||||||
|
static void addRefractRay() {};
|
||||||
|
static void addIntersection() {};
|
||||||
|
static void addDiscardedIntersect() {};
|
||||||
|
static void setMaxDepth(uint32_t depth) {};
|
||||||
|
static void addIntersect() {};
|
||||||
|
static void addMalloc() {};
|
||||||
|
static void addRealloc() {};
|
||||||
|
static void setMaxIntersect(uint32_t count) {};
|
||||||
|
static void addOBJFile() {};
|
||||||
|
static void addCsg() {};
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern RenderStats stats;
|
||||||
|
|
||||||
|
#endif /* DORAYME_RENDERSTAT_H */
|
||||||
27
source/include/sequence.h
Normal file
@@ -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 */
|
||||||
@@ -11,44 +11,96 @@
|
|||||||
|
|
||||||
class Shape;
|
class Shape;
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
#include <matrix.h>
|
#include <matrix.h>
|
||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
#include <material.h>
|
#include <material.h>
|
||||||
|
#include <boundingbox.h>
|
||||||
enum ShapeType
|
|
||||||
{
|
|
||||||
SHAPE_NONE,
|
|
||||||
SHAPE_SPHERE,
|
|
||||||
SHAPE_PLANE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Base class for all object that can be presented in the world */
|
/* Base class for all object that can be presented in the world */
|
||||||
class Shape
|
class Shape
|
||||||
{
|
{
|
||||||
private:
|
public:
|
||||||
ShapeType type;
|
enum ShapeType
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
SPHERE,
|
||||||
|
PLANE,
|
||||||
|
CUBE,
|
||||||
|
CYLINDER,
|
||||||
|
CONE,
|
||||||
|
GROUP,
|
||||||
|
TRIANGLE,
|
||||||
|
OBJFILE,
|
||||||
|
SMOOTHTRIANGLE,
|
||||||
|
CSG,
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
virtual Intersect localIntersect(Ray r) = 0;
|
ShapeType type;
|
||||||
virtual Tuple localNormalAt(Tuple point) = 0;
|
Matrix localTransformMatrix;
|
||||||
|
bool locked;
|
||||||
|
uint64_t objectId;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void localIntersect(Ray r, Intersect &xs) = 0;
|
||||||
|
virtual Tuple localNormalAt(Tuple point, Intersection *hit) = 0;
|
||||||
|
|
||||||
|
static uint64_t newObjectId();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Matrix transformMatrix;
|
Matrix transformMatrix;
|
||||||
Matrix inverseTransform;
|
Matrix inverseTransform;
|
||||||
|
Matrix transposedInverseTransform;
|
||||||
|
|
||||||
Material material;
|
Material material;
|
||||||
|
bool dropShadow;
|
||||||
|
Shape *parent;
|
||||||
|
bool materialSet;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Shape(ShapeType = SHAPE_NONE);
|
Shape(ShapeType = Shape::NONE);
|
||||||
|
|
||||||
Intersect intersect(Ray r);
|
ShapeType getType() { return this->type; };
|
||||||
Tuple normalAt(Tuple point);
|
|
||||||
|
virtual void intersect(Ray &r, Intersect &xs) { this->localIntersect(this->invTransform(r), xs); };
|
||||||
|
Tuple normalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
|
uint64_t getObjectId() { return this->objectId; };
|
||||||
|
void setObjectId(uint64_t oid) { this->objectId = oid; };
|
||||||
|
|
||||||
|
/* Bounding box points are always world value */
|
||||||
|
virtual BoundingBox getLocalBounds();
|
||||||
|
virtual BoundingBox getBounds();
|
||||||
|
virtual bool haveFiniteBounds() { return true; };
|
||||||
|
|
||||||
|
virtual void updateTransform();
|
||||||
|
|
||||||
|
virtual bool includes(Shape *b) { return this == b; };
|
||||||
|
|
||||||
|
virtual void dumpMe(FILE *fp);
|
||||||
|
|
||||||
|
/* When an object is locked, the matrix transformation and bounding box can't be updated. This is
|
||||||
|
* usefull to move object between group without changing the real hierarchy between them.
|
||||||
|
* It will also not change the parent member.
|
||||||
|
* This is supposed to be used only before a render is going to start so we can optimise the
|
||||||
|
* way the object are stored to prefer lots of un-needed intersections.
|
||||||
|
*/
|
||||||
|
virtual void lock() { this->locked = true; };
|
||||||
|
|
||||||
|
Tuple worldToObject(Tuple point) { return this->inverseTransform * point; };
|
||||||
|
Tuple objectToWorld(Tuple point) { return this->transformMatrix * point; };
|
||||||
|
Tuple normalToWorld(Tuple normalVector);
|
||||||
|
|
||||||
|
void setParent(Shape *parent) { if (!this->locked) { this->parent = parent; };};
|
||||||
|
|
||||||
void setTransform(Matrix transform);
|
void setTransform(Matrix transform);
|
||||||
void setMaterial(Material material) { this->material = material; };
|
void setMaterial(Material material) { this->material = material; this->materialSet = true; };
|
||||||
Ray transform(Ray r) { return Ray(this->transformMatrix * r.origin, this->transformMatrix * r.direction); };
|
Material *getMaterial();
|
||||||
Ray invTransform(Ray r) { return Ray(this->inverseTransform * r.origin, this->inverseTransform * r.direction); };
|
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 &&
|
bool operator==(const Shape &b) const { return this->material == b.material &&
|
||||||
this->type == b.type &&
|
this->type == b.type &&
|
||||||
|
|||||||
30
source/include/smoothtriangle.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Smooth Triangle header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_SMOOTHTRIANGLE_H
|
||||||
|
#define DORAYME_SMOOTHTRIANGLE_H
|
||||||
|
|
||||||
|
#include <triangle.h>
|
||||||
|
|
||||||
|
class SmoothTriangle : public Triangle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Vector n1;
|
||||||
|
Vector n2;
|
||||||
|
Vector n3;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Tuple localNormalAt(Tuple point, Intersection *hit);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SmoothTriangle(Point p1, Point p2, Point p3, Vector n1, Vector n2, Vector n3);
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_SMOOTHTRIANGLE_H */
|
||||||
@@ -12,16 +12,21 @@
|
|||||||
#include <shape.h>
|
#include <shape.h>
|
||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
class Sphere : public Shape
|
class Sphere : public Shape
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
Intersect localIntersect(Ray r);
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
Tuple localNormalAt(Tuple point);
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
public:
|
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 */
|
/* All sphere are at (0, 0, 0) and radius 1 in the object space */
|
||||||
|
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mostly for test purposes */
|
/* Mostly for test purposes */
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
class TestShape : public Shape
|
class TestShape : public Shape
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Intersect localIntersect(Ray r);
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
Tuple localNormalAt(Tuple point);
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Ray localRay;
|
Ray localRay;
|
||||||
|
|||||||
34
source/include/triangle.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Triangle header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_TRIANGLE_H
|
||||||
|
#define DORAYME_TRIANGLE_H
|
||||||
|
|
||||||
|
#include <shape.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
class Triangle : public Shape
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void localIntersect(Ray r, Intersect &xs);
|
||||||
|
Tuple localNormalAt(Tuple point, Intersection *hit = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Tuple p1, p2, p3;
|
||||||
|
Tuple e1, e2;
|
||||||
|
Tuple normal;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Triangle(Point p1, Point p2, Point p3);
|
||||||
|
BoundingBox getLocalBounds();
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_TRIANGLE_H */
|
||||||
@@ -17,6 +17,7 @@ public:
|
|||||||
double x, y, z, w;
|
double x, y, z, w;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Tuple() : x(0), y(0), z(0), w(0.0) {};
|
||||||
Tuple(double x, double y, double z) : x(x), y(y), z(z), w(0.0) {};
|
Tuple(double x, double y, double z) : x(x), y(y), z(z), w(0.0) {};
|
||||||
Tuple(double x, double y, double z, double w) : x(x), y(y), z(z), w(w) {};
|
Tuple(double x, double y, double z, double w) : x(x), y(y), z(z), w(w) {};
|
||||||
bool isPoint() { return (this->w == 1.0); };
|
bool isPoint() { return (this->w == 1.0); };
|
||||||
@@ -26,6 +27,7 @@ public:
|
|||||||
double_equal(this->y, b.y) &&
|
double_equal(this->y, b.y) &&
|
||||||
double_equal(this->z, b.z) &&
|
double_equal(this->z, b.z) &&
|
||||||
double_equal(this->w, b.w); };
|
double_equal(this->w, b.w); };
|
||||||
|
bool operator!=(const Tuple &b) const { return !(*this == b); };
|
||||||
|
|
||||||
Tuple operator+(const Tuple &b) const { return Tuple(this->x + b.x, this->y + b.y,
|
Tuple operator+(const Tuple &b) const { return Tuple(this->x + b.x, this->y + b.y,
|
||||||
this->z + b.z, this->w + b.w); };
|
this->z + b.z, this->w + b.w); };
|
||||||
@@ -37,23 +39,37 @@ public:
|
|||||||
this->z * b, this->w * b); };
|
this->z * b, this->w * b); };
|
||||||
Tuple operator/(const double &b) const { return Tuple(this->x / b, this->y / b,
|
Tuple operator/(const double &b) const { return Tuple(this->x / b, this->y / b,
|
||||||
this->z / b, this->w / b); };
|
this->z / b, this->w / b); };
|
||||||
|
bool isRepresentable();
|
||||||
|
|
||||||
|
void set(double nX, double nY, double nZ) { this->x = nX; this->y = nY; this->z = nZ; };
|
||||||
double magnitude();
|
double magnitude();
|
||||||
Tuple normalise();
|
Tuple normalise();
|
||||||
double dot(const Tuple &b);
|
|
||||||
Tuple cross(const Tuple &b) const;
|
double dot(const Tuple &b) {
|
||||||
|
return this->x * b.x + this->y * b.y + this->z * b.z + this->w * b.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple cross(const Tuple &b) const {
|
||||||
|
return Tuple(this->y * b.z - this->z * b.y,
|
||||||
|
this->z * b.x - this->x * b.z,
|
||||||
|
this->x * b.y - this->y * b.x,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
Tuple reflect(const Tuple &normal);
|
Tuple reflect(const Tuple &normal);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Point: public Tuple
|
class Point: public Tuple
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Point() : Tuple(0, 0, 0, 1.0) {};
|
||||||
Point(double x, double y, double z) : Tuple(x, y, z, 1.0) {};
|
Point(double x, double y, double z) : Tuple(x, y, z, 1.0) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Vector: public Tuple
|
class Vector: public Tuple
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Vector() : Tuple(0, 0, 0, 0.0) {};
|
||||||
Vector(double x, double y, double z) : Tuple(x, y, z, 0.0) {};
|
Vector(double x, double y, double z) : Tuple(x, y, z, 0.0) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
28
source/include/uv_pattern.h
Normal 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 */
|
||||||
@@ -14,19 +14,30 @@
|
|||||||
#include <shape.h>
|
#include <shape.h>
|
||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <group.h>
|
||||||
|
#include <worldoptimiser.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_LUA_SUPPORT
|
||||||
|
extern "C" {
|
||||||
|
#include <lua.h>
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class World
|
class World
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
uint32_t objectCount;
|
|
||||||
uint32_t lightCount;
|
uint32_t lightCount;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t allocatedObjectCount;
|
|
||||||
uint32_t allocatedLightCount;
|
uint32_t allocatedLightCount;
|
||||||
|
|
||||||
Light* *lightList;
|
Light* *lightList;
|
||||||
Shape* *objectList;
|
|
||||||
|
Group worldGroup;
|
||||||
|
|
||||||
|
#ifdef ENABLE_LUA_SUPPORT
|
||||||
|
lua_State *L;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
World();
|
World();
|
||||||
@@ -39,18 +50,24 @@ public:
|
|||||||
bool lightIsIn(Light &l);
|
bool lightIsIn(Light &l);
|
||||||
bool objectIsIn(Shape &s);
|
bool objectIsIn(Shape &s);
|
||||||
|
|
||||||
Shape *getObject(int i) { return this->objectList[i]; };
|
Shape *getObject(int i) { return this->worldGroup[i]; };
|
||||||
Light *getLight(int i) { return this->lightList[i]; };
|
Light *getLight(int i) { return this->lightList[i]; };
|
||||||
|
|
||||||
|
uint32_t getObjectCount() { return this->worldGroup.getObjectCount(); };
|
||||||
|
uint32_t getLightCount() { return this->lightCount; };
|
||||||
|
|
||||||
Tuple shadeHit(Computation comps, uint32_t depthCount = 4);
|
Tuple shadeHit(Computation comps, uint32_t depthCount = 4);
|
||||||
Tuple colourAt(Ray r, uint32_t depthCount = 4);
|
Tuple colourAt(Ray r, uint32_t depthCount = 4);
|
||||||
bool isShadowed(Tuple point);
|
bool isShadowed(Tuple point, Tuple lightPosition);
|
||||||
|
|
||||||
Colour reflectColour(Computation comps, uint32_t depthCount = 4);
|
Colour reflectColour(Computation comps, uint32_t depthCount = 4);
|
||||||
Colour refractedColour(Computation comps, uint32_t depthCount = 4);
|
Colour refractedColour(Computation comps, uint32_t depthCount = 4);
|
||||||
|
|
||||||
Intersect intersect(Ray r);
|
void intersect(Ray &r, Intersect &xs);
|
||||||
|
|
||||||
|
void finalise(WorldOptimiser &opt);
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DORAYME_WORLD_H */
|
#endif /* DORAYME_WORLD_H */
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#define DORAYME_WORLDBUILDER_H
|
#define DORAYME_WORLDBUILDER_H
|
||||||
|
|
||||||
#include <world.h>
|
#include <world.h>
|
||||||
|
#include <camera.h>
|
||||||
|
|
||||||
/* Let's keep a single header for now, will see later */
|
/* Let's keep a single header for now, will see later */
|
||||||
|
|
||||||
@@ -22,7 +23,30 @@ public:
|
|||||||
/* Not implemented yet */
|
/* Not implemented yet */
|
||||||
class Hw3File : public World
|
class Hw3File : public World
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
Matrix transformStack[50];
|
||||||
|
uint32_t transStackCount;
|
||||||
|
|
||||||
public:
|
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);
|
Hw3File(const char *filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
51
source/include/worldoptimiser.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* World optimiser header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_WORLDOPTIMISER_H
|
||||||
|
#define DORAYME_WORLDOPTIMISER_H
|
||||||
|
|
||||||
|
#include <group.h>
|
||||||
|
|
||||||
|
/* World Optimiser subclasses will created move objects around to try to optimise the raytrace of the world, to
|
||||||
|
* have as least as possible object to intersect per ray.
|
||||||
|
* This class is abstract to we can implement different type and change at runtime or build time
|
||||||
|
*/
|
||||||
|
class WorldOptimiser
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Group *root;
|
||||||
|
void moveInfiniteObjects(Shape *s = nullptr);
|
||||||
|
void moveAllObjects(Shape *s = nullptr);
|
||||||
|
public:
|
||||||
|
void setRoot(Group *root) { this->root = root; };
|
||||||
|
virtual void run() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NoWorldOptimisation : public WorldOptimiser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void run() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class BVHOptimisation : public WorldOptimiser
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void makeTree(Group *leaf, int depth = 0);
|
||||||
|
public:
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
class OctreeOptimisation : public WorldOptimiser
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void makeTree(Group *leaf, int depth = 0);
|
||||||
|
public:
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_WORLDOPTIMISER_H */
|
||||||
@@ -11,19 +11,54 @@
|
|||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
|
||||||
#define MIN_ALLOC (2)
|
#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()
|
Intersect::Intersect()
|
||||||
{
|
{
|
||||||
this->allocated = MIN_ALLOC;
|
this->allocated = MIN_ALLOC;
|
||||||
this->list = (Intersection **)calloc(sizeof(Intersection *), MIN_ALLOC);
|
this->list = (Intersection **)calloc(sizeof(Intersection *), MIN_ALLOC);
|
||||||
|
if (this->list != nullptr)
|
||||||
|
{
|
||||||
|
stats.addMalloc();
|
||||||
|
stats.addIntersect();
|
||||||
this->num = 0;
|
this->num = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ABORT: Allocation error [%s]!\n", __FUNCTION__);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Intersect::~Intersect()
|
Intersect::~Intersect()
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < this->num; i++)
|
||||||
|
{
|
||||||
|
if (this->list[i] != nullptr)
|
||||||
|
{
|
||||||
|
delete this->list[i];
|
||||||
|
this->list[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Free stuff */
|
/* Free stuff */
|
||||||
|
if (this->list != nullptr)
|
||||||
|
{
|
||||||
|
free(this->list);
|
||||||
|
this->list = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Intersect::reset()
|
||||||
|
{
|
||||||
|
this->num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Intersect::add(Intersection i)
|
void Intersect::add(Intersection i)
|
||||||
@@ -34,9 +69,13 @@ void Intersect::add(Intersection i)
|
|||||||
if ((this->num + 1) > this->allocated)
|
if ((this->num + 1) > this->allocated)
|
||||||
{
|
{
|
||||||
this->allocated *= 2;
|
this->allocated *= 2;
|
||||||
|
stats.addRealloc();
|
||||||
this->list = (Intersection **)realloc(this->list, sizeof(Intersection *) * this->allocated);
|
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.. */
|
/* Now sort.. */
|
||||||
for(j = 1; j < (this->num); j++)
|
for(j = 1; j < (this->num); j++)
|
||||||
|
|||||||
@@ -10,13 +10,50 @@
|
|||||||
#include <shape.h>
|
#include <shape.h>
|
||||||
#include <list.h>
|
#include <list.h>
|
||||||
|
|
||||||
|
double Computation::schlick()
|
||||||
|
{
|
||||||
|
/* Find the cos of the angle betzeen the eye and normal vector */
|
||||||
|
double cos = this->eyeVector.dot(this->normalVector);
|
||||||
|
double r0;
|
||||||
|
/* Total internal reflection can only occur when n1 > n2 */
|
||||||
|
if (this->n1 > this->n2)
|
||||||
|
{
|
||||||
|
double n, sin2_t;
|
||||||
|
n = this->n1 / this->n2;
|
||||||
|
sin2_t = (n * n) * (1.0 - (cos * cos));
|
||||||
|
if (sin2_t > 1.0)
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
/* Compute the cos of theta */
|
||||||
|
cos = sqrt(1.0 - sin2_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
r0 = ((this->n1 - this->n2) / (this->n1 + this->n2));
|
||||||
|
r0 = r0 * r0;
|
||||||
|
|
||||||
|
return r0 + (1 - r0) * ((1 - cos)*(1 - cos)*(1 - cos)*(1 - cos)*(1 - cos));
|
||||||
|
};
|
||||||
|
|
||||||
Computation Intersection::prepareComputation(Ray r, Intersect *xs)
|
Computation Intersection::prepareComputation(Ray r, Intersect *xs)
|
||||||
{
|
{
|
||||||
double n1 = 1.0;
|
double n1 = 1.0;
|
||||||
double n2 = 1.0;
|
double n2 = 1.0;
|
||||||
|
|
||||||
Tuple hitP = r.position(this->t);
|
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;
|
Tuple eyeV = -r.direction;
|
||||||
bool inside = false;
|
bool inside = false;
|
||||||
|
|
||||||
@@ -30,10 +67,11 @@ Computation Intersection::prepareComputation(Ray r, Intersect *xs)
|
|||||||
Tuple underHitP = hitP - normalV * getEpsilon();
|
Tuple underHitP = hitP - normalV * getEpsilon();
|
||||||
Tuple reflectV = r.direction.reflect(normalV);
|
Tuple reflectV = r.direction.reflect(normalV);
|
||||||
|
|
||||||
if (xs != nullptr)
|
/* If the hit object is not transparent, there is no need to do that. I think .*/
|
||||||
|
if ((xs != nullptr) && (xs->hit().object->getMaterial()->transparency > 0))
|
||||||
{
|
{
|
||||||
List containers;
|
List containers;
|
||||||
int j, k;
|
int j;
|
||||||
|
|
||||||
for (j = 0 ; j < xs->count() ; j++)
|
for (j = 0 ; j < xs->count() ; j++)
|
||||||
{
|
{
|
||||||
@@ -42,7 +80,7 @@ Computation Intersection::prepareComputation(Ray r, Intersect *xs)
|
|||||||
{
|
{
|
||||||
if (!containers.isEmpty())
|
if (!containers.isEmpty())
|
||||||
{
|
{
|
||||||
n1 = containers.last()->material.refractiveIndex;
|
n1 = containers.last()->getMaterial()->refractiveIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +97,7 @@ Computation Intersection::prepareComputation(Ray r, Intersect *xs)
|
|||||||
{
|
{
|
||||||
if (!containers.isEmpty())
|
if (!containers.isEmpty())
|
||||||
{
|
{
|
||||||
n2 = containers.last()->material.refractiveIndex;
|
n2 = containers.last()->getMaterial()->refractiveIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End the loop */
|
/* End the loop */
|
||||||
@@ -68,6 +106,8 @@ Computation Intersection::prepareComputation(Ray r, Intersect *xs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Material *m = this->object->getMaterial();
|
||||||
|
|
||||||
return Computation(this->object,
|
return Computation(this->object,
|
||||||
this->t,
|
this->t,
|
||||||
hitP,
|
hitP,
|
||||||
@@ -78,5 +118,6 @@ Computation Intersection::prepareComputation(Ray r, Intersect *xs)
|
|||||||
reflectV,
|
reflectV,
|
||||||
n1,
|
n1,
|
||||||
n2,
|
n2,
|
||||||
underHitP);
|
underHitP,
|
||||||
|
m);
|
||||||
}
|
}
|
||||||
@@ -8,10 +8,45 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_sin (lua_State *L) {
|
||||||
|
double d = luaL_checknumber(L, 1); /* get argument */
|
||||||
|
lua_pushnumber(L, sin(d)); /* push result */
|
||||||
|
return 1; /* number of results */
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
printf("Hello !\n");
|
char buff[256];
|
||||||
|
int error;
|
||||||
|
lua_State *L = luaL_newstate(); /* opens Lua */
|
||||||
|
luaL_openlibs(L); /* opens the basic library */
|
||||||
|
|
||||||
|
lua_pushcfunction(L, l_sin);
|
||||||
|
lua_setglobal(L, "mysin");
|
||||||
|
printf("[0]>");
|
||||||
|
|
||||||
|
while (fgets(buff, sizeof(buff), stdin) != NULL)
|
||||||
|
{
|
||||||
|
error = luaL_loadstring(L, buff) || lua_pcall(L, 0, LUA_MULTRET, 0);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s\n", lua_tostring(L, -1));
|
||||||
|
lua_pop(L, 1); /* pop error message from the stack */
|
||||||
|
}
|
||||||
|
printf("[%d]>", lua_gettop(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_close(L);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <math_helper.h>
|
#include <math_helper.h>
|
||||||
@@ -25,6 +26,9 @@ double getEpsilon()
|
|||||||
|
|
||||||
bool double_equal(double a, double b)
|
bool double_equal(double a, double b)
|
||||||
{
|
{
|
||||||
|
if (isinf(a) && isinf(b))
|
||||||
|
return true;
|
||||||
|
|
||||||
return fabs(a - b) < current_precision;
|
return fabs(a - b) < current_precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,3 +36,41 @@ double deg_to_rad(double deg)
|
|||||||
{
|
{
|
||||||
return deg * M_PI / 180.;
|
return deg * M_PI / 180.;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double min3(double a, double b, double c)
|
||||||
|
{
|
||||||
|
if (a <= b)
|
||||||
|
{
|
||||||
|
if (c < a) return c;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (b <= a)
|
||||||
|
{
|
||||||
|
if (c < b) return c;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
double max3(double a, double b, double c)
|
||||||
|
{
|
||||||
|
if (a >= b)
|
||||||
|
{
|
||||||
|
if (c > a) return c;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (b >= a)
|
||||||
|
{
|
||||||
|
if (c > b) return c;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
double frand()
|
||||||
|
{
|
||||||
|
return rand() / ((double) RAND_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
double frandclip(double min, double max)
|
||||||
|
{
|
||||||
|
return (frand() * (max - min)) + min;
|
||||||
|
}
|
||||||
@@ -101,14 +101,18 @@ Matrix Matrix::operator*(const Matrix &b) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#define FastGet4(_x, _y) (this->data[4 * (_x) + (_y)])
|
||||||
|
|
||||||
|
/* TODO: Check if we can optimise this function. It is called a lot */
|
||||||
|
/*
|
||||||
Tuple Matrix::operator*(const Tuple &b) const
|
Tuple Matrix::operator*(const Tuple &b) const
|
||||||
{
|
{
|
||||||
return Tuple(b.x * this->get(0, 0) + b.y * this->get(0, 1) + b.z * this->get(0, 2) + b.w * this->get(0, 3),
|
return Tuple(b.x * FastGet4(0, 0) + b.y * FastGet4(0, 1) + b.z * FastGet4(0, 2) + b.w * FastGet4(0, 3),
|
||||||
b.x * this->get(1, 0) + b.y * this->get(1, 1) + b.z * this->get(1, 2) + b.w * this->get(1, 3),
|
b.x * FastGet4(1, 0) + b.y * FastGet4(1, 1) + b.z * FastGet4(1, 2) + b.w * FastGet4(1, 3),
|
||||||
b.x * this->get(2, 0) + b.y * this->get(2, 1) + b.z * this->get(2, 2) + b.w * this->get(2, 3),
|
b.x * FastGet4(2, 0) + b.y * FastGet4(2, 1) + b.z * FastGet4(2, 2) + b.w * FastGet4(2, 3),
|
||||||
b.x * this->get(3, 0) + b.y * this->get(3, 1) + b.z * this->get(3, 2) + b.w * this->get(3, 3));
|
b.x * FastGet4(3, 0) + b.y * FastGet4(3, 1) + b.z * FastGet4(3, 2) + b.w * FastGet4(3, 3));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
Matrix Matrix::identity()
|
Matrix Matrix::identity()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -123,6 +127,7 @@ Matrix Matrix::transpose()
|
|||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
Matrix ret = Matrix(this->size);
|
Matrix ret = Matrix(this->size);
|
||||||
|
|
||||||
for (y = 0 ; y < this->size ; y++)
|
for (y = 0 ; y < this->size ; y++)
|
||||||
{
|
{
|
||||||
for (x = 0 ; x < this->size ; x++)
|
for (x = 0 ; x < this->size ; x++)
|
||||||
@@ -138,6 +143,7 @@ Matrix Matrix::submatrix(int row, int column)
|
|||||||
int i, j;
|
int i, j;
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
Matrix ret = Matrix(this->size - 1);
|
Matrix ret = Matrix(this->size - 1);
|
||||||
|
|
||||||
for (i = 0 ; i < this->size ; i++)
|
for (i = 0 ; i < this->size ; i++)
|
||||||
{
|
{
|
||||||
if (i == row)
|
if (i == row)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <pattern.h>
|
#include <pattern.h>
|
||||||
#include <shape.h>
|
#include <shape.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
Pattern::Pattern(Colour a, Colour b): a(a), b(b)
|
Pattern::Pattern(Colour a, Colour b): a(a), b(b)
|
||||||
{
|
{
|
||||||
@@ -18,7 +19,7 @@ Pattern::Pattern(Colour a, Colour b): a(a), b(b)
|
|||||||
|
|
||||||
Colour Pattern::patternAtObject(Shape *object, Tuple worldPoint)
|
Colour Pattern::patternAtObject(Shape *object, Tuple worldPoint)
|
||||||
{
|
{
|
||||||
Tuple objectPoint = object->inverseTransform * worldPoint;
|
Tuple objectPoint = object->worldToObject(worldPoint);
|
||||||
Tuple patternPoint = this->inverseTransform * objectPoint;
|
Tuple patternPoint = this->inverseTransform * objectPoint;
|
||||||
|
|
||||||
return this->patternAt(patternPoint);
|
return this->patternAt(patternPoint);
|
||||||
@@ -29,3 +30,9 @@ void Pattern::setTransform(Matrix transform)
|
|||||||
this->transformMatrix = transform;
|
this->transformMatrix = transform;
|
||||||
this->inverseTransform = transform.inverse();
|
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);
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
#ifndef DORAYME_CHECKERSPATTERN_H
|
#ifndef DORAYME_CHECKERSPATTERN_H
|
||||||
#define DORAYME_CHECKERSPATTERN_H
|
#define DORAYME_CHECKERSPATTERN_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
class CheckersPattern : public Pattern
|
class CheckersPattern : public Pattern
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -18,8 +20,14 @@ public:
|
|||||||
{
|
{
|
||||||
double value = floor(point.x) + floor(point.y) + floor(point.z);
|
double value = floor(point.x) + floor(point.y) + floor(point.z);
|
||||||
|
|
||||||
return (fmod(value, 2) == 0)?this->a:this->b;
|
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 */
|
#endif /* DORAYME_CHECKERSPATTERN_H */
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#define DORAYME_GRADIENTPATTERN_H
|
#define DORAYME_GRADIENTPATTERN_H
|
||||||
|
|
||||||
#include <pattern.h>
|
#include <pattern.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
class GradientPattern : public Pattern
|
class GradientPattern : public Pattern
|
||||||
{
|
{
|
||||||
@@ -25,6 +26,12 @@ public:
|
|||||||
|
|
||||||
return Colour(ret.x, ret.y, ret.z);
|
return Colour(ret.x, ret.y, ret.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp) {
|
||||||
|
fprintf(fp, "\"Type\": \"Gradient\",\n");
|
||||||
|
Pattern::dumpMe(fp);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DORAYME_GRADIENTPATTERN_H */
|
#endif /* DORAYME_GRADIENTPATTERN_H */
|
||||||
|
|||||||
107
source/pattern/luapattern.h
Normal 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 */
|
||||||
@@ -22,7 +22,12 @@ public:
|
|||||||
|
|
||||||
double value = floor(sqrt(squared));
|
double value = floor(sqrt(squared));
|
||||||
|
|
||||||
return (fmod(value, 2) == 0)?this->a:this->b;
|
return (modulo(value, 2) == 0)?this->a:this->b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp) {
|
||||||
|
fprintf(fp, "\"Type\": \"Ring\"\n");
|
||||||
|
Pattern::dumpMe(fp);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,17 @@ public:
|
|||||||
|
|
||||||
Colour patternAt(Tuple point)
|
Colour patternAt(Tuple point)
|
||||||
{
|
{
|
||||||
if (fmod(floor(point.x), 2) == 0)
|
if (modulo(floor(point.x), 2) == 0)
|
||||||
{
|
{
|
||||||
return this->a;
|
return this->a;
|
||||||
}
|
}
|
||||||
return this->b;
|
return this->b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp) {
|
||||||
|
fprintf(fp, "\"Type\": \"Strip\",\n");
|
||||||
|
Pattern::dumpMe(fp);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DORAYME_STRIPPATTERN_H */
|
#endif /* DORAYME_STRIPPATTERN_H */
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ public:
|
|||||||
{
|
{
|
||||||
return Colour(point.x, point.y, point.z);
|
return Colour(point.x, point.y, point.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp) {
|
||||||
|
fprintf(fp, "\"Type\": \"Test\",\n");
|
||||||
|
Pattern::dumpMe(fp);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DORAYME_TESTPATTERN_H */
|
#endif /* DORAYME_TESTPATTERN_H */
|
||||||
|
|||||||
198
source/pattern/texturemap.h
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Texture Map header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DORAYME_TEXTUREMAP_H
|
||||||
|
#define DORAYME_TEXTUREMAP_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <tuple.h>
|
||||||
|
#include <uv_pattern.h>
|
||||||
|
#include <colour.h>
|
||||||
|
enum TextureMapType
|
||||||
|
{
|
||||||
|
SPHERICAL_MAP,
|
||||||
|
PLANAR_MAP,
|
||||||
|
CYLINDRICAL_MAP,
|
||||||
|
CUBIC_MAP
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextureMap : public Pattern
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
TextureMapType type;
|
||||||
|
UVPattern *pattern;
|
||||||
|
UVPattern *frontPat, *leftPat, *rightPat, *backPat, *upPat, *downPat;
|
||||||
|
public:
|
||||||
|
TextureMap(TextureMapType type, UVPattern *pattern) : Pattern(Colour(0, 0, 0), Colour(0, 0, 0)),
|
||||||
|
type(type), pattern(pattern) { };
|
||||||
|
|
||||||
|
static void sphericalMap(Tuple point, double &u, double &v) {
|
||||||
|
/* First compute the azimuthal angle
|
||||||
|
* -π < theta <= π
|
||||||
|
* angle increases clockwise as viewed from above,
|
||||||
|
* which is opposite of what we want, but we'll fix it later.
|
||||||
|
*/
|
||||||
|
double theta = atan2(point.x, point.z);
|
||||||
|
|
||||||
|
/* vec is the vector pointing from the sphere's origin (the world origin)
|
||||||
|
* to the point, which will also happen to be exactly equal to the sphere's
|
||||||
|
* radius.
|
||||||
|
*/
|
||||||
|
Tuple vec = Vector(point.x, point.y, point.z);
|
||||||
|
double radius = vec.magnitude();
|
||||||
|
|
||||||
|
/* Let's compute the polar angle
|
||||||
|
* 0 <= phi <= π
|
||||||
|
*/
|
||||||
|
double phi = acos(point.y / radius);
|
||||||
|
|
||||||
|
/* -0.5 < raw_u <= 0.5 */
|
||||||
|
double raw_u = theta / (2 * M_PI);
|
||||||
|
|
||||||
|
/* 0 <= u < 1
|
||||||
|
* here's also where we fix the direction of u. Subtract it from 1,
|
||||||
|
* so that it increases counterclockwise as viewed from above.
|
||||||
|
*/
|
||||||
|
u = 1 - (raw_u + 0.5);
|
||||||
|
|
||||||
|
/* We want v to be 0 at the south pole of the sphere,
|
||||||
|
* and 1 at the north pole, so we have to "flip it over"
|
||||||
|
* by subtracting it from 1.
|
||||||
|
*/
|
||||||
|
v = 1 - phi / M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void planarMap(Tuple point, double &u, double &v) {
|
||||||
|
u = modulo(point.x, 1.0);
|
||||||
|
v = modulo(point.z, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cylindricalMap(Tuple point, double &u, double &v) {
|
||||||
|
/* Let's get the azimuthal angle, same as with the spherical mapping */
|
||||||
|
double theta = atan2(point.x , point.z);
|
||||||
|
double raw_u = theta / (2 * M_PI);
|
||||||
|
|
||||||
|
u = 1 - (raw_u + 0.5);
|
||||||
|
v = modulo(point.y, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CubeFaces {
|
||||||
|
CUBE_LEFT,
|
||||||
|
CUBE_RIGHT,
|
||||||
|
CUBE_FRONT,
|
||||||
|
CUBE_BACK,
|
||||||
|
CUBE_UP,
|
||||||
|
CUBE_DOWN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static CubeFaces faceFromPoint(Tuple point) {
|
||||||
|
double abs_x = fabs(point.x);
|
||||||
|
double abs_y = fabs(point.y);
|
||||||
|
double abs_z = fabs(point.z);
|
||||||
|
|
||||||
|
double coord = max3(abs_x, abs_y, abs_z);
|
||||||
|
|
||||||
|
if (coord == point.x) { return CUBE_RIGHT; }
|
||||||
|
if (coord == -point.x) { return CUBE_LEFT; }
|
||||||
|
if (coord == point.y) { return CUBE_UP; }
|
||||||
|
if (coord == -point.y) { return CUBE_DOWN; }
|
||||||
|
if (coord == point.z) { return CUBE_FRONT; }
|
||||||
|
|
||||||
|
return CUBE_BACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cubeUBFront(Tuple point, double &u, double &v) {
|
||||||
|
u = modulo(point.x + 1, 2.0) / 2.0;
|
||||||
|
v = modulo(point.y + 1, 2.0) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cubeUBBack(Tuple point, double &u, double &v) {
|
||||||
|
u = modulo(1 - point.x, 2.0) / 2.0;
|
||||||
|
v = modulo(point.y + 1, 2.0) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cubeUBLeft(Tuple point, double &u, double &v) {
|
||||||
|
u = modulo(point.z + 1, 2.0) / 2.0;
|
||||||
|
v = modulo(point.y + 1, 2.0) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cubeUBRight(Tuple point, double &u, double &v) {
|
||||||
|
u = modulo(1 - point.z, 2.0) / 2.0;
|
||||||
|
v = modulo(point.y + 1, 2.0) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cubeUBUp(Tuple point, double &u, double &v) {
|
||||||
|
u = modulo(point.x + 1, 2.0) / 2.0;
|
||||||
|
v = modulo(1 - point.z, 2.0) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cubeUBDown(Tuple point, double &u, double &v) {
|
||||||
|
u = modulo(point.x + 1, 2.0) / 2.0;
|
||||||
|
v = modulo(point.z + 1, 2.0) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCubePattern(UVPattern *front, UVPattern *left, UVPattern *right,
|
||||||
|
UVPattern *back, UVPattern *up, UVPattern *down)
|
||||||
|
{
|
||||||
|
this->frontPat = front;
|
||||||
|
this->leftPat = left;
|
||||||
|
this->rightPat = right;
|
||||||
|
this->backPat = back;
|
||||||
|
this->upPat = up;
|
||||||
|
this->downPat = down;
|
||||||
|
}
|
||||||
|
|
||||||
|
Colour patternAt(Tuple point)
|
||||||
|
{
|
||||||
|
double u,v;
|
||||||
|
if (this->type == CUBIC_MAP)
|
||||||
|
{
|
||||||
|
CubeFaces face = TextureMap::faceFromPoint(point);
|
||||||
|
UVPattern *facePat;
|
||||||
|
switch(face)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case CUBE_LEFT: facePat = this->leftPat; TextureMap::cubeUBLeft(point, u, v); break;
|
||||||
|
case CUBE_RIGHT: facePat = this->rightPat; TextureMap::cubeUBRight(point, u, v); break;
|
||||||
|
case CUBE_FRONT: facePat = this->frontPat; TextureMap::cubeUBFront(point, u, v); break;
|
||||||
|
case CUBE_BACK: facePat = this->backPat; TextureMap::cubeUBBack(point, u, v); break;
|
||||||
|
case CUBE_UP: facePat = this->upPat; TextureMap::cubeUBUp(point, u, v); break;
|
||||||
|
case CUBE_DOWN: facePat = this->downPat; TextureMap::cubeUBDown(point, u, v); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return facePat->uvPatternAt(u, v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (this->type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case SPHERICAL_MAP:
|
||||||
|
this->sphericalMap(point, u, v);
|
||||||
|
break;
|
||||||
|
case PLANAR_MAP:
|
||||||
|
this->planarMap(point, u, v);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CYLINDRICAL_MAP:
|
||||||
|
this->cylindricalMap(point, u, v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->pattern->uvPatternAt(u, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpMe(FILE *fp) {
|
||||||
|
fprintf(fp, "\"Type\": \"TextureMap\",\n");
|
||||||
|
Pattern::dumpMe(fp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_TEXTUREMAP_H */
|
||||||
202
source/renderstat.cpp
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Render statistics implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <renderstat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
RenderStats stats;
|
||||||
|
|
||||||
|
#ifdef RENDER_STATS
|
||||||
|
|
||||||
|
void RenderStats::addCone()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->coneCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addCylinder()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->cylinderCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addCube()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->cubeCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addGroup()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->groupCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addLight()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->lightCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addPlane()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->planeCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addSphere()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->sphereCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addTriangle()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->triangleCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addSmoothTriangle()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->smoothTriangleCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addOBJFile()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->objfileCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addPixel()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->pixelCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addRay()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->rayCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addCastedRay()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->rayCasted++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addLightRay()
|
||||||
|
{
|
||||||
|
this->addCastedRay();
|
||||||
|
|
||||||
|
#pragma omp atomic
|
||||||
|
this->lightRayEmitedCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addReflectRay()
|
||||||
|
{
|
||||||
|
this->addCastedRay();
|
||||||
|
|
||||||
|
#pragma omp atomic
|
||||||
|
this->reflectionRayCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addRefractRay()
|
||||||
|
{
|
||||||
|
this->addCastedRay();
|
||||||
|
|
||||||
|
#pragma omp atomic
|
||||||
|
this->refractedRayCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addIntersect()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->intersectCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addIntersection()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->intersectionCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addMalloc()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->mallocCallCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addRealloc()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->reallocCallCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addDiscardedIntersect()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->discardedIntersectCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::addCsg()
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
this->csgCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void RenderStats::setMaxDepth(uint32_t depth)
|
||||||
|
{
|
||||||
|
if (this->maxDepthAttained > depth)
|
||||||
|
{
|
||||||
|
this->maxDepthAttained = depth;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::setMaxIntersect(uint32_t count)
|
||||||
|
{
|
||||||
|
if (this->maxIntersectOnARay < count)
|
||||||
|
{
|
||||||
|
this->maxIntersectOnARay = count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderStats::printStats()
|
||||||
|
{
|
||||||
|
printf("Rendering statistics:\n");
|
||||||
|
printf("Cones : %lld\n", this->coneCount);
|
||||||
|
printf("Cubes : %lld\n", this->cubeCount);
|
||||||
|
printf("Cylinders : %lld\n", this->cylinderCount);
|
||||||
|
printf("Groups : %lld\n", this->groupCount);
|
||||||
|
printf("Lights : %lld\n", this->lightCount);
|
||||||
|
printf("Planes : %lld\n", this->planeCount);
|
||||||
|
printf("Spheres : %lld\n", this->sphereCount);
|
||||||
|
printf("Triangles : %lld\n", this->triangleCount);
|
||||||
|
printf("Smooth Triangles : %lld\n", this->smoothTriangleCount);
|
||||||
|
printf("OBJ File : %lld\n", this->objfileCount);
|
||||||
|
printf("CSG : %lld\n", this->csgCount);
|
||||||
|
printf("==================================================\n");
|
||||||
|
printf("Pixel rendered : %lld\n", this->pixelCount);
|
||||||
|
printf("Ray created : %lld\n", this->rayCount);
|
||||||
|
printf("Ray casted : %lld\n", this->rayCasted);
|
||||||
|
printf("Light Ray casted : %lld\n", this->lightRayEmitedCount);
|
||||||
|
printf("Reflection ray casted : %lld\n", this->reflectionRayCount);
|
||||||
|
printf("Refraction ray casted : %lld\n", this->refractedRayCount);
|
||||||
|
printf("Intersect object created: %lld\n", this->intersectCount);
|
||||||
|
printf("Intersection created : %lld\n", this->intersectionCount);
|
||||||
|
printf("Malloc called : %lld\n", this->mallocCallCount);
|
||||||
|
printf("Realloc called : %lld\n", this->reallocCallCount);
|
||||||
|
printf("Bounding box missed : %lld\n", this->discardedIntersectCount);
|
||||||
|
printf("Min depth attained : %lld\n", this->maxDepthAttained);
|
||||||
|
printf("Max intersect count : %lld\n", this->maxIntersectOnARay);
|
||||||
|
printf("==================================================\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
33
source/sequence.cpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Sequence implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <sequence.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <math_helper.h>
|
||||||
|
|
||||||
|
Sequence::Sequence() : list(nullptr), listPos(0), listSize(0) {
|
||||||
|
/* Need to bootstrap rand here */
|
||||||
|
srand(time(NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
Sequence::Sequence(double *list, uint32_t listSize) : list(list), listPos(0), listSize(listSize) { };
|
||||||
|
|
||||||
|
double Sequence::next() {
|
||||||
|
if (this->listSize == 0)
|
||||||
|
{
|
||||||
|
return frand();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t pos = this->listPos;
|
||||||
|
this->listPos = (this->listPos + 1) % this->listSize;
|
||||||
|
return this->list[pos];
|
||||||
|
}
|
||||||
|
}
|
||||||
146
source/shapes/cone.cpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Cone implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <tuple.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <shape.h>
|
||||||
|
#include <cone.h>
|
||||||
|
#include <math_helper.h>
|
||||||
|
|
||||||
|
bool Cone::checkCap(Ray r, double t, double y)
|
||||||
|
{
|
||||||
|
/* Helping function to reduce duplication.
|
||||||
|
* Checks to see if the intersection ot t is within a radius
|
||||||
|
* of 1 (the radius of our Cone from the y axis
|
||||||
|
*/
|
||||||
|
double x = r.origin.x + t * r.direction.x;
|
||||||
|
double z = r.origin.z + t * r.direction.z;
|
||||||
|
return (x * x + z * z) <= fabs(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cone::intersectCaps(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
/* Caps only mattter is the Cone is closed, and might possibly be
|
||||||
|
* intersected by the ray
|
||||||
|
*/
|
||||||
|
if ((this->isClosed) && (fabs(r.direction.y) > getEpsilon()))
|
||||||
|
{
|
||||||
|
double t;
|
||||||
|
/* Check for an intersection with the lower end cap by intersecting
|
||||||
|
* the ray with the plan at y = this->minCap
|
||||||
|
*/
|
||||||
|
t = (this->minCap - r.origin.y) / r.direction.y;
|
||||||
|
if (this->checkCap(r, t, this->minCap))
|
||||||
|
{
|
||||||
|
xs.add(Intersection(t, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for an intersection with the upper end cap by intersecting
|
||||||
|
* the ray with the plan at y = this->maxCap
|
||||||
|
*/
|
||||||
|
t = (this->maxCap - r.origin.y) / r.direction.y;
|
||||||
|
if (this->checkCap(r, t, this->maxCap))
|
||||||
|
{
|
||||||
|
xs.add(Intersection(t, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cone::localIntersect(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
double A = (r.direction.x * r.direction.x) -
|
||||||
|
(r.direction.y * r.direction.y) +
|
||||||
|
(r.direction.z * r.direction.z);
|
||||||
|
|
||||||
|
double B = (2 * r.origin.x * r.direction.x) -
|
||||||
|
(2 * r.origin.y * r.direction.y) +
|
||||||
|
(2 * r.origin.z * r.direction.z);
|
||||||
|
|
||||||
|
double C = (r.origin.x * r.origin.x) -
|
||||||
|
(r.origin.y * r.origin.y) +
|
||||||
|
(r.origin.z * r.origin.z);
|
||||||
|
|
||||||
|
if ((fabs(A) <= getEpsilon()) && (fabs(B) >= getEpsilon()))
|
||||||
|
{
|
||||||
|
double t = -C / (2*B);
|
||||||
|
xs.add(Intersection(t, this));
|
||||||
|
}
|
||||||
|
else if (fabs(A) >= getEpsilon())
|
||||||
|
{
|
||||||
|
double disc = (B * B) - 4 * A * C;
|
||||||
|
if (disc >= 0)
|
||||||
|
{
|
||||||
|
double t0 = (-B - sqrt(disc)) / (2 * A);
|
||||||
|
double t1 = (-B + sqrt(disc)) / (2 * A);
|
||||||
|
|
||||||
|
double y0 = r.origin.y + t0 * r.direction.y;
|
||||||
|
if ((this->minCap < y0) && (y0 < this->maxCap))
|
||||||
|
{
|
||||||
|
xs.add(Intersection(t0, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
double y1 = r.origin.y + t1 * r.direction.y;
|
||||||
|
if ((this->minCap < y1) && (y1 < this->maxCap))
|
||||||
|
{
|
||||||
|
xs.add(Intersection(t1, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->intersectCaps(r, xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple Cone::localNormalAt(Tuple point, Intersection *hit)
|
||||||
|
{
|
||||||
|
/* Compute the square of the distance from the Y axis */
|
||||||
|
double dist = point.x * point.x + point.z * point.z;
|
||||||
|
|
||||||
|
if ((dist < 1) && (point.y >= (this->maxCap - getEpsilon())))
|
||||||
|
{
|
||||||
|
return Vector(0, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dist < 1) && (point.y <= this->minCap + getEpsilon()))
|
||||||
|
{
|
||||||
|
return Vector(0, -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double y = sqrt(point.x * point.x + point.z * point.z);
|
||||||
|
if (point.y > 0)
|
||||||
|
{
|
||||||
|
y = -y;
|
||||||
|
}
|
||||||
|
return Vector(point.x, y, point.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox Cone::getLocalBounds()
|
||||||
|
{
|
||||||
|
BoundingBox ret;
|
||||||
|
|
||||||
|
double a = fabs(this->minCap);
|
||||||
|
double b = fabs(this->maxCap);
|
||||||
|
double limit = (a > b)?a:b;
|
||||||
|
|
||||||
|
ret | Point(-limit, this->minCap, -limit);
|
||||||
|
ret | Point(limit, this->maxCap, limit);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cone::dumpMe(FILE *fp)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"Type\": \"Cylinder\",\n");
|
||||||
|
Tuple t = this->transformMatrix * Point(0, 0, 0);
|
||||||
|
fprintf(fp, "\"pseudocenter\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
t = this->transformMatrix * Point(0, this->minCap, 0);
|
||||||
|
fprintf(fp, "\"min\": %f, \n", t.y);
|
||||||
|
t = this->transformMatrix * Point(1, this->maxCap, 1);
|
||||||
|
fprintf(fp, "\"max\": %f, \n", t.y);
|
||||||
|
Shape::dumpMe(fp);
|
||||||
|
}
|
||||||
146
source/shapes/csg.cpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Constructive Solid Geometry (CSG) implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <tuple.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <shape.h>
|
||||||
|
#include <csg.h>
|
||||||
|
#include <math_helper.h>
|
||||||
|
|
||||||
|
|
||||||
|
CSG::CSG(OperationType operation, Shape *left, Shape *right) : Shape(Shape::CSG), operation(operation), left(left), right(right)
|
||||||
|
{
|
||||||
|
stats.addCsg();
|
||||||
|
|
||||||
|
this->left->setParent(this);
|
||||||
|
this->right->setParent(this);
|
||||||
|
|
||||||
|
this->bounds | this->left->getBounds();
|
||||||
|
this->bounds | this->right->getBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSG::localIntersect(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
this->intersect(r, xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CSG::intersect(Ray &r, Intersect &xs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Intersect tmp = Intersect();
|
||||||
|
|
||||||
|
if (this->bounds.intesectMe(r))
|
||||||
|
{
|
||||||
|
this->left->intersect(r, tmp);
|
||||||
|
this->right->intersect(r, tmp);
|
||||||
|
|
||||||
|
this->filterIntersections(tmp, xs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple CSG::localNormalAt(Tuple point, Intersection *hit)
|
||||||
|
{
|
||||||
|
return Vector(1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox CSG::getLocalBounds()
|
||||||
|
{
|
||||||
|
return this->bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox CSG::getBounds()
|
||||||
|
{
|
||||||
|
if (this->bounds.isEmpty()) { this->updateBoundingBox(); }
|
||||||
|
return this->bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSG::updateBoundingBox()
|
||||||
|
{
|
||||||
|
this->bounds.reset();
|
||||||
|
|
||||||
|
this->bounds | this->left->getBounds();
|
||||||
|
this->bounds | this->right->getBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSG::updateTransform()
|
||||||
|
{
|
||||||
|
Shape::updateTransform();
|
||||||
|
|
||||||
|
this->left->updateTransform();
|
||||||
|
this->right->updateTransform();
|
||||||
|
|
||||||
|
/* Once the full stack being notified of the changes, let's update the
|
||||||
|
* bounding box
|
||||||
|
*/
|
||||||
|
this->updateBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSG::includes(Shape *b)
|
||||||
|
{
|
||||||
|
if (this->left->includes(b)) { return true; }
|
||||||
|
if (this->right->includes(b)) { return true; }
|
||||||
|
if (this == b) { return true; }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSG::intersectionAllowed(bool leftHit, bool inLeft, bool inRight)
|
||||||
|
{
|
||||||
|
switch(this->operation)
|
||||||
|
{
|
||||||
|
case CSG::UNION: return (leftHit && !inRight) || (!leftHit && !inLeft);
|
||||||
|
case CSG::INTERSECTION: return (!leftHit && inLeft) || (leftHit && inRight);
|
||||||
|
case CSG::DIFFERENCE: return (leftHit && !inRight) || (!leftHit && inLeft);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSG::filterIntersections(Intersect &xs, Intersect &ret)
|
||||||
|
{
|
||||||
|
bool inl = false;
|
||||||
|
bool inr = false;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < xs.count(); i++)
|
||||||
|
{
|
||||||
|
bool lhit = this->left->includes(xs[i].object);
|
||||||
|
|
||||||
|
if (this->intersectionAllowed(lhit, inl, inr))
|
||||||
|
{
|
||||||
|
ret.add(xs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lhit)
|
||||||
|
{
|
||||||
|
inl = !inl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inr = !inr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSG::lock()
|
||||||
|
{
|
||||||
|
Shape::lock();
|
||||||
|
if(this->left)
|
||||||
|
{
|
||||||
|
this->left->lock();
|
||||||
|
}
|
||||||
|
if(this->right)
|
||||||
|
{
|
||||||
|
this->right->lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSG::dumpMe(FILE *fp)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
84
source/shapes/cube.cpp
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Cube implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <tuple.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <shape.h>
|
||||||
|
#include <cube.h>
|
||||||
|
#include <math_helper.h>
|
||||||
|
|
||||||
|
void Cube::checkAxis(double axeOrigin, double axeDirection, double *axeMin, double *axeMax)
|
||||||
|
{
|
||||||
|
double tMinNumerator = (-1 - axeOrigin);
|
||||||
|
double tMaxNumerator = (1 - axeOrigin);
|
||||||
|
|
||||||
|
if (fabs(axeDirection) >= getEpsilon())
|
||||||
|
{
|
||||||
|
*axeMin = tMinNumerator / axeDirection;
|
||||||
|
*axeMax = tMaxNumerator / axeDirection;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*axeMin = tMinNumerator * INFINITY;
|
||||||
|
*axeMax = tMaxNumerator * INFINITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*axeMin > *axeMax)
|
||||||
|
{
|
||||||
|
double swap = *axeMax;
|
||||||
|
*axeMax = *axeMin;
|
||||||
|
*axeMin = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cube::localIntersect(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
double xtMin, xtMax, ytMin, ytMax, ztMin, ztMax;
|
||||||
|
double tMin, tMax;
|
||||||
|
|
||||||
|
this->checkAxis(r.origin.x, r.direction.x, &xtMin, &xtMax);
|
||||||
|
this->checkAxis(r.origin.y, r.direction.y, &ytMin, &ytMax);
|
||||||
|
this->checkAxis(r.origin.z, r.direction.z, &ztMin, &ztMax);
|
||||||
|
|
||||||
|
tMin = max3(xtMin, ytMin, ztMin);
|
||||||
|
tMax = min3(xtMax, ytMax, ztMax);
|
||||||
|
|
||||||
|
if (tMin <= tMax)
|
||||||
|
{
|
||||||
|
xs.add(Intersection(tMin, this));
|
||||||
|
xs.add(Intersection(tMax, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple Cube::localNormalAt(Tuple point, Intersection *hit)
|
||||||
|
{
|
||||||
|
double maxC = max3(fabs(point.x), fabs(point.y), fabs(point.z));
|
||||||
|
|
||||||
|
if (maxC == fabs(point.x))
|
||||||
|
{
|
||||||
|
return Vector(point.x, 0, 0);
|
||||||
|
}
|
||||||
|
else if (maxC == fabs(point.y))
|
||||||
|
{
|
||||||
|
return Vector(0, point.y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vector(0, 0, point.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cube::dumpMe(FILE *fp)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"Type\": \"Cube\",\n");
|
||||||
|
Tuple t = this->transformMatrix * Point(0, 0, 0);
|
||||||
|
fprintf(fp, "\"center\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
t = this->transformMatrix * Point(1, 1, 1);
|
||||||
|
fprintf(fp, "\"corner\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
Shape::dumpMe(fp);
|
||||||
|
}
|
||||||
128
source/shapes/cylinder.cpp
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Cylinder implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <tuple.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <shape.h>
|
||||||
|
#include <cylinder.h>
|
||||||
|
#include <math_helper.h>
|
||||||
|
|
||||||
|
bool Cylinder::checkCap(Ray r, double t)
|
||||||
|
{
|
||||||
|
/* Helping function to reduce duplication.
|
||||||
|
* Checks to see if the intersection ot t is within a radius
|
||||||
|
* of 1 (the radius of our cylinder from the y axis
|
||||||
|
*/
|
||||||
|
double x = r.origin.x + t * r.direction.x;
|
||||||
|
double z = r.origin.z + t * r.direction.z;
|
||||||
|
return (x * x + z * z) <= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cylinder::intersectCaps(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
/* Caps only matter if the cylinder is closed, and might possibly be
|
||||||
|
* intersected by the ray
|
||||||
|
*/
|
||||||
|
if ((this->isClosed) && (fabs(r.direction.y) > getEpsilon()))
|
||||||
|
{
|
||||||
|
double t;
|
||||||
|
/* Check for an intersection with the lower end cap by intersecting
|
||||||
|
* the ray with the plan at y = this->minCap
|
||||||
|
*/
|
||||||
|
t = (this->minCap - r.origin.y) / r.direction.y;
|
||||||
|
if (this->checkCap(r, t))
|
||||||
|
{
|
||||||
|
xs.add(Intersection(t, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for an intersection with the upper end cap by intersecting
|
||||||
|
* the ray with the plan at y = this->maxCap
|
||||||
|
*/
|
||||||
|
t = (this->maxCap - r.origin.y) / r.direction.y;
|
||||||
|
if (this->checkCap(r, t))
|
||||||
|
{
|
||||||
|
xs.add(Intersection(t, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cylinder::localIntersect(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
double A = r.direction.x * r.direction.x + r.direction.z * r.direction.z;
|
||||||
|
|
||||||
|
/* Ray is parallel to the Y axis */
|
||||||
|
if (A >= getEpsilon())
|
||||||
|
{
|
||||||
|
double B = 2 * r.origin.x * r.direction.x +
|
||||||
|
2 * r.origin.z * r.direction.z;
|
||||||
|
double C = r.origin.x * r.origin.x + r.origin.z * r.origin.z - 1;
|
||||||
|
|
||||||
|
double disc = B * B - 4 * A * C;
|
||||||
|
|
||||||
|
if (disc >= 0)
|
||||||
|
{
|
||||||
|
double t0 = (-B - sqrt(disc)) / (2 * A);
|
||||||
|
double t1 = (-B + sqrt(disc)) / (2 * A);
|
||||||
|
|
||||||
|
double y0 = r.origin.y + t0 * r.direction.y;
|
||||||
|
if ((this->minCap < y0) && (y0 < this->maxCap))
|
||||||
|
{
|
||||||
|
xs.add(Intersection(t0, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
double y1 = r.origin.y + t1 * r.direction.y;
|
||||||
|
if ((this->minCap < y1) && (y1 < this->maxCap))
|
||||||
|
{
|
||||||
|
xs.add(Intersection(t1, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->intersectCaps(r, xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple Cylinder::localNormalAt(Tuple point, Intersection *hit)
|
||||||
|
{
|
||||||
|
/* Compute the square of the distance from the Y axis */
|
||||||
|
double dist = point.x * point.x + point.z * point.z;
|
||||||
|
|
||||||
|
if ((dist < 1) && (point.y >= (this->maxCap - getEpsilon())))
|
||||||
|
{
|
||||||
|
return Vector(0, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dist < 1) && (point.y <= this->minCap + getEpsilon()))
|
||||||
|
{
|
||||||
|
return Vector(0, -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vector(point.x, 0, point.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox Cylinder::getLocalBounds()
|
||||||
|
{
|
||||||
|
BoundingBox ret;
|
||||||
|
|
||||||
|
ret | Point(-1, this->minCap, -1);
|
||||||
|
ret | Point(1, this->maxCap, 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cylinder::dumpMe(FILE *fp)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"Type\": \"Cylinder\",\n");
|
||||||
|
Tuple t = this->transformMatrix * Point(0, 0, 0);
|
||||||
|
fprintf(fp, "\"pseudocenter\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
t = this->transformMatrix * Point(0, this->minCap, 0);
|
||||||
|
fprintf(fp, "\"min\": %f, \n", t.y);
|
||||||
|
t = this->transformMatrix * Point(1, this->maxCap, 1);
|
||||||
|
fprintf(fp, "\"max\": %f, \n", t.y);
|
||||||
|
Shape::dumpMe(fp);
|
||||||
|
}
|
||||||
279
source/shapes/group.cpp
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Group implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <tuple.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <group.h>
|
||||||
|
#include <math_helper.h>
|
||||||
|
#include <renderstat.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MIN_ALLOC (2)
|
||||||
|
|
||||||
|
Group::Group(const char *name) : Shape(Shape::GROUP)
|
||||||
|
{
|
||||||
|
stats.addGroup();
|
||||||
|
this->allocatedObjectCount = MIN_ALLOC;
|
||||||
|
this->objectList = (Shape **)calloc(sizeof(Shape **), MIN_ALLOC);
|
||||||
|
this->objectCount = 0;
|
||||||
|
|
||||||
|
this->allocatedUnboxableObjectCount = MIN_ALLOC;
|
||||||
|
this->unboxableObjectList = (Shape **)calloc(sizeof(Shape **), MIN_ALLOC);
|
||||||
|
this->unboxableObjectCount = 0;
|
||||||
|
|
||||||
|
if (name != nullptr)
|
||||||
|
{
|
||||||
|
strncpy(this->name, name, 32);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(this->name, "untitled", 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::intersect(Ray &r, Intersect &xs)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
if (this->objectCount > 0)
|
||||||
|
{
|
||||||
|
if (this->bounds.intesectMe(r))
|
||||||
|
{
|
||||||
|
for (i = 0 ; i < this->objectCount ; i++)
|
||||||
|
{
|
||||||
|
this->objectList[i]->intersect(r, xs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We are force to do them all the time */
|
||||||
|
if (this->unboxableObjectCount > 0)
|
||||||
|
{
|
||||||
|
for(i = 0; i < this->unboxableObjectCount; i++)
|
||||||
|
{
|
||||||
|
this->unboxableObjectList[i]->intersect(r, xs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Group::includes(Shape *b)
|
||||||
|
{
|
||||||
|
if (this->objectCount > 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0 ; i < this->objectCount ; i++)
|
||||||
|
{
|
||||||
|
if (this->objectList[i] == b)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->unboxableObjectCount > 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < this->unboxableObjectCount; i++)
|
||||||
|
{
|
||||||
|
if (this->unboxableObjectList[i] == b)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::localIntersect(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
this->intersect(r, xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple Group::localNormalAt(Tuple point, Intersection *hit)
|
||||||
|
{
|
||||||
|
return Vector(1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ONLY INSERT SHAPES THAT ARE NOT GOING TO CHANGE ELSE..! */
|
||||||
|
void Group::addObject(Shape *s)
|
||||||
|
{
|
||||||
|
if (s->haveFiniteBounds())
|
||||||
|
{
|
||||||
|
if ((this->objectCount + 1) > this->allocatedObjectCount)
|
||||||
|
{
|
||||||
|
this->allocatedObjectCount *= 2;
|
||||||
|
this->objectList = (Shape **)realloc(this->objectList, sizeof(Shape **) * this->allocatedObjectCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->setParent(this);
|
||||||
|
s->updateTransform();
|
||||||
|
|
||||||
|
this->objectList[this->objectCount++] = s;
|
||||||
|
|
||||||
|
this->bounds | s->getBounds();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((this->unboxableObjectCount + 1) > this->allocatedUnboxableObjectCount)
|
||||||
|
{
|
||||||
|
this->allocatedUnboxableObjectCount *= 2;
|
||||||
|
this->unboxableObjectList = (Shape **)realloc(this->unboxableObjectList, sizeof(Shape **) * this->allocatedUnboxableObjectCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->setParent(this);
|
||||||
|
s->updateTransform();
|
||||||
|
|
||||||
|
this->unboxableObjectList[this->unboxableObjectCount++] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::removeObject(Shape *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (s->haveFiniteBounds())
|
||||||
|
{
|
||||||
|
for (i = 0; i < this->objectCount; i++)
|
||||||
|
{
|
||||||
|
if (this->objectList[i] == s)
|
||||||
|
{
|
||||||
|
this->objectCount --;
|
||||||
|
this->objectList[i] = this->objectList[this->objectCount];
|
||||||
|
this->objectList[this->objectCount] = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < this->unboxableObjectCount; i++)
|
||||||
|
{
|
||||||
|
if (this->unboxableObjectList[i] == s)
|
||||||
|
{
|
||||||
|
this->unboxableObjectCount --;
|
||||||
|
this->unboxableObjectList[i] = this->unboxableObjectList[this->unboxableObjectCount];
|
||||||
|
this->unboxableObjectList[this->unboxableObjectCount] = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Group::isEmpty()
|
||||||
|
{
|
||||||
|
return (this->objectCount == 0) && (this->unboxableObjectCount == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox Group::getLocalBounds()
|
||||||
|
{
|
||||||
|
return this->bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox Group::getBounds()
|
||||||
|
{
|
||||||
|
if (this->bounds.isEmpty()) { this->updateBoundingBox(); }
|
||||||
|
return this->bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::updateBoundingBox()
|
||||||
|
{
|
||||||
|
this->bounds.reset();
|
||||||
|
if (this->objectCount > 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < this->objectCount; i++)
|
||||||
|
{
|
||||||
|
if (this->objectList[i]->haveFiniteBounds())
|
||||||
|
{
|
||||||
|
BoundingBox objB = this->objectList[i]->getBounds();
|
||||||
|
this->bounds | objB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::updateTransform()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
Shape::updateTransform();
|
||||||
|
if (this->objectCount > 0)
|
||||||
|
{
|
||||||
|
for (i = 0 ; i < this->objectCount ; i++)
|
||||||
|
{
|
||||||
|
this->objectList[i]->updateTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->unboxableObjectCount > 0)
|
||||||
|
{
|
||||||
|
for(i = 0; i < this->unboxableObjectCount; i++)
|
||||||
|
{
|
||||||
|
this->unboxableObjectList[i]->updateTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Once the full stack being notified of the changes, let's update the
|
||||||
|
* bounding box
|
||||||
|
*/
|
||||||
|
this->updateBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::dumpMe(FILE *fp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fprintf(fp, "\"Type\": \"Group\",\n");
|
||||||
|
fprintf(fp, "\"Name\": \"%s\",\n", this->name);
|
||||||
|
if (this->objectCount > 0)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"Objects\": {\n");
|
||||||
|
for(i = 0; i < this->objectCount; i++)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"%d\": {\n", i);
|
||||||
|
this->objectList[i]->dumpMe(fp);
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
}
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->unboxableObjectCount > 0)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"UnboxableObjects\": {\n");
|
||||||
|
for(i = 0; i < this->objectCount; i++)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"%d\": {\n", i);
|
||||||
|
this->objectList[i]->dumpMe(fp);
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
}
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
}
|
||||||
|
Shape::dumpMe(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::lock()
|
||||||
|
{
|
||||||
|
Shape::lock();
|
||||||
|
|
||||||
|
/* Now notify included object they have to lock */
|
||||||
|
int i;
|
||||||
|
if (this->objectCount > 0)
|
||||||
|
{
|
||||||
|
for (i = 0 ; i < this->objectCount ; i++)
|
||||||
|
{
|
||||||
|
this->objectList[i]->lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->unboxableObjectCount > 0)
|
||||||
|
{
|
||||||
|
for(i = 0; i < this->unboxableObjectCount; i++)
|
||||||
|
{
|
||||||
|
this->unboxableObjectList[i]->lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,3 +6,51 @@
|
|||||||
* Copyright (c) 2020 986-Studio.
|
* 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);
|
||||||
|
}
|
||||||
@@ -11,7 +11,8 @@
|
|||||||
#include <colour.h>
|
#include <colour.h>
|
||||||
#include <shape.h>
|
#include <shape.h>
|
||||||
|
|
||||||
Colour Material::lighting(Light light, Tuple point, Tuple eyeVector, Tuple normalVector, Shape *hitObject, bool inShadow)
|
Colour Material::lighting(Light light, Tuple point, Tuple eyeVector, Tuple normalVector, Shape *hitObject,
|
||||||
|
double lightIntensity)
|
||||||
{
|
{
|
||||||
Colour pointColor = this->colour;
|
Colour pointColor = this->colour;
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ Colour Material::lighting(Light light, Tuple point, Tuple eyeVector, Tuple norma
|
|||||||
|
|
||||||
Tuple effectiveColour = pointColor * light.intensity;
|
Tuple effectiveColour = pointColor * light.intensity;
|
||||||
Tuple ambientColour = Colour(0, 0, 0);
|
Tuple ambientColour = Colour(0, 0, 0);
|
||||||
|
Tuple emissiveColour = Colour(0, 0, 0);
|
||||||
Tuple diffuseColour = Colour(0, 0, 0);
|
Tuple diffuseColour = Colour(0, 0, 0);
|
||||||
Tuple specularColour = Colour(0, 0, 0);
|
Tuple specularColour = Colour(0, 0, 0);
|
||||||
Tuple finalColour = Colour(0, 0, 0);
|
Tuple finalColour = Colour(0, 0, 0);
|
||||||
@@ -33,8 +35,8 @@ Colour Material::lighting(Light light, Tuple point, Tuple eyeVector, Tuple norma
|
|||||||
|
|
||||||
ambientColour = effectiveColour * this->ambient;
|
ambientColour = effectiveColour * this->ambient;
|
||||||
|
|
||||||
if (!inShadow)
|
emissiveColour = pointColor * this->emissive;
|
||||||
{
|
|
||||||
lightDotNormal = lightVector.dot(normalVector);
|
lightDotNormal = lightVector.dot(normalVector);
|
||||||
|
|
||||||
if (lightDotNormal < 0)
|
if (lightDotNormal < 0)
|
||||||
@@ -59,8 +61,30 @@ Colour Material::lighting(Light light, Tuple point, Tuple eyeVector, Tuple norma
|
|||||||
specularColour = light.intensity * this->specular * factor;
|
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);
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
558
source/shapes/objfile.cpp
Normal file
@@ -0,0 +1,558 @@
|
|||||||
|
/*
|
||||||
|
* 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 <sphere.h>
|
||||||
|
#include <smoothtriangle.h>
|
||||||
|
#include <transformation.h>
|
||||||
|
#include <cone.h>
|
||||||
|
#include <cylinder.h>
|
||||||
|
|
||||||
|
#define MIN_ALLOC (2)
|
||||||
|
|
||||||
|
//#define DEBUG_NORMAL
|
||||||
|
|
||||||
|
OBJFile::OBJFile() : Shape(Shape::OBJFILE), ignoredLines(0)
|
||||||
|
{
|
||||||
|
stats.addOBJFile();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* The base group */
|
||||||
|
this->baseGroup = new Group(OBJ_DEFAULT_GROUP);
|
||||||
|
this->currentGroup = this->baseGroup;
|
||||||
|
this->baseGroup->parent = this;
|
||||||
|
};
|
||||||
|
|
||||||
|
OBJFile::~OBJFile()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (vertexCount > 0)
|
||||||
|
{
|
||||||
|
for(i = 0; i < vertexCount; i++)
|
||||||
|
{
|
||||||
|
delete this->vertexList[i];
|
||||||
|
this->vertexList[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(this->vertexList);
|
||||||
|
this->vertexList = nullptr;
|
||||||
|
|
||||||
|
if (vertexNormalCount > 0)
|
||||||
|
{
|
||||||
|
for(i = 0; i < vertexNormalCount; i++)
|
||||||
|
{
|
||||||
|
delete this->vertexNormalList[i];
|
||||||
|
this->vertexNormalList[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(this->vertexNormalList);
|
||||||
|
this->vertexNormalList = nullptr;
|
||||||
|
|
||||||
|
/* It is not our responsibility to clear the group object as this object may be destroyed before the
|
||||||
|
* render is done
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
/* Add one byte to the size to make sure it is null terminated */
|
||||||
|
fileBuff = (char *)calloc(fileSize + 1, 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)
|
||||||
|
{
|
||||||
|
this->baseGroup->addObject(group);
|
||||||
|
|
||||||
|
group->setParent(this);
|
||||||
|
group->updateTransform();
|
||||||
|
this->bounds | group->getBounds();
|
||||||
|
|
||||||
|
this->currentGroup = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Group *OBJFile::groups(const char *groupName)
|
||||||
|
{
|
||||||
|
if (strncmp(groupName, this->baseGroup->getName(), strlen(groupName)) == 0)
|
||||||
|
{
|
||||||
|
return this->baseGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < this->baseGroup->getObjectCount(); i++)
|
||||||
|
{
|
||||||
|
Shape *cur = (*this->baseGroup)[i];
|
||||||
|
|
||||||
|
if (cur->getType() == Shape::GROUP)
|
||||||
|
{
|
||||||
|
Group *curGrp = (Group *)cur;
|
||||||
|
if (strncmp(groupName, curGrp->getName(), strlen(groupName)) == 0)
|
||||||
|
{
|
||||||
|
return curGrp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not found */
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBJFile::intersect(Ray &r, Intersect &xs)
|
||||||
|
{
|
||||||
|
this->baseGroup->intersect(r, xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OBJFile::includes(Shape *b)
|
||||||
|
{
|
||||||
|
return this->baseGroup->includes(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBJFile::localIntersect(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
this->intersect(r, xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
this->bounds | this->baseGroup->getBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBJFile::updateTransform()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
Shape::updateTransform();
|
||||||
|
|
||||||
|
this->baseGroup->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");
|
||||||
|
this->baseGroup->dumpMe(fp);
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
fprintf(fp, "\"Vertices\": {\n");
|
||||||
|
for(i = 1; i < this->vertexCount + 1; i++)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"v[%d]\": { \"x\": %f, \"y\": %f, \"z\": %f },\n", i,
|
||||||
|
this->vertices(i).x, this->vertices(i).y, this->vertices(i).z);
|
||||||
|
}
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
fprintf(fp, "\"NormalVertices\": {\n");
|
||||||
|
for(i = 1; i < this->vertexNormalCount + 1; i++)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"vn[%d]\": { \"x\": %f, \"y\": %f, \"z\": %f },\n", i,
|
||||||
|
this->verticesNormal(i).x, this->verticesNormal(i).y, this->verticesNormal(i).z);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
uint32_t totalLength = strlen(content);
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
if ((bufferPos - content) >= totalLength)
|
||||||
|
{
|
||||||
|
/* We are past the length of the buffer, don't need to continue */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_NORMAL
|
||||||
|
Shape *makeVector(Point pos, Vector verNorm, Colour c, double scale = 1)
|
||||||
|
{
|
||||||
|
Group *ret = new Group("Vector");
|
||||||
|
Sphere *sp = new Sphere();
|
||||||
|
Colour c2 = c;
|
||||||
|
sp->material.colour = c2;
|
||||||
|
sp->material.ambient = 1;
|
||||||
|
sp->material.refractiveIndex = 0;
|
||||||
|
sp->material.reflective = 0;
|
||||||
|
sp->material.specular = 0;
|
||||||
|
sp->materialSet = true;
|
||||||
|
sp->setTransform(translation(pos.x, pos.y, pos.z) * scaling(0.1, 0.1, 0.1));
|
||||||
|
ret->addObject(sp);
|
||||||
|
|
||||||
|
double theta = atan2(verNorm.x, verNorm.z);
|
||||||
|
double radius = verNorm.magnitude();
|
||||||
|
double phi = acos(verNorm.y / radius);
|
||||||
|
|
||||||
|
sp = new Sphere();
|
||||||
|
|
||||||
|
c2 = c;
|
||||||
|
c2.x /=3; c2.y /=3; c2.y /=3;
|
||||||
|
|
||||||
|
sp->material.colour = c2;
|
||||||
|
sp->material.ambient = 1;
|
||||||
|
sp->material.refractiveIndex = 0;
|
||||||
|
sp->material.transparency = 0;
|
||||||
|
sp->material.specular = 0;
|
||||||
|
sp->materialSet = true;
|
||||||
|
sp->setTransform(translation(pos.x, pos.y, pos.z) * translation(verNorm.x, verNorm.y, verNorm.z) * scaling(0.1, 0.1, 0.1));
|
||||||
|
ret->addObject(sp);
|
||||||
|
|
||||||
|
c2 = c;
|
||||||
|
c2.x /=2; c2.y /=3; c2.y /=2;
|
||||||
|
|
||||||
|
Cone *cn = new Cone();
|
||||||
|
cn->minCap = 0;
|
||||||
|
cn->maxCap = 1;
|
||||||
|
cn->material.colour = c2;
|
||||||
|
cn->material.ambient = 1;
|
||||||
|
cn->material.refractiveIndex = 0;
|
||||||
|
cn->material.reflective = 0;
|
||||||
|
cn->material.specular = 0;
|
||||||
|
cn->materialSet = true;
|
||||||
|
cn->setTransform(translation(pos.x, pos.y, pos.z) * rotationY(theta) * rotationX(phi) * scaling(0.1, radius, 0.1));
|
||||||
|
ret->addObject(cn);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_NORMAL
|
||||||
|
this->currentGroup->addObject(makeVector(this->vertices(v[1]),
|
||||||
|
this->verticesNormal(vn[1]),
|
||||||
|
Colour(1, 0, 1)));
|
||||||
|
this->currentGroup->addObject(makeVector(this->vertices(v[2]),
|
||||||
|
this->verticesNormal(vn[2]),
|
||||||
|
Colour(0.5, 0, 0.5)));
|
||||||
|
this->currentGroup->addObject(makeVector(this->vertices(v[3]),
|
||||||
|
this->verticesNormal(vn[3]),
|
||||||
|
Colour(0.5, 0, 1)));
|
||||||
|
#endif
|
||||||
|
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]));
|
||||||
|
}
|
||||||
|
/* Set the object id to the OBJ one */
|
||||||
|
t->setObjectId(this->getObjectId());
|
||||||
|
|
||||||
|
this->currentGroup->addObject(t);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
else if (argc > 4)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_NORMAL
|
||||||
|
if (vn[1] != INT32_MAX)
|
||||||
|
{
|
||||||
|
for(i = 2; i < (argc); i++)
|
||||||
|
{
|
||||||
|
this->currentGroup->addObject(makeVector(this->vertices(v[i]),
|
||||||
|
this->verticesNormal(vn[i]),
|
||||||
|
Colour(1, 1, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
this->currentGroup->addObject(makeVector(this->vertices(v[1]),
|
||||||
|
this->verticesNormal(vn[1]),
|
||||||
|
Colour(0, 1, 0)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
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]));
|
||||||
|
}
|
||||||
|
t->setObjectId(this->getObjectId());
|
||||||
|
this->currentGroup->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(argv[1]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ERROR: Malformed file at line %d: Too few/many parameters!\n", currentLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBJFile::lock()
|
||||||
|
{
|
||||||
|
Shape::lock();
|
||||||
|
|
||||||
|
this->baseGroup->lock();
|
||||||
|
}
|
||||||
@@ -12,25 +12,33 @@
|
|||||||
#include <plane.h>
|
#include <plane.h>
|
||||||
#include <math_helper.h>
|
#include <math_helper.h>
|
||||||
|
|
||||||
Intersect Plane::localIntersect(Ray r)
|
void Plane::localIntersect(Ray r, Intersect &xs)
|
||||||
{
|
{
|
||||||
double t;
|
double t;
|
||||||
Intersect ret = Intersect();
|
|
||||||
|
|
||||||
if (fabs(r.direction.y) < getEpsilon())
|
if (fabs(r.direction.y) < getEpsilon())
|
||||||
{
|
{
|
||||||
/* With a direction == 0, the ray can't intersect the plane */
|
/* With a direction == 0, the ray can't intersect the plane */
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
t = -r.origin.y / r.direction.y;
|
t = -r.origin.y / r.direction.y;
|
||||||
|
|
||||||
ret.add(Intersection(t, this));
|
xs.add(Intersection(t, this));
|
||||||
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple Plane::localNormalAt(Tuple point)
|
Tuple Plane::localNormalAt(Tuple point, Intersection *hit)
|
||||||
{
|
{
|
||||||
return Vector(0, 1, 0);
|
return Vector(0, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BoundingBox Plane::getLocalBounds()
|
||||||
|
{
|
||||||
|
BoundingBox ret;
|
||||||
|
|
||||||
|
ret | Point(-INFINITY, 0-getEpsilon(), -INFINITY);
|
||||||
|
ret | Point(INFINITY, 0+getEpsilon(), INFINITY);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -15,32 +15,122 @@
|
|||||||
|
|
||||||
Shape::Shape(ShapeType type)
|
Shape::Shape(ShapeType type)
|
||||||
{
|
{
|
||||||
|
this->objectId = Shape::newObjectId();
|
||||||
|
this->locked = false;
|
||||||
|
this->parent = nullptr;
|
||||||
|
this->dropShadow = true;
|
||||||
this->type = type;
|
this->type = type;
|
||||||
this->transformMatrix = Matrix4().identity();
|
this->localTransformMatrix = Matrix4().identity();
|
||||||
this->inverseTransform = this->transformMatrix.inverse();
|
this->materialSet = false;
|
||||||
|
|
||||||
|
this->updateTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersect Shape::intersect(Ray r)
|
uint64_t Shape::newObjectId()
|
||||||
{
|
{
|
||||||
return this->localIntersect(this->invTransform(r));
|
static uint64_t id = 0;
|
||||||
};
|
uint64_t ret;
|
||||||
|
|
||||||
Tuple Shape::normalAt(Tuple point)
|
ret = id++;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple Shape::normalToWorld(Tuple normalVector)
|
||||||
{
|
{
|
||||||
Tuple local_point = this->inverseTransform * point;
|
Tuple world_normal = this->transposedInverseTransform * normalVector;
|
||||||
|
|
||||||
Tuple local_normal = this->localNormalAt(local_point);
|
|
||||||
|
|
||||||
Tuple world_normal = this->inverseTransform.transpose() * local_normal;
|
|
||||||
|
|
||||||
/* W may get wrong, so hack it. This is perfectly normal as we are using a 4x4 matrix instead of a 3x3 */
|
/* 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;
|
world_normal.w = 0;
|
||||||
|
|
||||||
return world_normal.normalise();
|
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()
|
||||||
|
{
|
||||||
|
if (this->locked) return;
|
||||||
|
|
||||||
|
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)
|
void Shape::setTransform(Matrix transform)
|
||||||
{
|
{
|
||||||
this->transformMatrix = transform;
|
if (this->locked) return;
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material *Shape::getMaterial()
|
||||||
|
{
|
||||||
|
Shape *s = this;
|
||||||
|
while((!s->materialSet) && (s->parent != nullptr))
|
||||||
|
{
|
||||||
|
s = s->parent;
|
||||||
|
}
|
||||||
|
return &s->material;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shape::dumpMe(FILE *fp)
|
||||||
|
{
|
||||||
|
if (this->materialSet)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"Material\": {\n");
|
||||||
|
this->material.dumpMe(fp);
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
}
|
||||||
|
fprintf(fp, "\"DropShadow\": %d,\n", this->dropShadow);
|
||||||
|
fprintf(fp, "\"Locked\": %d,\n", this->locked);
|
||||||
|
fprintf(fp, "\"MaterialSet\": %d,\n", this->materialSet);
|
||||||
|
if (this->haveFiniteBounds())
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"BoundingBox\": {\n");
|
||||||
|
this->getBounds().dumpMe(fp);
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
}
|
||||||
|
fprintf(fp, "\"id\": %ld,\n", this->getObjectId());
|
||||||
|
if (this->parent)
|
||||||
|
{
|
||||||
|
fprintf(fp, "\"parentId\": %ld,\n", this->parent->getObjectId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
42
source/shapes/smoothtriangle.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmoothTriangle::dumpMe(FILE *fp)
|
||||||
|
{
|
||||||
|
Tuple t = this->n1;
|
||||||
|
fprintf(fp, "\"n1\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
t = this->n2;
|
||||||
|
fprintf(fp, "\"n2\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
t = this->n3;
|
||||||
|
fprintf(fp, "\"n3\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
Triangle::dumpMe(fp);
|
||||||
|
}
|
||||||
@@ -13,9 +13,8 @@
|
|||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
|
|
||||||
Intersect Sphere::localIntersect(Ray r)
|
void Sphere::localIntersect(Ray r, Intersect &xs)
|
||||||
{
|
{
|
||||||
Intersect ret;
|
|
||||||
double a, b, c, discriminant;
|
double a, b, c, discriminant;
|
||||||
|
|
||||||
Tuple sphere_to_ray = r.origin - Point(0, 0, 0);
|
Tuple sphere_to_ray = r.origin - Point(0, 0, 0);
|
||||||
@@ -28,14 +27,24 @@ Intersect Sphere::localIntersect(Ray r)
|
|||||||
|
|
||||||
if (discriminant >= 0)
|
if (discriminant >= 0)
|
||||||
{
|
{
|
||||||
ret.add(Intersection((-b - sqrt(discriminant)) / (2 * a), this));
|
xs.add(Intersection((-b - sqrt(discriminant)) / (2 * a), this));
|
||||||
ret.add(Intersection((-b + sqrt(discriminant)) / (2 * a), this));
|
xs.add(Intersection((-b + sqrt(discriminant)) / (2 * a), this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
Tuple Sphere::localNormalAt(Tuple point, Intersection *hit)
|
||||||
}
|
|
||||||
|
|
||||||
Tuple Sphere::localNormalAt(Tuple point)
|
|
||||||
{
|
{
|
||||||
return (point - Point(0, 0, 0)).normalise();
|
return (point - Point(0, 0, 0)).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);
|
||||||
|
}
|
||||||
@@ -13,13 +13,12 @@ TestShape::TestShape() : localRay(Point(0, 0, 0), Vector(0, 0, 0))
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersect TestShape::localIntersect(Ray r)
|
void TestShape::localIntersect(Ray r, Intersect &xs)
|
||||||
{
|
{
|
||||||
this->localRay = r;
|
this->localRay = r;
|
||||||
return Intersect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple TestShape::localNormalAt(Tuple point)
|
Tuple TestShape::localNormalAt(Tuple point, Intersection *hit)
|
||||||
{
|
{
|
||||||
return Vector(point.x, point.y, point.z);
|
return Vector(point.x, point.y, point.z);
|
||||||
}
|
}
|
||||||
95
source/shapes/triangle.cpp
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Triangle::localIntersect(Ray r, Intersect &xs)
|
||||||
|
{
|
||||||
|
Tuple dirCrossE2 = r.direction.cross(this->e2);
|
||||||
|
double determinant = this->e1.dot(dirCrossE2);
|
||||||
|
if (fabs(determinant) < getEpsilon())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v < 0) || ((u + v) > 1))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double t = f * this->e2.dot(originCrossE1);
|
||||||
|
xs.add(Intersection(t, this, u, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
/* World points*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Local points */
|
||||||
|
t = this->p1;
|
||||||
|
fprintf(fp, "\"lp1\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
t = this->p2;
|
||||||
|
fprintf(fp, "\"lp2\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
t = this->p3;
|
||||||
|
fprintf(fp, "\"lp3\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n",
|
||||||
|
t.x, t.y, t.z);
|
||||||
|
Shape::dumpMe(fp);
|
||||||
|
}
|
||||||
@@ -19,9 +19,14 @@ double Tuple::magnitude()
|
|||||||
Tuple Tuple::normalise()
|
Tuple Tuple::normalise()
|
||||||
{
|
{
|
||||||
double mag = this->magnitude();
|
double mag = this->magnitude();
|
||||||
return Tuple(this->x / mag, this->y / mag, this->z / mag, this->w / mag);
|
if (mag == 0)
|
||||||
|
{
|
||||||
|
return Tuple(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Tuple(this->x / mag, this->y / mag, this->z / mag, this->w / mag);
|
||||||
|
}
|
||||||
|
/*
|
||||||
double Tuple::dot(const Tuple &b)
|
double Tuple::dot(const Tuple &b)
|
||||||
{
|
{
|
||||||
return this->x * b.x + this->y * b.y + this->z * b.z + this->w * b.w;
|
return this->x * b.x + this->y * b.y + this->z * b.z + this->w * b.w;
|
||||||
@@ -34,8 +39,14 @@ Tuple Tuple::cross(const Tuple &b) const
|
|||||||
this->x * b.y - this->y * b.x,
|
this->x * b.y - this->y * b.x,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
Tuple Tuple::reflect(const Tuple &normal)
|
Tuple Tuple::reflect(const Tuple &normal)
|
||||||
{
|
{
|
||||||
return *this - normal * 2 * this->dot(normal);
|
return *this - normal * 2 * this->dot(normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Tuple::isRepresentable()
|
||||||
|
{
|
||||||
|
return !(isnan(this->x) || isnan(this->y) || isnan(this->z) ||
|
||||||
|
isinf(this->x) || isinf(this->y) || isinf(this->z));
|
||||||
|
}
|
||||||
39
source/uvpattern/uv_aligncheck.h
Normal 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 */
|
||||||
32
source/uvpattern/uv_checkers.h
Normal 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 */
|
||||||
43
source/uvpattern/uv_image.h
Normal 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 */
|
||||||
140
source/world.cpp
@@ -9,18 +9,29 @@
|
|||||||
#include <world.h>
|
#include <world.h>
|
||||||
#include <light.h>
|
#include <light.h>
|
||||||
#include <shape.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)
|
#define MIN_ALLOC (2)
|
||||||
|
|
||||||
World::World() : objectCount(0), lightCount(0)
|
World::World() : lightCount(0), worldGroup("World")
|
||||||
{
|
{
|
||||||
this->allocatedLightCount = MIN_ALLOC;
|
this->allocatedLightCount = MIN_ALLOC;
|
||||||
this->lightList = (Light **)calloc(sizeof(Light *), MIN_ALLOC);
|
this->lightList = (Light **)calloc(sizeof(Light *), MIN_ALLOC);
|
||||||
this->lightCount = 0;
|
this->lightCount = 0;
|
||||||
|
|
||||||
this->allocatedObjectCount = MIN_ALLOC;
|
#ifdef ENABLE_LUA_SUPPORT
|
||||||
this->objectList = (Shape **)calloc(sizeof(Shape *), MIN_ALLOC);
|
this->L = luaL_newstate(); /* opens Lua */
|
||||||
this->objectCount = 0;
|
luaL_openlibs(L); /* opens the basic library */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
World::~World()
|
World::~World()
|
||||||
@@ -30,12 +41,10 @@ World::~World()
|
|||||||
|
|
||||||
void World::addObject(Shape *s)
|
void World::addObject(Shape *s)
|
||||||
{
|
{
|
||||||
if ((this->objectCount + 1) > this->allocatedObjectCount)
|
/* Cheaty but need to be done for now */
|
||||||
{
|
s->materialSet = true;
|
||||||
this->allocatedObjectCount *= 2;
|
|
||||||
this->objectList = (Shape **)realloc(this->objectList, sizeof(Shape **) * this->allocatedObjectCount);
|
this->worldGroup.addObject(s);
|
||||||
}
|
|
||||||
this->objectList[this->objectCount++] = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::addLight(Light *l)
|
void World::addLight(Light *l)
|
||||||
@@ -63,53 +72,35 @@ bool World::lightIsIn(Light &l)
|
|||||||
|
|
||||||
bool World::objectIsIn(Shape &s)
|
bool World::objectIsIn(Shape &s)
|
||||||
{
|
{
|
||||||
int i;
|
return this->worldGroup.includes(&s);
|
||||||
for(i = 0; i < this->objectCount; i++)
|
|
||||||
{
|
|
||||||
if (*this->objectList[i] == s)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersect World::intersect(Ray r)
|
void World::intersect(Ray &r, Intersect &xs)
|
||||||
{
|
{
|
||||||
Intersect ret;
|
this->worldGroup.intersect(r, xs);
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for(i = 0; i < this->objectCount; i++)
|
|
||||||
{
|
|
||||||
Intersect xs = this->objectList[i]->intersect(r);
|
|
||||||
|
|
||||||
for(j = 0; j < xs.count(); j++)
|
|
||||||
{
|
|
||||||
ret.add(xs[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple World::shadeHit(Computation comps, uint32_t depthCount)
|
Tuple World::shadeHit(Computation comps, uint32_t depthCount)
|
||||||
{
|
{
|
||||||
/* TODO: Add support for more than one light */
|
uint32_t lightIndex;
|
||||||
|
|
||||||
bool isThereAnObstacle = this->isShadowed(comps.overHitPoint);
|
Tuple surface = Colour(0, 0, 0);
|
||||||
|
|
||||||
Tuple surface = comps.object->material.lighting(*this->lightList[0], comps.overHitPoint, comps.eyeVector,
|
for(lightIndex = 0; lightIndex < this->lightCount; lightIndex++)
|
||||||
comps.normalVector, comps.object, isThereAnObstacle);
|
{
|
||||||
|
double lightLevel = this->lightList[lightIndex]->intensityAt(*this, comps.overHitPoint);
|
||||||
|
|
||||||
|
surface = surface + comps.material->lighting(*this->lightList[lightIndex], comps.overHitPoint, comps.eyeVector,
|
||||||
|
comps.normalVector, comps.object, lightLevel);
|
||||||
|
}
|
||||||
Tuple reflected = this->reflectColour(comps, depthCount);
|
Tuple reflected = this->reflectColour(comps, depthCount);
|
||||||
Tuple refracted = this->refractedColour(comps, depthCount);
|
Tuple refracted = this->refractedColour(comps, depthCount);
|
||||||
|
|
||||||
if ((comps.object->material.reflective > 0) && (comps.object->material.transparency > 0))
|
if ((comps.material->reflective > 0) && (comps.material->transparency > 0))
|
||||||
{
|
{
|
||||||
double reflectance = comps.schlick();
|
double reflectance = comps.schlick();
|
||||||
|
|
||||||
return surface + reflected * reflectance + refracted * (1 - reflectance);
|
return surface + reflected * reflectance + refracted * (1 - reflectance);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return surface + reflected + refracted;
|
return surface + reflected + refracted;
|
||||||
@@ -117,9 +108,12 @@ Tuple World::shadeHit(Computation comps, uint32_t depthCount)
|
|||||||
|
|
||||||
Tuple World::colourAt(Ray r, uint32_t depthCount)
|
Tuple World::colourAt(Ray r, uint32_t depthCount)
|
||||||
{
|
{
|
||||||
Intersect allHits = this->intersect(r);
|
Intersect allHits;
|
||||||
|
this->intersect(r, allHits);
|
||||||
Intersection hit = allHits.hit();
|
Intersection hit = allHits.hit();
|
||||||
|
|
||||||
|
stats.setMaxDepth(depthCount);
|
||||||
|
|
||||||
if (hit.nothing())
|
if (hit.nothing())
|
||||||
{
|
{
|
||||||
return Colour(0, 0, 0);
|
return Colour(0, 0, 0);
|
||||||
@@ -130,37 +124,45 @@ Tuple World::colourAt(Ray r, uint32_t depthCount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::isShadowed(Tuple point)
|
bool World::isShadowed(Tuple point, Tuple lightPosition)
|
||||||
{
|
{
|
||||||
/* TODO: Add support for more than one light */
|
Tuple v = lightPosition - point;
|
||||||
|
|
||||||
Tuple v = this->lightList[0]->position - point;
|
|
||||||
double distance = v.magnitude();
|
double distance = v.magnitude();
|
||||||
Tuple direction = v.normalise();
|
Tuple direction = v.normalise();
|
||||||
|
|
||||||
Ray r = Ray(point, direction);
|
Ray r = Ray(point, direction);
|
||||||
Intersection h = this->intersect(r).hit();
|
stats.addLightRay();
|
||||||
|
Intersect xs;
|
||||||
|
this->intersect(r, xs);
|
||||||
|
|
||||||
if (!h.nothing() && (h.t < distance))
|
int i;
|
||||||
|
for(i = 0; i < xs.count(); i++)
|
||||||
|
{
|
||||||
|
Intersection h = xs[i];
|
||||||
|
|
||||||
|
if (h.t < 0) continue;
|
||||||
|
|
||||||
|
if ((h.object->dropShadow == true) && (h.t < distance))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Colour World::reflectColour(Computation comps, uint32_t depthCount)
|
Colour World::reflectColour(Computation comps, uint32_t depthCount)
|
||||||
{
|
{
|
||||||
if ((depthCount == 0) || (comps.object->material.reflective == 0))
|
if ((depthCount == 0) || (comps.material->reflective == 0))
|
||||||
{
|
{
|
||||||
return Colour(0, 0, 0);
|
return Colour(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* So it is reflective, even just a bit. Let'sr reflect the ray! */
|
/* So it is reflective, even just a bit. Let'sr reflect the ray! */
|
||||||
Ray reflectedRay = Ray(comps.overHitPoint, comps.reflectVector);
|
Ray reflectedRay = Ray(comps.overHitPoint, comps.reflectVector);
|
||||||
|
stats.addReflectRay();
|
||||||
|
|
||||||
Tuple hitColour = this->colourAt(reflectedRay, depthCount - 1);
|
Tuple hitColour = this->colourAt(reflectedRay, depthCount - 1);
|
||||||
hitColour = hitColour * comps.object->material.reflective;
|
hitColour = hitColour * comps.material->reflective;
|
||||||
|
|
||||||
return Colour(hitColour.x, hitColour.y, hitColour.z);
|
return Colour(hitColour.x, hitColour.y, hitColour.z);
|
||||||
}
|
}
|
||||||
@@ -171,7 +173,7 @@ Colour World::refractedColour(Computation comps, uint32_t depthCount)
|
|||||||
double cos_i = comps.eyeVector.dot(comps.normalVector);
|
double cos_i = comps.eyeVector.dot(comps.normalVector);
|
||||||
double sin2_t = (nRatio*nRatio) * (1 - cos_i * cos_i);
|
double sin2_t = (nRatio*nRatio) * (1 - cos_i * cos_i);
|
||||||
|
|
||||||
if ((sin2_t > 1 ) || (depthCount == 0) || (comps.object->material.transparency == 0))
|
if ((sin2_t > 1 ) || (depthCount == 0) || (comps.material->transparency == 0))
|
||||||
{
|
{
|
||||||
return Colour(0, 0, 0);
|
return Colour(0, 0, 0);
|
||||||
}
|
}
|
||||||
@@ -180,8 +182,42 @@ Colour World::refractedColour(Computation comps, uint32_t depthCount)
|
|||||||
Tuple direction = comps.normalVector * (nRatio * cos_i - cos_t) - comps.eyeVector * nRatio;
|
Tuple direction = comps.normalVector * (nRatio * cos_i - cos_t) - comps.eyeVector * nRatio;
|
||||||
|
|
||||||
Ray refractedRay = Ray(comps.underHitPoint, direction);
|
Ray refractedRay = Ray(comps.underHitPoint, direction);
|
||||||
|
stats.addRefractRay();
|
||||||
|
|
||||||
Tuple hitColour = this->colourAt(refractedRay, depthCount - 1) * comps.object->material.transparency;
|
Tuple hitColour = this->colourAt(refractedRay, depthCount - 1) * comps.material->transparency;
|
||||||
|
|
||||||
return Colour(hitColour.x, hitColour.y, hitColour.z);
|
return Colour(hitColour.x, hitColour.y, hitColour.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::finalise(WorldOptimiser &opt)
|
||||||
|
{
|
||||||
|
/* First lock everything */
|
||||||
|
this->worldGroup.lock();
|
||||||
|
|
||||||
|
/* Now run the optimiser */
|
||||||
|
opt.setRoot(&this->worldGroup);
|
||||||
|
opt.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
this->worldGroup.dumpMe(fp);
|
||||||
|
fprintf(fp, "},\n");
|
||||||
|
|
||||||
|
/* JSON Closing */
|
||||||
|
fprintf(fp, "}\n");
|
||||||
|
}
|
||||||
@@ -7,18 +7,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/* Don't build for now */
|
/* Don't build for now */
|
||||||
#if 0
|
|
||||||
/* This file is parsing a text format from another raytracer I made in the past. */
|
/* This file is parsing a text format from another raytracer I made in the past. */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <ctype.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)
|
#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
|
typedef struct cmd_def
|
||||||
{
|
{
|
||||||
@@ -27,111 +29,127 @@ typedef struct cmd_def
|
|||||||
cmdFunc f;
|
cmdFunc f;
|
||||||
} cmd_def;
|
} 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]));
|
w->cam = viewTransform(Point(argv[0], argv[1], argv[2]),
|
||||||
sc->cam.setat(point(argv[3], argv[4], argv[5]));
|
Point(argv[3], argv[4], argv[5]),
|
||||||
sc->cam.setup(vector(argv[6], argv[7], argv[8]));
|
Vector(argv[6], argv[7], argv[8]));
|
||||||
sc->cam.setfovy(argv[9]);
|
|
||||||
|
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 */
|
/* Instanciate a sphere */
|
||||||
sphere *sp = new sphere(point(argv[0], argv[1], argv[2]), argv[3], sc->getMatrix());
|
Sphere *shape = new Sphere();
|
||||||
sp->ambient = sc->ambient;
|
|
||||||
sp->diffuse = sc->diffuse;
|
Matrix pos = translation(argv[0], argv[1], argv[2]) * scaling(argv[3], argv[3], argv[3]);
|
||||||
sp->specular = sc->specular;
|
|
||||||
sp->emission = sc->emission;
|
shape->setTransform(w->getTransformMatrix() * pos);
|
||||||
sp->shininess = sc->shininess;
|
|
||||||
sp->sourceLine = curLine;
|
shape->material.ambient = w->currentAmbient;
|
||||||
sc->o[sc->o_count] = sp;
|
shape->material.reflective = w->currentReflective;
|
||||||
sc->o_count++;
|
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
|
#if 0
|
||||||
void cmdMaxVerts (scene *sc, uint32_t curLine, char *first, float argv[15])
|
static void cmdLDire (Hw3File *w, uint32_t curLine, double 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])
|
|
||||||
{
|
{
|
||||||
/* create directional light */
|
/* create directional light */
|
||||||
light *cur = new light();
|
light *cur = new light();
|
||||||
@@ -145,55 +163,51 @@ void cmdLDire (scene *sc, uint32_t curLine, char *first, float argv[15])
|
|||||||
sc->l[sc->l_count] = cur;
|
sc->l[sc->l_count] = cur;
|
||||||
sc->l_count++;
|
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 */
|
sc->attenuation = Vector(argv[0], argv[1], argv[2]);
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static void cmdMaxVerts (Hw3File *w, uint32_t curLine, double argv[15])
|
||||||
void cmdAtten (scene *sc, uint32_t curLine, char *first, float 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
|
#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 */
|
||||||
{"camera", 10, cmdCamera},
|
{"camera", 10, cmdCamera},
|
||||||
@@ -217,6 +231,7 @@ cmd_def commandList[] =
|
|||||||
{"point", 6, cmdLPoint},
|
{"point", 6, cmdLPoint},
|
||||||
//{ "attenuation", 3, cmdAtten },
|
//{ "attenuation", 3, cmdAtten },
|
||||||
/* Materials */
|
/* Materials */
|
||||||
|
{"color", 3, cmdColour},
|
||||||
{"ambient", 3, cmdAmbient},
|
{"ambient", 3, cmdAmbient},
|
||||||
{"diffuse", 3, cmdDiffuse},
|
{"diffuse", 3, cmdDiffuse},
|
||||||
{"specular", 3, cmdSpecular},
|
{"specular", 3, cmdSpecular},
|
||||||
@@ -226,37 +241,39 @@ cmd_def commandList[] =
|
|||||||
#define CMD_COUNT (sizeof(commandList) / sizeof(cmd_def))
|
#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;
|
FILE *fp;
|
||||||
scene *sc = new scene;
|
|
||||||
if (sc != NULL)
|
this->popTransformMatrix();
|
||||||
{
|
|
||||||
fp = fopen(filename, "rt");
|
fp = fopen(filename, "rt");
|
||||||
if (fp == NULL)
|
if (fp != NULL)
|
||||||
{
|
|
||||||
delete sc;
|
|
||||||
sc = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
int line = 0;
|
int line = 0;
|
||||||
while(!feof(fp))
|
while(!feof(fp))
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
line++;
|
line++;
|
||||||
|
|
||||||
memset(buffer, 0, 512);
|
memset(buffer, 0, 512);
|
||||||
fgets(buffer, 512, fp);
|
fgets(buffer, 512, fp);
|
||||||
|
|
||||||
if ((buffer[0] == '#') || (strlen(buffer) < 2))
|
if ((buffer[0] == '#') || (strlen(buffer) < 2))
|
||||||
|
{
|
||||||
continue; /* Ingore empty line or commented lines */
|
continue; /* Ingore empty line or commented lines */
|
||||||
//printf("::%d:> %s", strlen(buffer), buffer);
|
}
|
||||||
|
|
||||||
for (i = 0; i < CMD_COUNT; i++)
|
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];
|
char first[512];
|
||||||
float value[15];
|
double value[15];
|
||||||
if (commandList[i].numparam != 0)
|
if (commandList[i].numparam != 0)
|
||||||
{
|
{
|
||||||
size_t j;
|
size_t j;
|
||||||
@@ -285,23 +302,45 @@ scene *readfile::read(char *filename)
|
|||||||
if (k != abs(commandList[i].numparam))
|
if (k != abs(commandList[i].numparam))
|
||||||
{
|
{
|
||||||
printf("line %d malformed: given %d parameter, expected %d\n%s", line, k, abs(commandList[i].numparam), buffer);
|
printf("line %d malformed: given %d parameter, expected %d\n%s", line, k, abs(commandList[i].numparam), buffer);
|
||||||
sc = NULL;
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commandList[i].f(sc, line, first, value);
|
commandList[i].f(this, line, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef USE_OCTREE
|
|
||||||
sc->createOctree();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
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;
|
||||||
|
}
|
||||||
124
source/worldoptimiser.cpp
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* WorldOptimiser implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <shape.h>
|
||||||
|
#include <group.h>
|
||||||
|
#include <objfile.h>
|
||||||
|
#include <world.h>
|
||||||
|
#include <worldoptimiser.h>
|
||||||
|
|
||||||
|
/* This function is meant to move all infinite object to the root group */
|
||||||
|
void WorldOptimiser::moveInfiniteObjects(Shape *s)
|
||||||
|
{
|
||||||
|
if (s == nullptr)
|
||||||
|
{
|
||||||
|
s = this->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->getType() == Shape::OBJFILE)
|
||||||
|
{
|
||||||
|
/* Special case */
|
||||||
|
OBJFile *obj = (OBJFile *)s;
|
||||||
|
s = obj->getBaseGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (s->getType() == Shape::GROUP)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Group *grp = (Group *)s;
|
||||||
|
|
||||||
|
if (grp->getUnboxableCount() > 0)
|
||||||
|
{
|
||||||
|
for(i = 0; i < grp->getUnboxableCount(); i++)
|
||||||
|
{
|
||||||
|
Shape *shp = grp->getUnboxable(i);
|
||||||
|
|
||||||
|
if (this->root != s)
|
||||||
|
{
|
||||||
|
if (shp->getType() == Shape::GROUP)
|
||||||
|
{
|
||||||
|
/* Issue a warning if it is a group */
|
||||||
|
printf("WARNING: The group '%s' in '%s' have infinite bounds, all items part of it will not be optimised."
|
||||||
|
"That may affect performances!",
|
||||||
|
((Group *)shp)->getName(),
|
||||||
|
grp->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
this->root->addObject(shp);
|
||||||
|
grp->removeObject(shp);
|
||||||
|
|
||||||
|
/* We remove an object from that list, so need to do some stuffs. */
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now let's traverse the rest of that group */
|
||||||
|
if (grp->getObjectCount() > 0)
|
||||||
|
{
|
||||||
|
for(i = 0; i < grp->getObjectCount(); i++)
|
||||||
|
{
|
||||||
|
Shape *shp = grp->getObject(i);
|
||||||
|
this->moveInfiniteObjects(shp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If it is not a group, there is nothing to be done there. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldOptimiser::moveAllObjects(Shape *s)
|
||||||
|
{
|
||||||
|
if (s == nullptr)
|
||||||
|
{
|
||||||
|
s = this->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->getType() == Shape::OBJFILE)
|
||||||
|
{
|
||||||
|
/* Special case */
|
||||||
|
OBJFile *obj = (OBJFile *)s;
|
||||||
|
s = obj->getBaseGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We should be here only when it is a group, but better being safe. */
|
||||||
|
if (s->getType() == Shape::GROUP)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Group *grp = (Group *)s;
|
||||||
|
|
||||||
|
/* Now let's traverse the rest of that group */
|
||||||
|
if (grp->getObjectCount() > 0)
|
||||||
|
{
|
||||||
|
for(i = 0; i < grp->getObjectCount(); i++)
|
||||||
|
{
|
||||||
|
Shape *shp = grp->getObject(i);
|
||||||
|
switch(shp->getType())
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
/* Don't move if we are on the same leaf */
|
||||||
|
if (this->root != s)
|
||||||
|
{
|
||||||
|
/* It is not a group type object so, move it! */
|
||||||
|
this->root->addObject(shp);
|
||||||
|
grp->removeObject(shp);
|
||||||
|
|
||||||
|
/* We remove an object from that list, so need to do some stuffs. */
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Shape::GROUP:
|
||||||
|
case Shape::OBJFILE:
|
||||||
|
this->moveAllObjects(shp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If it is not a group, there is nothing to be done there. */
|
||||||
|
}
|
||||||
144
source/worldoptimiser/bvhoptimisation.cpp
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* BVH world optimiser implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <worldoptimiser.h>
|
||||||
|
#include <cube.h>
|
||||||
|
#include <objfile.h>
|
||||||
|
#include <transformation.h>
|
||||||
|
|
||||||
|
void BVHOptimisation::makeTree(Group *leaf, int depth)
|
||||||
|
{
|
||||||
|
/* Let's take the bounding box of the root */
|
||||||
|
BoundingBox rootBB = leaf->getBounds();
|
||||||
|
|
||||||
|
double dx = (rootBB.max.x - rootBB.min.x);
|
||||||
|
double dy = (rootBB.max.y - rootBB.min.y);
|
||||||
|
double dz = (rootBB.max.z - rootBB.min.z);
|
||||||
|
/* Take the mid value for each axes */
|
||||||
|
Tuple midMin = rootBB.min;
|
||||||
|
Tuple midMax = rootBB.max;
|
||||||
|
|
||||||
|
BoundingBox SlicesBB[2];
|
||||||
|
int sliceIdx;
|
||||||
|
Group *Slices[2];
|
||||||
|
|
||||||
|
double largestSide = max3(dx, dy, dz);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (largestSide == dx)
|
||||||
|
{
|
||||||
|
midMin.x = rootBB.min.x + dx / 2.0;
|
||||||
|
midMax.x = rootBB.min.x + dx / 2.0;
|
||||||
|
}
|
||||||
|
else if (largestSide == dy)
|
||||||
|
{
|
||||||
|
midMin.y = rootBB.min.y + dy / 2.0;
|
||||||
|
midMax.y = rootBB.min.y + dy / 2.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
midMin.z = rootBB.min.z + dx / 2.0;
|
||||||
|
midMax.z = rootBB.min.z + dx / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Split the main bounding box into 8 boxes */
|
||||||
|
SlicesBB[0] | rootBB.min;
|
||||||
|
SlicesBB[0] | midMax;
|
||||||
|
|
||||||
|
SlicesBB[1] | rootBB.max;
|
||||||
|
SlicesBB[1] | midMin;
|
||||||
|
|
||||||
|
|
||||||
|
for (sliceIdx = 0 ; sliceIdx < 2 ; sliceIdx++)
|
||||||
|
{
|
||||||
|
Slices[sliceIdx] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0 ; i < leaf->getObjectCount(); i++)
|
||||||
|
{
|
||||||
|
Shape *shp = leaf->getObject(i);
|
||||||
|
BoundingBox objBB = shp->getBounds();
|
||||||
|
|
||||||
|
for (sliceIdx = 0 ; sliceIdx < 2 ; sliceIdx++)
|
||||||
|
{
|
||||||
|
if (SlicesBB[sliceIdx].fitsIn(objBB))
|
||||||
|
{
|
||||||
|
if (Slices[sliceIdx] == nullptr)
|
||||||
|
{
|
||||||
|
char name[32];
|
||||||
|
snprintf(name, 32, "%d_Slice %d", depth, sliceIdx);
|
||||||
|
Slices[sliceIdx] = new Group(name);
|
||||||
|
|
||||||
|
Slices[sliceIdx]->setBounds(SlicesBB[sliceIdx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Slices[sliceIdx]->addObject(shp);
|
||||||
|
leaf->removeObject(shp);
|
||||||
|
|
||||||
|
i -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shp->getType() == Shape::GROUP)
|
||||||
|
{
|
||||||
|
this->makeTree((Group *)shp, depth + 1);
|
||||||
|
}
|
||||||
|
else if (shp->getType() == Shape::OBJFILE)
|
||||||
|
{
|
||||||
|
this->makeTree((Group *)((OBJFile *)shp)->getBaseGroup(), depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now add the quadrant to the root and recurse in it */
|
||||||
|
for (sliceIdx = 0 ; sliceIdx < 2 ; sliceIdx++)
|
||||||
|
{
|
||||||
|
if (Slices[sliceIdx] != nullptr)
|
||||||
|
{
|
||||||
|
this->makeTree(Slices[sliceIdx], depth + 1);
|
||||||
|
|
||||||
|
Slices[sliceIdx]->updateBoundingBox();
|
||||||
|
|
||||||
|
leaf->addObject(Slices[sliceIdx]);
|
||||||
|
#if 0
|
||||||
|
Cube *cb = new Cube();
|
||||||
|
double sx = SlicesBB[sliceIdx].max.x - SlicesBB[sliceIdx].min.x;
|
||||||
|
double sy = SlicesBB[sliceIdx].max.y - SlicesBB[sliceIdx].min.y;
|
||||||
|
double sz = SlicesBB[sliceIdx].max.z - SlicesBB[sliceIdx].min.z;
|
||||||
|
|
||||||
|
cb->setTransform(translation(SlicesBB[sliceIdx].min.x, SlicesBB[sliceIdx].min.y,
|
||||||
|
SlicesBB[sliceIdx].min.z) * scaling(sx, sy, sz));
|
||||||
|
cb->material.colour = Colour(0.01, 0.01, 0);
|
||||||
|
cb->materialSet = true;
|
||||||
|
cb->dropShadow = false;
|
||||||
|
cb->material.ambient = 0.1;
|
||||||
|
cb->material.reflective = 0;
|
||||||
|
cb->material.transparency = 0.95;
|
||||||
|
cb->material.refractiveIndex = 1;
|
||||||
|
cb->material.specular = 0;
|
||||||
|
leaf->addObject(cb);
|
||||||
|
|
||||||
|
printf("%s: %d objs\n", Slices[sliceIdx]->getName(),
|
||||||
|
Slices[sliceIdx]->getObjectCount());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BVHOptimisation::run()
|
||||||
|
{
|
||||||
|
/* First let's clear our hands */
|
||||||
|
this->moveInfiniteObjects();
|
||||||
|
|
||||||
|
/* Then let's have some fun! */
|
||||||
|
//this->moveAllObjects();
|
||||||
|
|
||||||
|
/* Now.. The fun start ! */
|
||||||
|
makeTree(this->root, 0);
|
||||||
|
}
|
||||||
141
source/worldoptimiser/octreeoptimisation.cpp
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Octree world optimiser implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <worldoptimiser.h>
|
||||||
|
#include <cube.h>
|
||||||
|
#include <objfile.h>
|
||||||
|
#include <transformation.h>
|
||||||
|
|
||||||
|
void OctreeOptimisation::makeTree(Group *leaf, int depth)
|
||||||
|
{
|
||||||
|
/* Let's take the bounding box of the root */
|
||||||
|
BoundingBox rootBB = leaf->getBounds();
|
||||||
|
|
||||||
|
/* Take the mid value for each axes */
|
||||||
|
double midX = (rootBB.max.x - rootBB.min.x) / 2.0 + rootBB.min.x;
|
||||||
|
double midY = (rootBB.max.y - rootBB.min.y) / 2.0 + rootBB.min.y;
|
||||||
|
double midZ = (rootBB.max.z - rootBB.min.z) / 2.0 + rootBB.min.z;
|
||||||
|
BoundingBox octantBB[8];
|
||||||
|
int octantIdx;
|
||||||
|
Group *octants[8];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
/* Split the main bounding box into 8 boxes */
|
||||||
|
octantBB[0] | Point(rootBB.min.x, rootBB.min.y, rootBB.min.z);
|
||||||
|
octantBB[0] | Point(midX, midY, midZ);
|
||||||
|
|
||||||
|
octantBB[1] | Point(midX, rootBB.min.y, rootBB.min.z);
|
||||||
|
octantBB[1] | Point(rootBB.max.x, midY, midZ);
|
||||||
|
|
||||||
|
octantBB[2] | Point(rootBB.min.x, midY, rootBB.min.z);
|
||||||
|
octantBB[2] | Point(midX, rootBB.max.y, midZ);
|
||||||
|
|
||||||
|
octantBB[3] | Point(midX, midY, rootBB.min.z);
|
||||||
|
octantBB[3] | Point(rootBB.max.x, rootBB.max.y, midZ);
|
||||||
|
|
||||||
|
octantBB[4] | Point(rootBB.min.x, midY, midZ);
|
||||||
|
octantBB[4] | Point(midX, rootBB.max.y, rootBB.max.z);
|
||||||
|
|
||||||
|
octantBB[5] | Point(midX, midY, midZ);
|
||||||
|
octantBB[5] | Point(rootBB.max.x, rootBB.max.y, rootBB.max.z);
|
||||||
|
|
||||||
|
octantBB[6] | Point(rootBB.min.x, rootBB.min.y, midZ);
|
||||||
|
octantBB[6] | Point(midX, midY, rootBB.max.z);
|
||||||
|
|
||||||
|
octantBB[7] | Point(midX, rootBB.min.y, midZ);
|
||||||
|
octantBB[7] | Point(rootBB.max.x, midY, rootBB.max.z);
|
||||||
|
|
||||||
|
for (octantIdx = 0 ; octantIdx < 8 ; octantIdx++)
|
||||||
|
{
|
||||||
|
octants[octantIdx] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0 ; i < leaf->getObjectCount(); i++)
|
||||||
|
{
|
||||||
|
Shape *shp = leaf->getObject(i);
|
||||||
|
|
||||||
|
BoundingBox objBB = shp->getBounds();
|
||||||
|
//if ((shp->getType() != Shape::GROUP) && (shp->getType() != Shape::OBJFILE))
|
||||||
|
for (octantIdx = 0 ; octantIdx < 8 ; octantIdx++)
|
||||||
|
{
|
||||||
|
if (octantBB[octantIdx].fitsIn(objBB))
|
||||||
|
{
|
||||||
|
if (octants[octantIdx] == nullptr)
|
||||||
|
{
|
||||||
|
char name[32];
|
||||||
|
snprintf(name, 32, "%d_Quadrant %d", depth, octantIdx);
|
||||||
|
octants[octantIdx] = new Group(name);
|
||||||
|
|
||||||
|
octants[octantIdx]->setBounds(octantBB[octantIdx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
octants[octantIdx]->addObject(shp);
|
||||||
|
leaf->removeObject(shp);
|
||||||
|
|
||||||
|
i -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shp->getType() == Shape::GROUP)
|
||||||
|
{
|
||||||
|
this->makeTree((Group *)shp, depth + 1);
|
||||||
|
}
|
||||||
|
if (shp->getType() == Shape::OBJFILE)
|
||||||
|
{
|
||||||
|
this->makeTree((Group *)((OBJFile *)shp)->getBaseGroup(), depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now add the quadrant to the root and recurse in it */
|
||||||
|
for (octantIdx = 0 ; octantIdx < 8 ; octantIdx++)
|
||||||
|
{
|
||||||
|
if (octants[octantIdx] != nullptr)
|
||||||
|
{
|
||||||
|
this->makeTree(octants[octantIdx], depth + 1);
|
||||||
|
|
||||||
|
octants[octantIdx]->updateBoundingBox();
|
||||||
|
|
||||||
|
leaf->addObject(octants[octantIdx]);
|
||||||
|
#if 0
|
||||||
|
Cube *cb = new Cube();
|
||||||
|
double sx = octantBB[octantIdx].max.x - octantBB[octantIdx].min.x;
|
||||||
|
double sy = octantBB[octantIdx].max.y - octantBB[octantIdx].min.y;
|
||||||
|
double sz = octantBB[octantIdx].max.z - octantBB[octantIdx].min.z;
|
||||||
|
|
||||||
|
cb->setTransform(translation(octantBB[octantIdx].min.x, octantBB[octantIdx].min.y,
|
||||||
|
octantBB[octantIdx].min.z) * scaling(sx, sy, sz));
|
||||||
|
cb->material.colour = Colour(0.01, 0.01, 0);
|
||||||
|
cb->materialSet = true;
|
||||||
|
cb->dropShadow = false;
|
||||||
|
cb->material.ambient = 0.1;
|
||||||
|
cb->material.reflective = 0;
|
||||||
|
cb->material.transparency = 0.95;
|
||||||
|
cb->material.refractiveIndex = 1;
|
||||||
|
cb->material.specular = 0;
|
||||||
|
leaf->addObject(cb);
|
||||||
|
|
||||||
|
printf("%s: %d objs\n", octants[octantIdx]->getName(),
|
||||||
|
octants[octantIdx]->getObjectCount());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctreeOptimisation::run()
|
||||||
|
{
|
||||||
|
/* First let's clear our hands */
|
||||||
|
this->moveInfiniteObjects();
|
||||||
|
|
||||||
|
/* Then let's have some fun! */
|
||||||
|
//this->moveAllObjects();
|
||||||
|
|
||||||
|
/* Now.. The fun start ! */
|
||||||
|
makeTree(this->root, 0);
|
||||||
|
}
|
||||||