Compare commits
50 commits
shader-exp
...
master
Author | SHA1 | Date | |
---|---|---|---|
4994a23a8a | |||
159e9ca843 | |||
8988af2e0f | |||
|
2d996602a4 | ||
|
e4305190ea | ||
|
a99159dc53 | ||
4baf2901bb | |||
a4d7ccc1a5 | |||
9b07411ebd | |||
9837920c38 | |||
9608281164 | |||
|
ed47dc2b9b | ||
ffaaa7e814 | |||
dd92e85861 | |||
|
133f8444d2 | ||
|
6159650a00 | ||
c1bae8a43c | |||
9b228bff61 | |||
81e9a162be | |||
79446c289b | |||
d7c093944d | |||
|
128581d469 | ||
|
ce1fe4dd9a | ||
|
f5347bb07a | ||
3f3c89b0d0 | |||
ec59f251c7 | |||
cc5b66e338 | |||
8a1ec659a2 | |||
|
f24011f642 | ||
|
0d4814c901 | ||
|
9dd5878f31 | ||
da1f885e9a | |||
5db502d77a | |||
17fd35fe76 | |||
dcae587b8c | |||
3b76969ff2 | |||
7ec5a8a5f4 | |||
|
9a8d6bcccd | ||
d7d38944ea | |||
e5575c03f5 | |||
0c7071524a | |||
66959c3599 | |||
0eef1f8e6e | |||
a90441c255 | |||
53a4a6d1f0 | |||
98c3f97eea | |||
1dd7d845d9 | |||
3b644c8d29 | |||
720aafbb9a | |||
a374c31938 |
59 changed files with 12461 additions and 132 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -7,6 +7,8 @@ build/
|
||||||
/data/*
|
/data/*
|
||||||
!/data/README.txt
|
!/data/README.txt
|
||||||
!/data/fireplace
|
!/data/fireplace
|
||||||
|
!/data/FancyPlane
|
||||||
|
!/data/Bus
|
||||||
!/data/subdiv
|
!/data/subdiv
|
||||||
!/data/parallax
|
!/data/parallax
|
||||||
!/data/fractal.obj
|
!/data/fractal.obj
|
||||||
|
|
|
@ -17,32 +17,45 @@ endif()
|
||||||
|
|
||||||
# which source files to use
|
# which source files to use
|
||||||
file(GLOB common_src "common/*.cpp")
|
file(GLOB common_src "common/*.cpp")
|
||||||
|
file(GLOB noise_src "common/noise/*.cpp")
|
||||||
file(GLOB camera_src "camera/*.cpp")
|
file(GLOB camera_src "camera/*.cpp")
|
||||||
file(GLOB light_src "light/*.cpp")
|
file(GLOB light_src "light/*.cpp")
|
||||||
file(GLOB primitive_src "primitive/*.cpp")
|
file(GLOB primitive_src "primitive/*.cpp")
|
||||||
file(GLOB renderer_src "renderer/*.cpp")
|
file(GLOB renderer_src "renderer/*.cpp")
|
||||||
file(GLOB scene_src "scene/*.cpp")
|
file(GLOB scene_src "scene/*.cpp")
|
||||||
file(GLOB shader_src "shader/*.cpp")
|
file(GLOB shader_src "shader/*.cpp")
|
||||||
|
file(GLOB post_processing_src "post_processing/*.cpp")
|
||||||
|
file(GLOB homework_src "homeworkMains/*.cpp")
|
||||||
|
|
||||||
# The tracey library
|
# The tracey library
|
||||||
add_library(tracey STATIC ${common_src} ${camera_src} ${light_src}
|
add_library(tracey STATIC ${common_src} ${noise_src} ${camera_src} ${light_src}
|
||||||
${primitive_src} ${renderer_src} ${scene_src} ${shader_src} light/ambientlight.cpp light/ambientlight.h light/spotlight.cpp light/spotlight.h)
|
${primitive_src} ${renderer_src} ${scene_src} ${shader_src}
|
||||||
|
${post_processing_src} ${homework_src})
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
target_link_libraries(tracey ${CMAKE_THREAD_LIBS_INIT} ${X11_LIBRARIES})
|
target_link_libraries(tracey ${CMAKE_THREAD_LIBS_INIT} ${X11_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Executables
|
# Executables
|
||||||
|
|
||||||
add_executable(tracey_ex1 ex1.cpp)
|
add_executable(beautifulScene beautifulScene.cpp)
|
||||||
|
target_link_libraries(beautifulScene tracey)
|
||||||
|
|
||||||
|
add_executable(beautifulSceneEpic beautifulSceneEpic.cpp)
|
||||||
|
target_link_libraries(beautifulSceneEpic tracey)
|
||||||
|
|
||||||
|
add_executable(beautifulSceneDark beautifulSceneDark.cpp)
|
||||||
|
target_link_libraries(beautifulSceneDark tracey)
|
||||||
|
|
||||||
|
add_executable(tracey_ex1 homeworkMains/ex1.cpp)
|
||||||
target_link_libraries(tracey_ex1 tracey)
|
target_link_libraries(tracey_ex1 tracey)
|
||||||
|
|
||||||
add_executable(tracey_ex2 ex2.cpp)
|
add_executable(tracey_ex2 homeworkMains/ex2.cpp)
|
||||||
target_link_libraries(tracey_ex2 tracey)
|
target_link_libraries(tracey_ex2 tracey)
|
||||||
|
|
||||||
add_executable(tracey_ex3_1 ex3.cpp)
|
add_executable(tracey_ex3_1 homeworkMains/ex3.cpp)
|
||||||
target_link_libraries(tracey_ex3_1 tracey)
|
target_link_libraries(tracey_ex3_1 tracey)
|
||||||
target_compile_definitions(tracey_ex3_1 PUBLIC SITUATION=1)
|
target_compile_definitions(tracey_ex3_1 PUBLIC SITUATION=1)
|
||||||
add_executable(tracey_ex3_2 ex3.cpp)
|
add_executable(tracey_ex3_2 homeworkMains/ex3.cpp)
|
||||||
target_link_libraries(tracey_ex3_2 tracey)
|
target_link_libraries(tracey_ex3_2 tracey)
|
||||||
target_compile_definitions(tracey_ex3_2 PUBLIC SITUATION=2)
|
target_compile_definitions(tracey_ex3_2 PUBLIC SITUATION=2)
|
||||||
if("${CMAKE_CURRENT_LIST_DIR}/light/ambientlight.cpp" IN_LIST light_src)
|
if("${CMAKE_CURRENT_LIST_DIR}/light/ambientlight.cpp" IN_LIST light_src)
|
||||||
|
@ -55,19 +68,32 @@ if("${CMAKE_CURRENT_LIST_DIR}/primitive/objmodel.cpp" IN_LIST primitive_src)
|
||||||
add_definitions(-DOBJMODEL_FOUND)
|
add_definitions(-DOBJMODEL_FOUND)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(tracey_ex4 ex4.cpp)
|
add_executable(tracey_ex4 homeworkMains/ex4.cpp)
|
||||||
target_link_libraries(tracey_ex4 tracey)
|
target_link_libraries(tracey_ex4 tracey)
|
||||||
|
|
||||||
|
|
||||||
add_executable(tracey_ex5 ex5.cpp)
|
add_executable(tracey_ex5 homeworkMains/ex5.cpp)
|
||||||
target_link_libraries(tracey_ex5 tracey)
|
target_link_libraries(tracey_ex5 tracey)
|
||||||
|
|
||||||
add_executable(tracey_ex6 ex6.cpp)
|
add_executable(tracey_ex6 homeworkMains/ex6.cpp)
|
||||||
target_link_libraries(tracey_ex6 tracey)
|
target_link_libraries(tracey_ex6 tracey)
|
||||||
if("${CMAKE_CURRENT_LIST_DIR}/renderer/superrenderer.cpp" IN_LIST renderer_src)
|
if("${CMAKE_CURRENT_LIST_DIR}/renderer/superrenderer.cpp" IN_LIST renderer_src)
|
||||||
add_definitions(-DSUPERRENDERER_FOUND)
|
add_definitions(-DSUPERRENDERER_FOUND)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_executable(fancy1 fancy1.cpp)
|
||||||
|
target_link_libraries(fancy1 tracey)
|
||||||
|
|
||||||
|
add_executable(bloom bloom.cpp)
|
||||||
|
target_link_libraries(bloom tracey)
|
||||||
|
|
||||||
|
add_executable(DOFScene DOFScene.cpp)
|
||||||
|
target_link_libraries(DOFScene tracey)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
123
DOFScene.cpp
Normal file
123
DOFScene.cpp
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <shader/refractionshader.h>
|
||||||
|
|
||||||
|
#include "camera/perspectivecamera.h"
|
||||||
|
#include "renderer/simplerenderer.h"
|
||||||
|
#include "scene/simplescene.h"
|
||||||
|
|
||||||
|
#include "primitive/box.h"
|
||||||
|
#include "primitive/infiniteplane.h"
|
||||||
|
#include "primitive/objmodel.h"
|
||||||
|
#include "primitive/sphere.h"
|
||||||
|
|
||||||
|
#include "shader/brdfshader.h"
|
||||||
|
#include "shader/lambertshader.h"
|
||||||
|
#include "shader/mirrorshader.h"
|
||||||
|
#include "shader/phongshader.h"
|
||||||
|
#include "shader/cooktorranceshader.h"
|
||||||
|
#include "renderer/depthoffieldrenderer.h"
|
||||||
|
|
||||||
|
#include "light/ambientlight.h"
|
||||||
|
#include "light/pointlight.h"
|
||||||
|
#include "light/spotlight.h"
|
||||||
|
|
||||||
|
#include "post_processing/bloom.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Let's create a simple scene...
|
||||||
|
SimpleScene scene;
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setFovAngle(90.0f);
|
||||||
|
camera.setPosition(Vector3d(0.0f, 0.0f, -10.0f));
|
||||||
|
camera.setForwardDirection(Vector3d(0.0f, 0.0f, 1.0f));
|
||||||
|
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
// Add shaders
|
||||||
|
auto mirror = std::make_shared<MirrorShader>();
|
||||||
|
auto white = std::make_shared<LambertShader>(Color(0.9f, 0.9f, 0.9f));
|
||||||
|
auto red = std::make_shared<LambertShader>(Color(1.0f, 0.3f, 0.2f));
|
||||||
|
auto blue = std::make_shared<LambertShader>(Color(0.2f, 0.3f, 1.0f));
|
||||||
|
auto orange = std::make_shared<PhongShader>(Color(1.0f, 0.64f, 0.0f), 1.0f, Color(1.0f, 1.0f, 1.0f), 1.0f, 25.0f);
|
||||||
|
auto gold= std::make_shared<CookTorranceShader>(Color(0.83f, 0.69f, 0.22f), Color(1.0f, 1.0f, 0.0f), 1.2f, 0.2f);
|
||||||
|
auto blueMetallic = std::make_shared<BrdfShader>("../data/blue-metallic-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
||||||
|
auto darkRed = std::make_shared<BrdfShader>("../data/dark-red-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
||||||
|
auto glass = std::make_shared<RefractionShader>(1.31f, 1.0f);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Set up the walls
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), mirror));
|
||||||
|
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), mirror));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, +5.0f, 0.0f), Vector3d(0.0f, -1.0f, 0.0f), white));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, +1.0f, 0.0f), white));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(+5.0f, 0.0f, 0.0f), Vector3d(-1.0f, 0.0f, 0.0f), blue));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(-5.0f, 0.0f, 0.0f), Vector3d(+1.0f, 0.0f, 0.0f), red));
|
||||||
|
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(-5.0f, 0.0f, 0.0f), 1.0f, blueMetallic));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(-2.0f, 5.0f, 0.0f), 1.0f, orange));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(2.0f, 4.0f, 0.0f), 1.0f, orange));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(3.0f, 4.0f, -2.0f), 1.0f, glass));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(2.0f, 3.0f, 4.0f), 1.0f, orange));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, 3.0f, 2.0f), 1.0f, orange));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(2.0f, 1.0f, 0.0f), 1.0f, mirror));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(3.0f, -3.0f, 0.0f), 1.0f, darkRed));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(5.0f, 0.0f, 0.0f), 1.0f, darkRed));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(-5.0f, -3.3f, -4.0f), 1.0f, mirror));
|
||||||
|
|
||||||
|
// Add the teapot
|
||||||
|
auto ship = std::make_shared<ObjModel>(gold);
|
||||||
|
ship->loadObj("../data/NewObjects/Random/Ship.obj", Vector3d(0.07f, 0.07f, 0.07f), Vector3d(-1.0f, -5.0f, 0.0f));
|
||||||
|
scene.add(ship);
|
||||||
|
|
||||||
|
// Add ambient light
|
||||||
|
scene.add(std::make_shared<AmbientLight>(0.15f));
|
||||||
|
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, -4.0f), 7.0f));
|
||||||
|
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 2.5f, -4.0f), 7.0f));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Render the scene
|
||||||
|
// SimpleRenderer renderer;
|
||||||
|
// renderer.renderImage(scene, camera, 1024, 1024).save("result.png");
|
||||||
|
|
||||||
|
|
||||||
|
// initialize renderer: aperture = lens thickness, secondaryRayCount = how many rays per pixel are created
|
||||||
|
// focalLength = the area which is in focus
|
||||||
|
DOFRenderer renderer(0.2, 50, 10.0f);
|
||||||
|
|
||||||
|
// Use DOFRenderer to raytrace !!! careful more pixels lead to insane rendering times
|
||||||
|
int width = 600;
|
||||||
|
Texture image = renderer.renderImage(scene, camera, width, width / 16 * 9);
|
||||||
|
|
||||||
|
// Use post-processing Bloom effect
|
||||||
|
// Bloom bloomEffect = Bloom(image.getImage());
|
||||||
|
// Texture imageWithBloom = image;
|
||||||
|
// imageWithBloom.setTexture(bloomEffect.bloom(0.55f, 5, 10.0f, 0.06f));
|
||||||
|
|
||||||
|
// save images
|
||||||
|
image.save("result.png");
|
||||||
|
CImg<float> CImgOfImage = image.getImage();
|
||||||
|
CImg<unsigned char> img_8bit(image.width(), image.height(), 1, 3);
|
||||||
|
cimg_forXYC(CImgOfImage,x,y,c) {
|
||||||
|
img_8bit(x,y,c) = (unsigned char)std::round(CImgOfImage(x, y, c) * 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
CImgDisplay disp(img_8bit, "My Rendered Image",0, false, false);
|
||||||
|
while (!disp.is_closed()) {
|
||||||
|
disp.wait();
|
||||||
|
disp.display(img_8bit);
|
||||||
|
if (disp.is_resized()) {
|
||||||
|
disp.resize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// image.save("resultWithBloom");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
145
beautifulScene.cpp
Normal file
145
beautifulScene.cpp
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
#include <scene/simplescene.h>
|
||||||
|
|
||||||
|
#include <camera/perspectivecamera.h>
|
||||||
|
#include <shader/materialshader.h>
|
||||||
|
#include <primitive/sphere.h>
|
||||||
|
#include <light/ambientlight.h>
|
||||||
|
#include <light/pointlight.h>
|
||||||
|
#include <renderer/depthoffieldrenderer.h>
|
||||||
|
#include <post_processing/bloom.h>
|
||||||
|
#include <primitive/objmodel.h>
|
||||||
|
#include <shader/lambertshader.h>
|
||||||
|
#include <renderer/simplerenderer.h>
|
||||||
|
#include <shader/brdfshader.h>
|
||||||
|
#include <thread>
|
||||||
|
//#include <conio.h>
|
||||||
|
#include <shader/cooktorranceshader.h>
|
||||||
|
#include <shader/phongshader.h>
|
||||||
|
#include <primitive/infiniteplane.h>
|
||||||
|
#include <light/spotlight.h>
|
||||||
|
#include <shader/cloudshader.h>
|
||||||
|
#include <shader/mirrorshader.h>
|
||||||
|
#include <shader/refractionshader.h>
|
||||||
|
#include <primitive/triangle.h>
|
||||||
|
#include <shader/simpleshadowshader.h>
|
||||||
|
#include <light/sunlight.h>
|
||||||
|
#include "scene/fastscene.h"
|
||||||
|
#include "shader/toneshader.h"
|
||||||
|
#include "renderer/superrenderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
SimpleScene scene;
|
||||||
|
scene.setEnvironmentMap(std::make_shared<Texture>("data/clear_blue_sky.jpg"));
|
||||||
|
// scene.setEnvironmentMap(std::make_shared<Texture>("data/TychoSkymapII.t5_04096x02048.png"));
|
||||||
|
scene.setBackgroundColor(Color(0.1, 0.1, 0.1));
|
||||||
|
|
||||||
|
// Light
|
||||||
|
auto mainLight = std::make_shared<SunLight>(Vector3d(.5f, -.7f, .5f), 2.0f,
|
||||||
|
Color(1, 1, 1));//Color(1, 0.79f, 0.62f));
|
||||||
|
scene.add(mainLight);
|
||||||
|
scene.add(std::make_shared<AmbientLight>(.1f));
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setFovAngle(70.0f);
|
||||||
|
camera.setPosition(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
camera.setForwardDirection(Vector3d(1.0f, 0.0f, 0.0f));
|
||||||
|
// Final camera Position
|
||||||
|
// camera.setPosition(Vector3d(0.0f, -4.9f, 0.0f));
|
||||||
|
// camera.setForwardDirection(Vector3d(1.0f, 0.2f, 0.0f));
|
||||||
|
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
// Shader
|
||||||
|
auto church = std::make_shared<SimpleShadowShader>(Color(0.6f, 0.4f, 0.2f));
|
||||||
|
auto mirror = std::make_shared<MirrorShader>();
|
||||||
|
auto glass = std::make_shared<RefractionShader>(1.31f, 1.0f);
|
||||||
|
|
||||||
|
|
||||||
|
// Make Objects
|
||||||
|
auto house = std::make_shared<ObjModel>(church);
|
||||||
|
// auto temple = std::make_shared<ObjModel>(glass);
|
||||||
|
|
||||||
|
house->loadObj("data/NewObjects/house/objBuilding.obj", Vector3d(1.0f, 1.0f, 1.0f) * 0.7f,
|
||||||
|
Vector3d(43.0f, 1.5f, -9.0f));
|
||||||
|
// temple->loadObj("data/NewObjects/Random/Temple.obj", Vector3d(0.1f, 0.1f, 0.1f), Vector3d(30.0f, -6.0f, -10.0f));
|
||||||
|
|
||||||
|
|
||||||
|
// Setup ground and sky
|
||||||
|
// Add floor
|
||||||
|
// scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, 1.0f, 0.0f), church));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Add clouds
|
||||||
|
auto cloudSettings = CloudSettings();
|
||||||
|
cloudSettings.seed = 42;
|
||||||
|
cloudSettings.lightAbsorptionTowardsLight = 0.2f;
|
||||||
|
cloudSettings.lightAbsorptionThroughCloud = 1.9f;
|
||||||
|
cloudSettings.densityOffset = -0.65f;
|
||||||
|
cloudSettings.shadowIntensity = 0.4f;
|
||||||
|
auto cloudShader = std::make_shared<CloudShader>(cloudSettings);
|
||||||
|
scene.add(std::make_shared<Box>(Vector3d(0.0f, 15.0f, 0.0f), Vector3d(200.0f, 10.0f, 300.0f), cloudShader));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Insert Objects
|
||||||
|
scene.add(house);
|
||||||
|
//scene.add(temple);
|
||||||
|
//scene.add(std::make_shared<Sphere>(Vector3d(3.0f, -2.0f, -5.0f), 0.5f, mirror));
|
||||||
|
float f = 0.7;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(10.0f, -6.5f, 5.5f), 5.0f, std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(15.0f, -21.0f, -9.0f), 20.0f, std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(23.0f, -12.0f, 5.0f), 10.0f, std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(30.0f, -15.0f, 19.0f), 15.0f, std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(45.0f, -38.0f, -9.0f), 40.0f, std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(52.0f, -28.0f, 20.0f), 30.0f, std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
|
||||||
|
// Render
|
||||||
|
SuperRenderer rendererTest;
|
||||||
|
rendererTest.setSuperSamplingFactor(1);
|
||||||
|
int width = 512;
|
||||||
|
Texture imageSceneToTest = rendererTest.renderImage(scene, camera, width, width / 16 * 9);
|
||||||
|
|
||||||
|
// initialize renderer: aperture = lens thickness, secondaryRayCount = how many rays per pixel are created
|
||||||
|
// focalLength = the area which is in focus
|
||||||
|
// DOFRenderer renderer(0.2, 100, 70.0f);
|
||||||
|
|
||||||
|
// Use DOFRenderer to raytrace !!! careful more pixels lead to insane rendering times
|
||||||
|
// Texture image = renderer.renderImage(scene, camera, 1920, 1080);
|
||||||
|
|
||||||
|
// Use post-processing Bloom effect
|
||||||
|
/*
|
||||||
|
Bloom bloomEffect = Bloom(image.getImage());
|
||||||
|
Texture imageWithBloom = image;
|
||||||
|
imageWithBloom.setTexture(bloomEffect.bloom(0.55f, 5, 10.0f, 0.06f));
|
||||||
|
*/
|
||||||
|
|
||||||
|
// save images
|
||||||
|
imageSceneToTest.save("result.png");
|
||||||
|
// image.save("result.png");
|
||||||
|
// image.save("resultWithBloom");
|
||||||
|
|
||||||
|
// CImg<float> image = imageSceneToTest.getImage();
|
||||||
|
// CImg<unsigned char> img_8bit(image.width(), image.height(), 1, 3);
|
||||||
|
// cimg_forXYC(image, x, y, c) {
|
||||||
|
// img_8bit(x, y, c) = (unsigned char) std::round(image(x, y, c) * 255);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// CImgDisplay disp(img_8bit, "My Rendered Image", 0, false, false);
|
||||||
|
// while (!disp.is_closed()) {
|
||||||
|
// disp.wait();
|
||||||
|
// disp.display(img_8bit);
|
||||||
|
// if (disp.is_resized()) {
|
||||||
|
// disp.resize();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
152
beautifulSceneDark.cpp
Normal file
152
beautifulSceneDark.cpp
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
#include <scene/simplescene.h>
|
||||||
|
|
||||||
|
#include <camera/perspectivecamera.h>
|
||||||
|
#include <shader/materialshader.h>
|
||||||
|
#include <primitive/sphere.h>
|
||||||
|
#include <light/ambientlight.h>
|
||||||
|
#include <light/pointlight.h>
|
||||||
|
#include <renderer/depthoffieldrenderer.h>
|
||||||
|
#include <post_processing/bloom.h>
|
||||||
|
#include <primitive/objmodel.h>
|
||||||
|
#include <shader/lambertshader.h>
|
||||||
|
#include <renderer/simplerenderer.h>
|
||||||
|
#include <shader/brdfshader.h>
|
||||||
|
#include <thread>
|
||||||
|
//#include <conio.h>
|
||||||
|
#include <shader/cooktorranceshader.h>
|
||||||
|
#include <shader/phongshader.h>
|
||||||
|
#include <primitive/infiniteplane.h>
|
||||||
|
#include <light/spotlight.h>
|
||||||
|
#include <shader/cloudshader.h>
|
||||||
|
#include <shader/mirrorshader.h>
|
||||||
|
#include <shader/refractionshader.h>
|
||||||
|
#include <primitive/triangle.h>
|
||||||
|
#include <shader/simpleshadowshader.h>
|
||||||
|
#include <light/sunlight.h>
|
||||||
|
#include "scene/fastscene.h"
|
||||||
|
#include "shader/toneshader.h"
|
||||||
|
#include "renderer/superrenderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
SimpleScene scene;
|
||||||
|
scene.setEnvironmentMap(std::make_shared<Texture>("data/clear_red_sky.jpg"));
|
||||||
|
// scene.setEnvironmentMap(std::make_shared<Texture>("data/TychoSkymapII.t5_04096x02048.png"));
|
||||||
|
scene.setBackgroundColor(Color(0.2, 0.1, 0.1) * .5f);
|
||||||
|
|
||||||
|
// Light
|
||||||
|
auto mainLight = std::make_shared<SunLight>(Vector3d(-.9f, -.7f, .5f), 2.0f,
|
||||||
|
Color(1, 0.79f, 0.62f));
|
||||||
|
scene.add(mainLight);
|
||||||
|
// scene.add(std::make_shared<AmbientLight>(.1f));
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setFovAngle(70.0f);
|
||||||
|
camera.setPosition(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
camera.setForwardDirection(Vector3d(1.0f, 0.0f, 0.0f));
|
||||||
|
// Final camera Position
|
||||||
|
// camera.setPosition(Vector3d(0.0f, -4.9f, 0.0f));
|
||||||
|
// camera.setForwardDirection(Vector3d(1.0f, 0.2f, 0.0f));
|
||||||
|
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
// Shader
|
||||||
|
auto church = std::make_shared<SimpleShadowShader>(Color(0.6f, 0.4f, 0.2f));
|
||||||
|
auto mirror = std::make_shared<MirrorShader>();
|
||||||
|
auto glass = std::make_shared<RefractionShader>(1.31f, 1.0f);
|
||||||
|
|
||||||
|
|
||||||
|
// Make Objects
|
||||||
|
auto house = std::make_shared<ObjModel>(church);
|
||||||
|
// auto temple = std::make_shared<ObjModel>(glass);
|
||||||
|
|
||||||
|
house->loadObj("data/NewObjects/house/objBuilding.obj", Vector3d(1.0f, 1.0f, 1.0f) * 0.7f,
|
||||||
|
Vector3d(43.0f, 1.5f, -9.0f));
|
||||||
|
// temple->loadObj("data/NewObjects/Random/Temple.obj", Vector3d(0.1f, 0.1f, 0.1f), Vector3d(30.0f, -6.0f, -10.0f));
|
||||||
|
|
||||||
|
|
||||||
|
// Setup ground and sky
|
||||||
|
// Add floor
|
||||||
|
// scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, 1.0f, 0.0f), church));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Add clouds
|
||||||
|
auto cloudSettings = CloudSettings();
|
||||||
|
cloudSettings.seed = 42;
|
||||||
|
cloudSettings.lightAbsorptionTowardsLight = 0.2f;
|
||||||
|
cloudSettings.lightAbsorptionThroughCloud = 1.9f;
|
||||||
|
cloudSettings.densityOffset = -0.65f;
|
||||||
|
cloudSettings.shadowIntensity = 0.4f;
|
||||||
|
auto cloudShader = std::make_shared<CloudShader>(cloudSettings);
|
||||||
|
scene.add(std::make_shared<Box>(Vector3d(0.0f, 15.0f, 0.0f), Vector3d(200.0f, 10.0f, 300.0f), cloudShader));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Insert Objects
|
||||||
|
scene.add(house);
|
||||||
|
//scene.add(temple);
|
||||||
|
//scene.add(std::make_shared<Sphere>(Vector3d(3.0f, -2.0f, -5.0f), 0.5f, mirror));
|
||||||
|
float f = 0.5;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(10.0f, -6.5f, 5.5f), 5.0f,
|
||||||
|
std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(15.0f, -21.0f, -9.0f), 20.0f,
|
||||||
|
std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(23.0f, -12.0f, 5.0f), 10.0f,
|
||||||
|
std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(30.0f, -15.0f, 19.0f), 15.0f,
|
||||||
|
std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(45.0f, -38.0f, -9.0f), 40.0f,
|
||||||
|
std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
f *= 0.9f;
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(52.0f, -28.0f, 20.0f), 30.0f,
|
||||||
|
std::make_shared<SimpleShadowShader>(Color(0.1f, 0.6f, 0.1f) * f)));
|
||||||
|
|
||||||
|
// Render
|
||||||
|
SuperRenderer rendererTest;
|
||||||
|
rendererTest.setSuperSamplingFactor(1);
|
||||||
|
int width = 512;
|
||||||
|
Texture imageSceneToTest = rendererTest.renderImage(scene, camera, width, width / 16 * 9);
|
||||||
|
|
||||||
|
// initialize renderer: aperture = lens thickness, secondaryRayCount = how many rays per pixel are created
|
||||||
|
// focalLength = the area which is in focus
|
||||||
|
// DOFRenderer renderer(0.2, 100, 70.0f);
|
||||||
|
|
||||||
|
// Use DOFRenderer to raytrace !!! careful more pixels lead to insane rendering times
|
||||||
|
// Texture image = renderer.renderImage(scene, camera, 1920, 1080);
|
||||||
|
|
||||||
|
// Use post-processing Bloom effect
|
||||||
|
/*
|
||||||
|
Bloom bloomEffect = Bloom(image.getImage());
|
||||||
|
Texture imageWithBloom = image;
|
||||||
|
imageWithBloom.setTexture(bloomEffect.bloom(0.55f, 5, 10.0f, 0.06f));
|
||||||
|
*/
|
||||||
|
|
||||||
|
// save images
|
||||||
|
imageSceneToTest.save("result.png");
|
||||||
|
// image.save("result.png");
|
||||||
|
// image.save("resultWithBloom");
|
||||||
|
|
||||||
|
// CImg<float> image = imageSceneToTest.getImage();
|
||||||
|
// CImg<unsigned char> img_8bit(image.width(), image.height(), 1, 3);
|
||||||
|
// cimg_forXYC(image, x, y, c) {
|
||||||
|
// img_8bit(x, y, c) = (unsigned char) std::round(image(x, y, c) * 255);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// CImgDisplay disp(img_8bit, "My Rendered Image", 0, false, false);
|
||||||
|
// while (!disp.is_closed()) {
|
||||||
|
// disp.wait();
|
||||||
|
// disp.display(img_8bit);
|
||||||
|
// if (disp.is_resized()) {
|
||||||
|
// disp.resize();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
88
beautifulSceneEpic.cpp
Normal file
88
beautifulSceneEpic.cpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#include <scene/simplescene.h>
|
||||||
|
|
||||||
|
#include <camera/perspectivecamera.h>
|
||||||
|
#include <shader/materialshader.h>
|
||||||
|
#include <primitive/sphere.h>
|
||||||
|
#include <light/ambientlight.h>
|
||||||
|
#include <light/pointlight.h>
|
||||||
|
#include <renderer/depthoffieldrenderer.h>
|
||||||
|
#include <post_processing/bloom.h>
|
||||||
|
#include <primitive/objmodel.h>
|
||||||
|
#include <shader/lambertshader.h>
|
||||||
|
#include <renderer/simplerenderer.h>
|
||||||
|
#include <shader/brdfshader.h>
|
||||||
|
#include <thread>
|
||||||
|
//#include <conio.h>
|
||||||
|
#include <shader/cooktorranceshader.h>
|
||||||
|
#include <shader/phongshader.h>
|
||||||
|
#include <primitive/infiniteplane.h>
|
||||||
|
#include <light/spotlight.h>
|
||||||
|
#include <shader/cloudshader.h>
|
||||||
|
#include <shader/mirrorshader.h>
|
||||||
|
#include <shader/refractionshader.h>
|
||||||
|
#include <primitive/triangle.h>
|
||||||
|
#include <shader/simpleshadowshader.h>
|
||||||
|
#include <light/sunlight.h>
|
||||||
|
#include "scene/fastscene.h"
|
||||||
|
#include "shader/toneshader.h"
|
||||||
|
#include "renderer/superrenderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
FastScene scene;
|
||||||
|
scene.setEnvironmentMap(std::make_shared<Texture>("data/clear_blue_sky.jpg"));
|
||||||
|
|
||||||
|
// Light
|
||||||
|
// Alternative directio Vector3d(0, -.5f, -.5f)
|
||||||
|
auto mainLight = std::make_shared<SunLight>(Vector3d(0, -0.09f, 1), 2.0f, Color(1, 1, 1));
|
||||||
|
scene.add(mainLight);
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setFovAngle(100.0f);
|
||||||
|
camera.setPosition(Vector3d(0, .5f, .5f) * 2);
|
||||||
|
camera.setForwardDirection(Vector3d(0, .5f, .5f));
|
||||||
|
camera.setUpDirection(Vector3d(0, .5f, -.5f));
|
||||||
|
|
||||||
|
// Shader
|
||||||
|
Vector3d planePosition = Vector3d(0, 3, 4);
|
||||||
|
auto plane = std::make_shared<ObjModel>(
|
||||||
|
std::make_shared<ToneShader>(mainLight, Color(1, 1, 1), Color(1, 0.5f, 0.5f), Color(1, 0.5f, 0.5f) * 0.5f));
|
||||||
|
plane->loadObj("data/FancyPlane/Plane.obj", Vector3d(1.0f, 1.0f, 1.0f) * 0.005f, planePosition);
|
||||||
|
scene.add(plane);
|
||||||
|
|
||||||
|
// Add clouds
|
||||||
|
auto cloudSettings = CloudSettings();
|
||||||
|
cloudSettings.seed = 10;
|
||||||
|
cloudSettings.scale = 40;
|
||||||
|
cloudSettings.noiseSize = 512;
|
||||||
|
cloudSettings.lightAbsorptionTowardsLight = 0.05f;
|
||||||
|
cloudSettings.lightAbsorptionThroughCloud = 1.9f;
|
||||||
|
cloudSettings.densityOffset = -0.61f;
|
||||||
|
auto cloudShader = std::make_shared<CloudShader>(cloudSettings);
|
||||||
|
scene.add(std::make_shared<Box>(Vector3d(0.0f, 15.0f, 30.0f), Vector3d(100.0f, 15.0f, 70.0f), cloudShader));
|
||||||
|
|
||||||
|
scene.buildTree();
|
||||||
|
|
||||||
|
// Render
|
||||||
|
// SuperRenderer rendererTest;
|
||||||
|
// rendererTest.setSuperSamplingFactor(1);
|
||||||
|
// int width = 512;
|
||||||
|
// Texture image = rendererTest.renderImage(scene, camera, width, width / 16 * 9);
|
||||||
|
|
||||||
|
// initialize renderer: aperture = lens thickness, secondaryRayCount = how many rays per pixel are created
|
||||||
|
float focalLength = length(camera.getPosition() - planePosition + Vector3d(0, 0, 2.6f));
|
||||||
|
DOFRenderer renderer(0.02, 100, focalLength);
|
||||||
|
float imageScalar = 1;
|
||||||
|
Texture image = renderer.renderImage(scene, camera, 1920 * imageScalar, 1080 * imageScalar);
|
||||||
|
|
||||||
|
image.save("result.png");
|
||||||
|
|
||||||
|
// Use post-processing Bloom effect
|
||||||
|
Bloom bloomEffect = Bloom(image.getImage(), 0.88f, image);
|
||||||
|
image.setTexture(bloomEffect.bloom(50, 20.0f, 0.5f));
|
||||||
|
image.save("resultWithBloom.png");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
60
bloom.cpp
Normal file
60
bloom.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <post_processing/bloom.h>
|
||||||
|
#include <shader/phongshader.h>
|
||||||
|
#include <shader/simpleshadowshader.h>
|
||||||
|
#include <light/pointlight.h>
|
||||||
|
|
||||||
|
#include "camera/perspectivecamera.h"
|
||||||
|
|
||||||
|
#include "renderer/simplerenderer.h"
|
||||||
|
|
||||||
|
#include "scene/simplescene.h"
|
||||||
|
|
||||||
|
#include "primitive/box.h"
|
||||||
|
#include "primitive/infiniteplane.h"
|
||||||
|
#include "primitive/sphere.h"
|
||||||
|
#include "primitive/triangle.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
SimpleScene scene;
|
||||||
|
|
||||||
|
scene.setBackgroundColor(Color(0, 0, 0));
|
||||||
|
|
||||||
|
// Add shaders
|
||||||
|
auto red = std::make_shared<SimpleShadowShader>(Color(1.0f, 0.3f, 0.2f));
|
||||||
|
auto gray = std::make_shared<SimpleShadowShader>(Color(0.78f, 0.78f, 0.78f));
|
||||||
|
auto blue = std::make_shared<SimpleShadowShader>(Color(0.2f, 0.3f, 1.0f));
|
||||||
|
auto orange = std::make_shared<PhongShader>(Color(1.0f, 0.64f, 0.0f), 1.0f, Color(1.0f, 1.0f, 1.0f), 1.0f, 25.0f);
|
||||||
|
|
||||||
|
|
||||||
|
scene.add(std::make_shared<Box>(Vector3d(5.0f, -5.0f, 0.0f), Vector3d(4.0f, 4.0f, 4.0f), red));
|
||||||
|
scene.add(std::make_shared<Box>(Vector3d(-5.0f, -3.0f, 1.0f), Vector3d(1.0f, 6.0f, 1.0f), blue));
|
||||||
|
scene.add(std::make_shared<Box>(Vector3d(-3.5f, 4.0f, -2.0f), Vector3d(2.0f, 2.0f, 2.0f), orange));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(2.0f, 4.0f, 0.0f), 1.0f, orange));
|
||||||
|
|
||||||
|
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 0.0f, -11.0f), 100.0f));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setFovAngle(90.0f);
|
||||||
|
camera.setPosition(Vector3d(0.0f, 0.0f, -10.0f));
|
||||||
|
camera.setForwardDirection(Vector3d(0.0f, 0.0f, 1.0f));
|
||||||
|
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
// Render the scene
|
||||||
|
SimpleRenderer renderer;
|
||||||
|
Texture img = renderer.renderImage(scene, camera, 512, 512);
|
||||||
|
|
||||||
|
img.save("beforeBloom.png");
|
||||||
|
|
||||||
|
Bloom bloom = Bloom(img.getImage(), 0.88f, img);
|
||||||
|
img.setTexture(bloom.bloom(100, 300.0f, 1.5f));
|
||||||
|
|
||||||
|
img.save("afterBloom.png");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -12,6 +12,12 @@ public:
|
||||||
|
|
||||||
// Camera functions
|
// Camera functions
|
||||||
virtual Ray createRay(float x, float y) const = 0;
|
virtual Ray createRay(float x, float y) const = 0;
|
||||||
|
|
||||||
|
// Setter methods
|
||||||
|
virtual Vector3d getPosition() const = 0;
|
||||||
|
virtual Vector3d getRightDirection() const = 0;
|
||||||
|
virtual Vector3d getUpDirection() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,11 +13,6 @@ public:
|
||||||
// Set
|
// Set
|
||||||
void setPosition(Vector3d const &position) { this->position = position; }
|
void setPosition(Vector3d const &position) { this->position = position; }
|
||||||
void setForwardDirection(Vector3d const &forwardDirection) {
|
void setForwardDirection(Vector3d const &forwardDirection) {
|
||||||
// IMPLEMENT ME
|
|
||||||
// Set up a left-handed coordinate system,
|
|
||||||
// in which the camera looks along the positive z-Axis
|
|
||||||
// Set up a left-handed coordinate system,
|
|
||||||
// in which the camera looks along the positive z-Axis
|
|
||||||
std::tie(this->forwardDirection, this->upDirection, this->rightDirection) = orthoNormalized(forwardDirection, this->upDirection, crossProduct(this->upDirection, forwardDirection));
|
std::tie(this->forwardDirection, this->upDirection, this->rightDirection) = orthoNormalized(forwardDirection, this->upDirection, crossProduct(this->upDirection, forwardDirection));
|
||||||
}
|
}
|
||||||
void setUpDirection(Vector3d const &upDirection) {
|
void setUpDirection(Vector3d const &upDirection) {
|
||||||
|
@ -36,6 +31,12 @@ public:
|
||||||
// Camera functions
|
// Camera functions
|
||||||
Ray createRay(float x, float y) const override;
|
Ray createRay(float x, float y) const override;
|
||||||
|
|
||||||
|
//Getter
|
||||||
|
Vector3d getPosition() const override { return position; }
|
||||||
|
Vector3d getRightDirection() const override{ return rightDirection; }
|
||||||
|
Vector3d getUpDirection() const override { return upDirection; }
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Vector3d position;
|
Vector3d position;
|
||||||
Vector3d forwardDirection;
|
Vector3d forwardDirection;
|
||||||
|
|
69
common/noise/cloudnoise.cpp
Normal file
69
common/noise/cloudnoise.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include "cloudnoise.h"
|
||||||
|
|
||||||
|
CloudNoise::CloudNoise(int size, unsigned int seed) : Noise(size), worleyNoise1(WorleyNoise(std::min(LOWRES_SIZE, size), 3, seed)),
|
||||||
|
worleyNoise3(WorleyNoise(size, 15, seed)),
|
||||||
|
perlinNoise1(PerlinNoise(std::min(LOWRES_SIZE, size), 3, seed)),
|
||||||
|
perlinNoise2(PerlinNoise(size, 15, seed))
|
||||||
|
{
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
// Generate the noise
|
||||||
|
int const nThreads = (int) std::thread::hardware_concurrency() - 1;
|
||||||
|
int threadSize = std::floor((float) size / (float) nThreads);
|
||||||
|
int remaining = size - nThreads * threadSize;
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
for (int n = 0; n < nThreads; n++)
|
||||||
|
{
|
||||||
|
threads.emplace_back(runCloudNoiseInThread, n * threadSize, threadSize, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderNoiseThread(nThreads * threadSize, remaining);
|
||||||
|
|
||||||
|
// Rejoin the threads
|
||||||
|
for (int t = 0; t < nThreads; ++t)
|
||||||
|
{
|
||||||
|
threads[t].join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration of computation
|
||||||
|
auto stop = std::chrono::high_resolution_clock::now();
|
||||||
|
auto duration = std::chrono::duration_cast<std::chrono::seconds>(stop - start);
|
||||||
|
|
||||||
|
std::cout << "Finished computing Cloud noise for size " << size << " in "
|
||||||
|
<< duration.count() << " seconds" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CloudNoise::runCloudNoiseInThread(int xOffset, int xSize, CloudNoise *noise)
|
||||||
|
{
|
||||||
|
noise->renderNoiseThread(xOffset, xSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloudNoise::renderNoiseThread(int xOffset, int xSize)
|
||||||
|
{
|
||||||
|
for (int x = xOffset; x < xOffset + xSize; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < size; y++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < size; z++)
|
||||||
|
{
|
||||||
|
float sx = x / (float) size;
|
||||||
|
float sy = y / (float) size;
|
||||||
|
float sz = z / (float) size;
|
||||||
|
|
||||||
|
float worley1 = worleyNoise1.getNoise(sx, sy, sz);
|
||||||
|
float worley3 = worleyNoise3.getNoise(sx, sy, sz);
|
||||||
|
|
||||||
|
float perlin1 = perlinNoise1.getNoise(sx, sy, sz);
|
||||||
|
float perlin2 = perlinNoise2.getNoise(sx, sy, sz);
|
||||||
|
|
||||||
|
float noise = worley1 * 0.4f + worley3 * 0.12f + perlin1 * 0.36f + perlin2 * 0.12;
|
||||||
|
|
||||||
|
setNoise(x, y, z, noise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
common/noise/cloudnoise.h
Normal file
36
common/noise/cloudnoise.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef CG1_TRACER_CLOUDNOISE_H
|
||||||
|
#define CG1_TRACER_CLOUDNOISE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "noise.h"
|
||||||
|
#include "worleynoise.h"
|
||||||
|
#include "perlinnoise.h"
|
||||||
|
|
||||||
|
int const LOWRES_SIZE = 32;
|
||||||
|
|
||||||
|
class CloudNoise : public Noise
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* @param seed 0 for random seed
|
||||||
|
*/
|
||||||
|
explicit CloudNoise(int size, unsigned int seed = 0);
|
||||||
|
|
||||||
|
void renderNoiseThread(int xOffset, int xSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Some worley noises
|
||||||
|
WorleyNoise worleyNoise1;
|
||||||
|
WorleyNoise worleyNoise3;
|
||||||
|
|
||||||
|
// Some perlin noises
|
||||||
|
PerlinNoise perlinNoise1;
|
||||||
|
PerlinNoise perlinNoise2;
|
||||||
|
|
||||||
|
static void runCloudNoiseInThread(int xOffset, int xSize, CloudNoise *noise);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_CLOUDNOISE_H
|
117
common/noise/noise.cpp
Normal file
117
common/noise/noise.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#include <cmath>
|
||||||
|
#include "noise.h"
|
||||||
|
|
||||||
|
float Noise::getNoise(Vector3d point) const
|
||||||
|
{
|
||||||
|
return getNoise(point.x, point.y, point.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Noise::generateNoiseMap(int size)
|
||||||
|
{
|
||||||
|
noiseMap.clear();
|
||||||
|
noiseMap.resize(size * size * size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Noise::setNoise(int x, int y, int z, float value)
|
||||||
|
{
|
||||||
|
long int index = x + y * (long int) size + z * size * (long int) size;
|
||||||
|
noiseMap[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Noise::getNoise(float x, float y, float z) const
|
||||||
|
{
|
||||||
|
// Scale to [0, size]
|
||||||
|
x *= size;
|
||||||
|
y *= size;
|
||||||
|
z *= size;
|
||||||
|
|
||||||
|
// Get corner points of the cube
|
||||||
|
int x_min = (int) fitToNoise(floor(x));
|
||||||
|
int y_min = (int) fitToNoise(floor(y));
|
||||||
|
int z_min = (int) fitToNoise(floor(z));
|
||||||
|
|
||||||
|
int x_max = fitToNoise(x_min + 1);
|
||||||
|
int y_max = fitToNoise(y_min + 1);
|
||||||
|
int z_max = fitToNoise(z_min + 1);
|
||||||
|
|
||||||
|
// Get the getNoise values at the corner points
|
||||||
|
float n000 = getCalculatedNoise(x_min, y_min, z_min);
|
||||||
|
float n001 = getCalculatedNoise(x_min, y_min, z_max);
|
||||||
|
float n010 = getCalculatedNoise(x_min, y_max, z_min);
|
||||||
|
float n011 = getCalculatedNoise(x_min, y_max, z_max);
|
||||||
|
float n100 = getCalculatedNoise(x_max, y_min, z_min);
|
||||||
|
float n101 = getCalculatedNoise(x_max, y_min, z_max);
|
||||||
|
float n110 = getCalculatedNoise(x_max, y_max, z_min);
|
||||||
|
float n111 = getCalculatedNoise(x_max, y_max, z_max);
|
||||||
|
|
||||||
|
// Get fractions
|
||||||
|
float fx = x - floor(x);
|
||||||
|
float fy = y - floor(y);
|
||||||
|
float fz = z - floor(z);
|
||||||
|
|
||||||
|
// Interpolate
|
||||||
|
float nx00 = interpolate(n000, n100, fx);
|
||||||
|
float nx01 = interpolate(n001, n101, fx);
|
||||||
|
float nx10 = interpolate(n010, n110, fx);
|
||||||
|
float nx11 = interpolate(n011, n111, fx);
|
||||||
|
|
||||||
|
float nxy0 = interpolate(nx00, nx10, fy);
|
||||||
|
float nxy1 = interpolate(nx01, nx11, fy);
|
||||||
|
|
||||||
|
float noise = interpolate(nxy0, nxy1, fz);
|
||||||
|
|
||||||
|
return noise;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Noise::getCalculatedNoise(int x, int y, int z) const
|
||||||
|
{
|
||||||
|
long int index = x + y * (long int) size + z * size * (long int) size;
|
||||||
|
float noise = noiseMap[index];
|
||||||
|
|
||||||
|
if (invert)
|
||||||
|
{
|
||||||
|
noise = 1.0f - noise;
|
||||||
|
}
|
||||||
|
|
||||||
|
return noise;
|
||||||
|
}
|
||||||
|
|
||||||
|
Noise::Noise(int size)
|
||||||
|
{
|
||||||
|
this->size = size;
|
||||||
|
generateNoiseMap(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function to linearly interpolate between a0 and a1
|
||||||
|
* Weight w should be in the range [0.0, 1.0]
|
||||||
|
*/
|
||||||
|
float Noise::interpolate(float a0, float a1, float w) const
|
||||||
|
{
|
||||||
|
if (0.0 > w) return a0;
|
||||||
|
if (1.0 < w) return a1;
|
||||||
|
/* // You may want clamping by inserting:
|
||||||
|
* if (0.0 > w) return a0;
|
||||||
|
* if (1.0 < w) return a1;
|
||||||
|
*/
|
||||||
|
return (a1 - a0) * ((w * (w * 6.0 - 15.0) + 10.0) * w * w * w) + a0;
|
||||||
|
return (a1 - a0) * (3.0 - w * 2.0) * w * w + a0;
|
||||||
|
return (a1 - a0) * w + a0;
|
||||||
|
/* // Use this cubic interpolation [[Smoothstep]] instead, for a smooth appearance:
|
||||||
|
* return (a1 - a0) * (3.0 - w * 2.0) * w * w + a0;
|
||||||
|
*
|
||||||
|
* // Use [[Smootherstep]] for an even smoother result with a second derivative equal to zero on boundaries:
|
||||||
|
* return (a1 - a0) * ((w * (w * 6.0 - 15.0) + 10.0) * w * w * w) + a0;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
float Noise::fitToNoise(float point) const
|
||||||
|
{
|
||||||
|
float remainingValue = fmod(point, size);
|
||||||
|
|
||||||
|
if (remainingValue < 0)
|
||||||
|
{
|
||||||
|
remainingValue += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainingValue;
|
||||||
|
}
|
33
common/noise/noise.h
Normal file
33
common/noise/noise.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef CG1_TRACER_NOISE_H
|
||||||
|
#define CG1_TRACER_NOISE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "common/vector3d.h"
|
||||||
|
|
||||||
|
class Vector3d;
|
||||||
|
|
||||||
|
class Noise
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Noise(int size);
|
||||||
|
|
||||||
|
float getNoise(Vector3d point) const; // Parameters in [0,1], Output in [0,1]
|
||||||
|
float getNoise(float x, float y, float z) const; // Parameters in [0,1], Output in [0,1]
|
||||||
|
|
||||||
|
bool invert = false;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<float> noiseMap; // Noise map
|
||||||
|
int size; // Size of the cloudNoise map
|
||||||
|
|
||||||
|
void generateNoiseMap(int size);
|
||||||
|
void setNoise(int x, int y, int z, float value); // Parameters in [0,size]
|
||||||
|
|
||||||
|
float getCalculatedNoise(int x, int y, int z) const;
|
||||||
|
|
||||||
|
float interpolate(float a0, float a1, float w) const;
|
||||||
|
|
||||||
|
float fitToNoise(float point) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_NOISE_H
|
149
common/noise/perlinnoise.cpp
Normal file
149
common/noise/perlinnoise.cpp
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#include <random>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <thread>
|
||||||
|
#include <iostream>
|
||||||
|
#include "perlinnoise.h"
|
||||||
|
|
||||||
|
Vector3d PerlinNoise::randomGradient()
|
||||||
|
{
|
||||||
|
Vector3d v;
|
||||||
|
v.x = distribution(generator);
|
||||||
|
v.y = distribution(generator);
|
||||||
|
v.z = distribution(generator);
|
||||||
|
return normalized(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
float PerlinNoise::getGradientValue(int x, int y, int z)
|
||||||
|
{
|
||||||
|
Vector3d position = Vector3d(x, y, z);
|
||||||
|
|
||||||
|
// Translate position to grid
|
||||||
|
position /= (float) size;
|
||||||
|
position *= (float) gridSize;
|
||||||
|
|
||||||
|
// Get the grid coordinates
|
||||||
|
int x_min = floor(position.x);
|
||||||
|
int y_min = floor(position.y);
|
||||||
|
int z_min = floor(position.z);
|
||||||
|
|
||||||
|
// Get the grid coordinates of the next grid point
|
||||||
|
int x_max = x_min + 1;
|
||||||
|
int y_max = y_min + 1;
|
||||||
|
int z_max = z_min + 1;
|
||||||
|
|
||||||
|
// Get the fractional part of the position
|
||||||
|
Vector3d delta = position - Vector3d(x_min, y_min, z_min);
|
||||||
|
|
||||||
|
// Interpolate the gradient values
|
||||||
|
float n000 = getCornerValue(position, Vector3d(x_min, y_min, z_min));
|
||||||
|
float n100 = getCornerValue(position, Vector3d(x_max, y_min, z_min));
|
||||||
|
float n010 = getCornerValue(position, Vector3d(x_min, y_max, z_min));
|
||||||
|
float n110 = getCornerValue(position, Vector3d(x_max, y_max, z_min));
|
||||||
|
float n001 = getCornerValue(position, Vector3d(x_min, y_min, z_max));
|
||||||
|
float n101 = getCornerValue(position, Vector3d(x_max, y_min, z_max));
|
||||||
|
float n011 = getCornerValue(position, Vector3d(x_min, y_max, z_max));
|
||||||
|
float n111 = getCornerValue(position, Vector3d(x_max, y_max, z_max));
|
||||||
|
|
||||||
|
// Smooth the interpolation
|
||||||
|
float ix0 = interpolate(n000, n100, delta.x);
|
||||||
|
float ix1 = interpolate(n010, n110, delta.x);
|
||||||
|
float ix2 = interpolate(n001, n101, delta.x);
|
||||||
|
float ix3 = interpolate(n011, n111, delta.x);
|
||||||
|
|
||||||
|
float iy0 = interpolate(ix0, ix1, delta.y);
|
||||||
|
float iy1 = interpolate(ix2, ix3, delta.y);
|
||||||
|
|
||||||
|
float noise = interpolate(iy0, iy1, delta.z);
|
||||||
|
|
||||||
|
return noise;
|
||||||
|
}
|
||||||
|
|
||||||
|
PerlinNoise::PerlinNoise(int size, int gridSize, unsigned int seed) : Noise(size), gridSize(gridSize)
|
||||||
|
{
|
||||||
|
// Init random
|
||||||
|
if (seed == 0)
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
seed = rd();
|
||||||
|
}
|
||||||
|
this->generator = std::mt19937(seed);
|
||||||
|
this->distribution = std::normal_distribution<float>(0.0f, 1.0f);
|
||||||
|
|
||||||
|
generateNoise();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerlinNoise::generateNoise()
|
||||||
|
{
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
// Generate gradients
|
||||||
|
gradients.clear();
|
||||||
|
gradients.resize(pow(gridSize, 3));
|
||||||
|
for (int i = 0; i < gradients.size(); i++)
|
||||||
|
{
|
||||||
|
gradients[i] = randomGradient();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate each pixel
|
||||||
|
int const nThreads = (int) std::thread::hardware_concurrency() - 1;
|
||||||
|
int threadSize = std::floor((float) size / (float) nThreads);
|
||||||
|
int remaining = size - nThreads * threadSize;
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
for (int n = 0; n < nThreads; n++)
|
||||||
|
{
|
||||||
|
threads.emplace_back(runPerlinNoiseInThread, n * threadSize, threadSize, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderNoiseThread(nThreads * threadSize, remaining);
|
||||||
|
|
||||||
|
// Rejoin the threads
|
||||||
|
for (int t = 0; t < nThreads; ++t)
|
||||||
|
{
|
||||||
|
threads[t].join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize cloudNoise map to [0, 1]
|
||||||
|
float min = *std::min_element(noiseMap.begin(), noiseMap.end());
|
||||||
|
float max = *std::max_element(noiseMap.begin(), noiseMap.end());
|
||||||
|
|
||||||
|
std::for_each(noiseMap.begin(), noiseMap.end(), [min, max](float &value)
|
||||||
|
{
|
||||||
|
value = (value - min) / (max - min);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Duration of computation
|
||||||
|
auto stop = std::chrono::high_resolution_clock::now();
|
||||||
|
auto duration = std::chrono::duration_cast<std::chrono::seconds>(stop - start);
|
||||||
|
|
||||||
|
std::cout << "Finished computing Perlin noise for size " << size << " and grid size " << gridSize << " in "
|
||||||
|
<< duration.count() << " seconds" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerlinNoise::runPerlinNoiseInThread(int xOffset, int xSize, PerlinNoise *noise)
|
||||||
|
{
|
||||||
|
noise->renderNoiseThread(xOffset, xSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerlinNoise::renderNoiseThread(int xOffset, int xSize)
|
||||||
|
{
|
||||||
|
for (int x = xOffset; x < xOffset + xSize; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < size; y++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < size; z++)
|
||||||
|
{
|
||||||
|
setNoise(x, y, z, getGradientValue(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float PerlinNoise::getCornerValue(Vector3d position, Vector3d corner)
|
||||||
|
{
|
||||||
|
int x = (int) corner.x % gridSize;
|
||||||
|
int y = (int) corner.y % gridSize;
|
||||||
|
int z = (int) corner.z % gridSize;
|
||||||
|
|
||||||
|
Vector3d gradient = gradients[x + y * gridSize + z * gridSize * gridSize];
|
||||||
|
return dotProduct(gradient, position - corner);
|
||||||
|
}
|
39
common/noise/perlinnoise.h
Normal file
39
common/noise/perlinnoise.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef CG1_TRACER_PERLINNOISE_H
|
||||||
|
#define CG1_TRACER_PERLINNOISE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "noise.h"
|
||||||
|
|
||||||
|
// Stolen from https://en.wikipedia.org/wiki/Perlin_noise
|
||||||
|
class PerlinNoise : public Noise
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* @param gridSize
|
||||||
|
* @param seed 0 for random seed
|
||||||
|
*/
|
||||||
|
PerlinNoise(int size, int gridSize, unsigned int seed = 0);
|
||||||
|
|
||||||
|
void renderNoiseThread(int xOffset, int xSize);
|
||||||
|
private:
|
||||||
|
void generateNoise();
|
||||||
|
std::normal_distribution<float> distribution;
|
||||||
|
std::mt19937 generator;
|
||||||
|
|
||||||
|
int gridSize;
|
||||||
|
std::vector<Vector3d> gradients;
|
||||||
|
|
||||||
|
Vector3d randomGradient();
|
||||||
|
|
||||||
|
float getGradientValue(int x, int y, int z);
|
||||||
|
|
||||||
|
float getCornerValue(Vector3d position, Vector3d corner);
|
||||||
|
|
||||||
|
static void runPerlinNoiseInThread(int xOffset, int xSize, PerlinNoise *noise);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_PERLINNOISE_H
|
189
common/noise/worleynoise.cpp
Normal file
189
common/noise/worleynoise.cpp
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
#include <thread>
|
||||||
|
#include "worleynoise.h"
|
||||||
|
#include "common/vector3d.h"
|
||||||
|
|
||||||
|
void WorleyNoise::runWorleyNoiseInThread(int xOffset, int xSize, WorleyNoise *noise)
|
||||||
|
{
|
||||||
|
noise->renderNoiseThread(xOffset, xSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorleyNoise::generateNoise()
|
||||||
|
{
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
// Generate random points
|
||||||
|
points.clear();
|
||||||
|
points.reserve(pow(numberOfPoints, 3));
|
||||||
|
for (int x = 0; x < numberOfPoints; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < numberOfPoints; y++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < numberOfPoints; z++)
|
||||||
|
{
|
||||||
|
Vector3d point = getRandomPoint();
|
||||||
|
|
||||||
|
// Scale and translate into subcell
|
||||||
|
point /= (float) numberOfPoints;
|
||||||
|
|
||||||
|
Vector3d offset = Vector3d(x, y, z);
|
||||||
|
offset /= (float) numberOfPoints;
|
||||||
|
point += offset;
|
||||||
|
|
||||||
|
points[x + y * numberOfPoints + z * numberOfPoints * numberOfPoints] = point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate getNoise map
|
||||||
|
noiseMap.clear();
|
||||||
|
noiseMap.resize(size * size * size);
|
||||||
|
|
||||||
|
int const nThreads = (int) std::thread::hardware_concurrency() - 1;
|
||||||
|
int threadSize = std::floor((float) size / (float) nThreads);
|
||||||
|
int remaining = size - nThreads * threadSize;
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
for (int n = 0; n < nThreads; n++)
|
||||||
|
{
|
||||||
|
threads.emplace_back(runWorleyNoiseInThread, n * threadSize, threadSize, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderNoiseThread(nThreads * threadSize, remaining);
|
||||||
|
|
||||||
|
// Rejoin the threads
|
||||||
|
for (int t = 0; t < nThreads; ++t)
|
||||||
|
{
|
||||||
|
threads[t].join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize cloudNoise map to [0, 1]
|
||||||
|
float min = *std::min_element(noiseMap.begin(), noiseMap.end());
|
||||||
|
float max = *std::max_element(noiseMap.begin(), noiseMap.end());
|
||||||
|
|
||||||
|
std::for_each(noiseMap.begin(), noiseMap.end(), [min, max](float &value)
|
||||||
|
{
|
||||||
|
value = (value - min) / (max - min);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Duration of computation
|
||||||
|
auto stop = std::chrono::high_resolution_clock::now();
|
||||||
|
auto duration = std::chrono::duration_cast<std::chrono::seconds>(stop - start);
|
||||||
|
|
||||||
|
std::cout << "Finished computing Worley noise for size " << size << " and " << numberOfPoints << " points in "
|
||||||
|
<< duration.count() << " seconds" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorleyNoise::renderNoiseThread(int xOffset, int xSize)
|
||||||
|
{
|
||||||
|
for (int x = xOffset; x < xOffset + xSize; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < size; y++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < size; z++)
|
||||||
|
{
|
||||||
|
Vector3d point = Vector3d(x, y, z);
|
||||||
|
point /= (float) size;
|
||||||
|
setNoise(x, y, z, distanceToClosestPoint(point));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WorleyNoise::WorleyNoise(int size, int numberOfPoints, unsigned int seed) : numberOfPoints(numberOfPoints), Noise(size)
|
||||||
|
{
|
||||||
|
// Init random
|
||||||
|
if (seed == 0)
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
seed = rd();
|
||||||
|
}
|
||||||
|
this->generator = std::mt19937(seed);
|
||||||
|
this->distribution = std::uniform_real_distribution<float>(0.0f, 1.0f);
|
||||||
|
|
||||||
|
generateNoise();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3d WorleyNoise::getRandomPoint()
|
||||||
|
{
|
||||||
|
return Vector3d(distribution(generator), distribution(generator), distribution(generator));
|
||||||
|
}
|
||||||
|
|
||||||
|
float WorleyNoise::distanceToClosestPoint(Vector3d point)
|
||||||
|
{
|
||||||
|
std::vector<Vector3d> closePoints = getSubcellPoints(point);
|
||||||
|
|
||||||
|
// Iterate over all subcells
|
||||||
|
float minDistance = INFINITY;
|
||||||
|
for (Vector3d p: closePoints)
|
||||||
|
{
|
||||||
|
float distance = length(p - point);
|
||||||
|
if (distance < minDistance)
|
||||||
|
{
|
||||||
|
minDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Vector3d> WorleyNoise::getSubcellPoints(Vector3d point)
|
||||||
|
{
|
||||||
|
std::vector<Vector3d> closePoints;
|
||||||
|
|
||||||
|
point *= numberOfPoints;
|
||||||
|
point.x = std::floor(point.x);
|
||||||
|
point.y = std::floor(point.y);
|
||||||
|
point.z = std::floor(point.z);
|
||||||
|
|
||||||
|
// Iterate over all subcells
|
||||||
|
for (int x = -1; x <= 1; x++)
|
||||||
|
{
|
||||||
|
for (int y = -1; y <= 1; y++)
|
||||||
|
{
|
||||||
|
for (int z = -1; z <= 1; z++)
|
||||||
|
{
|
||||||
|
Vector3d offset = Vector3d(x, y, z);
|
||||||
|
Vector3d subcell = point + offset;
|
||||||
|
|
||||||
|
Vector3d cellOffsets = Vector3d(0, 0, 0);
|
||||||
|
|
||||||
|
if (subcell.x < 0)
|
||||||
|
{
|
||||||
|
cellOffsets.x = -1;
|
||||||
|
}
|
||||||
|
if (subcell.y < 0)
|
||||||
|
{
|
||||||
|
cellOffsets.y = -1;
|
||||||
|
}
|
||||||
|
if (subcell.z < 0)
|
||||||
|
{
|
||||||
|
cellOffsets.z = -1;
|
||||||
|
}
|
||||||
|
if (subcell.x >= numberOfPoints)
|
||||||
|
{
|
||||||
|
cellOffsets.x = 1;
|
||||||
|
}
|
||||||
|
if (subcell.y >= numberOfPoints)
|
||||||
|
{
|
||||||
|
cellOffsets.y = 1;
|
||||||
|
}
|
||||||
|
if (subcell.z >= numberOfPoints)
|
||||||
|
{
|
||||||
|
cellOffsets.z = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap around
|
||||||
|
subcell.x = std::fmod(subcell.x + numberOfPoints, numberOfPoints);
|
||||||
|
subcell.y = std::fmod(subcell.y + numberOfPoints, numberOfPoints);
|
||||||
|
subcell.z = std::fmod(subcell.z + numberOfPoints, numberOfPoints);
|
||||||
|
|
||||||
|
// Get points in subcell
|
||||||
|
int index = subcell.x + subcell.y * numberOfPoints + subcell.z * numberOfPoints * numberOfPoints;
|
||||||
|
closePoints.push_back(points[index] + cellOffsets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closePoints;
|
||||||
|
}
|
42
common/noise/worleynoise.h
Normal file
42
common/noise/worleynoise.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef CG1_TRACER_WORLEYNOISE_H
|
||||||
|
#define CG1_TRACER_WORLEYNOISE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include "common/vector3d.h"
|
||||||
|
#include "noise.h"
|
||||||
|
|
||||||
|
// Based on: https://www.youtube.com/watch?v=4QOcCGI6xOU
|
||||||
|
class WorleyNoise : public Noise
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* @param numberOfPoints
|
||||||
|
* @param seed 0 for random seed
|
||||||
|
*/
|
||||||
|
WorleyNoise(int size, int numberOfPoints, unsigned int seed = 0);
|
||||||
|
|
||||||
|
void renderNoiseThread(int xOffset, int xSize);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int numberOfPoints;
|
||||||
|
std::vector<Vector3d> points; // 3D-Array, each cell represents a subcell. There are numberOfPoints^3 subcells.
|
||||||
|
|
||||||
|
std::uniform_real_distribution<float> distribution;
|
||||||
|
std::mt19937 generator;
|
||||||
|
|
||||||
|
Vector3d getRandomPoint();
|
||||||
|
|
||||||
|
float distanceToClosestPoint(Vector3d point);
|
||||||
|
|
||||||
|
void generateNoise();
|
||||||
|
|
||||||
|
std::vector<Vector3d> getSubcellPoints(Vector3d point);
|
||||||
|
|
||||||
|
static void runWorleyNoiseInThread(int xOffset, int xSize, WorleyNoise *noise);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_WORLEYNOISE_H
|
|
@ -3,6 +3,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
Texture::Texture(int width, int height) { this->resize(width, height); }
|
Texture::Texture(int width, int height) { this->resize(width, height); }
|
||||||
|
|
||||||
|
@ -83,3 +84,12 @@ Color Texture::color(float u, float v, bool interpolate) const {
|
||||||
Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const {
|
Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const {
|
||||||
return color(surfacePosition.u, surfacePosition.v, interpolate);
|
return color(surfacePosition.u, surfacePosition.v, interpolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CImg<float>& Texture::getImage() {
|
||||||
|
return image_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture::setTexture(CImg<float> image){
|
||||||
|
image_ = std::move(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,11 +26,15 @@ public:
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
void setPixelAt(int x, int y, Color const &color);
|
void setPixelAt(int x, int y, Color const &color);
|
||||||
|
void setTexture(CImg<float> image);
|
||||||
|
|
||||||
|
|
||||||
// Color functions
|
// Color functions
|
||||||
Color color(float u, float v, bool interpolate = true) const;
|
Color color(float u, float v, bool interpolate = true) const;
|
||||||
Color color(Vector2d const &surfacePosition, bool interpolate = true) const;
|
Color color(Vector2d const &surfacePosition, bool interpolate = true) const;
|
||||||
|
|
||||||
|
CImg<float>& getImage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CImg<float> image_;
|
CImg<float> image_;
|
||||||
};
|
};
|
||||||
|
|
14
data/Bus/source/T07-11M.mtl
Normal file
14
data/Bus/source/T07-11M.mtl
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Materials file generated by ZModeler 2.2.6 (Build 981).
|
||||||
|
|
||||||
|
newmtl Default_Material
|
||||||
|
Ka 0.20 0.20 0.20
|
||||||
|
Kd 0.80 0.80 0.80
|
||||||
|
Ks 1.00 1.00 1.00
|
||||||
|
illum 4
|
||||||
|
|
||||||
|
newmtl Default_Material
|
||||||
|
Ka 0.20 0.20 0.20
|
||||||
|
Kd 0.80 0.80 0.80
|
||||||
|
Ks 1.00 1.00 1.00
|
||||||
|
illum 4
|
||||||
|
map_Kd t07-11m_d.png
|
7441
data/Bus/source/T07-11M.obj
Normal file
7441
data/Bus/source/T07-11M.obj
Normal file
File diff suppressed because it is too large
Load diff
BIN
data/Bus/textures/T07-11M.png
Normal file
BIN
data/Bus/textures/T07-11M.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 833 KiB |
BIN
data/Bus/textures/T07-11M_n.png
Normal file
BIN
data/Bus/textures/T07-11M_n.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 595 KiB |
BIN
data/Bus/textures/T07-11M_s.png
Normal file
BIN
data/Bus/textures/T07-11M_s.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
2667
data/FancyPlane/Plane.obj
Normal file
2667
data/FancyPlane/Plane.obj
Normal file
File diff suppressed because it is too large
Load diff
78
fancy1.cpp
Normal file
78
fancy1.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "camera/perspectivecamera.h"
|
||||||
|
|
||||||
|
#include "scene/fastscene.h"
|
||||||
|
#ifdef SUPERRENDERER_FOUND
|
||||||
|
|
||||||
|
#include "renderer/superrenderer.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "light/ambientlight.h"
|
||||||
|
#include "light/pointlight.h"
|
||||||
|
#include "shader/toneshader.h"
|
||||||
|
#include "primitive/infiniteplane.h"
|
||||||
|
#include "shader/simpleshadowshader.h"
|
||||||
|
#include "primitive/box.h"
|
||||||
|
#include "shader/cloudshader.h"
|
||||||
|
#include "common/noise/perlinnoise.h"
|
||||||
|
#include "shader/noiseshader.h"
|
||||||
|
#include "common/noise/cloudnoise.h"
|
||||||
|
#include "light/sunlight.h"
|
||||||
|
#include "scene/simplescene.h"
|
||||||
|
#include "shader/refractionshader.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
FastScene scene;
|
||||||
|
scene.setBackgroundColor(Color(0.2588f, 0.5098f, 0.9568f) * 1.0f);
|
||||||
|
// scene.setBackgroundColor(Color(1, 0.79f, 0.62f) * 0.8f);
|
||||||
|
|
||||||
|
// Add lights
|
||||||
|
auto mainLight = std::make_shared<SunLight>(Vector3d(-1.0f, -0.5f, -1.0f), 1.0f, Color(1,1,1));
|
||||||
|
scene.add(mainLight);
|
||||||
|
// scene.add(std::make_shared<AmbientLight>(0.3f));
|
||||||
|
// auto light = std::make_shared<PointLight>(Vector3d(25.0f, 10.0f, 25.0f), 100.0f);
|
||||||
|
// scene.add(light);
|
||||||
|
|
||||||
|
// Add the bus
|
||||||
|
// auto busShader = std::make_shared<ToneShader>(mainLight);
|
||||||
|
// scene.addObj("data/Bus/source/T07-11M.obj", Vector3d(1.0f, 1.0f, 1.0f), Vector3d(15.0f, 0.0f, 10.0f),
|
||||||
|
// busShader);
|
||||||
|
|
||||||
|
// Refraction boxes
|
||||||
|
// auto boxShader = std::make_shared<RefractionShader>(1.05f, 1, Color(1,1,0), 0.7f);
|
||||||
|
// scene.add(std::make_shared<Box>(Vector3d(5.0f, 3.0f, 10.0f), Vector3d(3.0f, 3.0f, 3.0f), boxShader));
|
||||||
|
// auto boxShader1 = std::make_shared<RefractionShader>(1.05f, 1, Color(0,1,1), 0.7f);
|
||||||
|
// scene.add(std::make_shared<Box>(Vector3d(9.0f, 3.0f, 12.0f), Vector3d(3.0f, 3.0f, 3.0f), boxShader1));
|
||||||
|
|
||||||
|
// Add floor
|
||||||
|
auto floorShader = std::make_shared<SimpleShadowShader>(Color(0.9f, 0.9f, 0.9f));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, 0.0f), Vector3d(0.0f, 1.0f, 0.0f),
|
||||||
|
floorShader));
|
||||||
|
|
||||||
|
// Add box for volume shader
|
||||||
|
auto cloudSettings = CloudSettings();
|
||||||
|
auto cloudShader = std::make_shared<CloudShader>(cloudSettings);
|
||||||
|
scene.add(std::make_shared<Box>(Vector3d(20.0f, 15.0f, 20.0f), Vector3d(70.0f, 10.0f, 70.0f), cloudShader));
|
||||||
|
|
||||||
|
// build the tree
|
||||||
|
scene.buildTree();
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setPosition(Vector3d(0.0f, 3.0f, 0.0f));
|
||||||
|
camera.setForwardDirection(normalized(Vector3d(1.0f, 0.15f, 1.0f)));
|
||||||
|
camera.setUpDirection(normalized(Vector3d(0.0f, 1.0f, 0.0f)));
|
||||||
|
camera.setFovAngle(90.0f);
|
||||||
|
|
||||||
|
// Render the scene
|
||||||
|
SuperRenderer sr;
|
||||||
|
sr.setSuperSamplingFactor(1);
|
||||||
|
sr.renderImage(scene, camera, 2048, 2048).save("result.png");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -18,7 +18,7 @@
|
||||||
int main() {
|
int main() {
|
||||||
// Let's create a simple cornell box scene...
|
// Let's create a simple cornell box scene...
|
||||||
SimpleScene scene;
|
SimpleScene scene;
|
||||||
scene.setEnvironmentMap(std::make_shared<Texture>("data/lion_env.png"));
|
scene.setEnvironmentMap(std::make_shared<Texture>("../data/lion_env.png"));
|
||||||
|
|
||||||
auto mirror = std::make_shared<MirrorShader>();
|
auto mirror = std::make_shared<MirrorShader>();
|
||||||
auto glass = std::make_shared<RefractionShader>(1.31f, 1.0f);
|
auto glass = std::make_shared<RefractionShader>(1.31f, 1.0f);
|
|
@ -11,20 +11,29 @@
|
||||||
#include "primitive/sphere.h"
|
#include "primitive/sphere.h"
|
||||||
|
|
||||||
#include "shader/brdfshader.h"
|
#include "shader/brdfshader.h"
|
||||||
|
|
||||||
#include "shader/lambertshader.h"
|
#include "shader/lambertshader.h"
|
||||||
#include "shader/mirrorshader.h"
|
#include "shader/mirrorshader.h"
|
||||||
#include "shader/phongshader.h"
|
#include "shader/phongshader.h"
|
||||||
#include "shader/cooktorranceshader.h"
|
#include "shader/cooktorranceshader.h"
|
||||||
|
#include "renderer/depthoffieldrenderer.h"
|
||||||
|
|
||||||
#include "light/ambientlight.h"
|
#include "light/ambientlight.h"
|
||||||
#include "light/pointlight.h"
|
#include "light/pointlight.h"
|
||||||
#include "light/spotlight.h"
|
#include "light/spotlight.h"
|
||||||
|
|
||||||
|
#include "post_processing/bloom.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Let's create a simple scene...
|
// Let's create a simple scene...
|
||||||
SimpleScene scene;
|
SimpleScene scene;
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setFovAngle(90.0f);
|
||||||
|
camera.setPosition(Vector3d(0.0f, 0.0f, -10.0f));
|
||||||
|
camera.setForwardDirection(Vector3d(0.0f, 0.0f, 1.0f));
|
||||||
|
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
// Add shaders
|
// Add shaders
|
||||||
auto mirror = std::make_shared<MirrorShader>();
|
auto mirror = std::make_shared<MirrorShader>();
|
||||||
auto white = std::make_shared<LambertShader>(Color(0.9f, 0.9f, 0.9f));
|
auto white = std::make_shared<LambertShader>(Color(0.9f, 0.9f, 0.9f));
|
||||||
|
@ -32,11 +41,14 @@ int main() {
|
||||||
auto blue = std::make_shared<LambertShader>(Color(0.2f, 0.3f, 1.0f));
|
auto blue = std::make_shared<LambertShader>(Color(0.2f, 0.3f, 1.0f));
|
||||||
auto orange = std::make_shared<PhongShader>(Color(1.0f, 0.64f, 0.0f), 1.0f, Color(1.0f, 1.0f, 1.0f), 1.0f, 25.0f);
|
auto orange = std::make_shared<PhongShader>(Color(1.0f, 0.64f, 0.0f), 1.0f, Color(1.0f, 1.0f, 1.0f), 1.0f, 25.0f);
|
||||||
auto gold= std::make_shared<CookTorranceShader>(Color(0.83f, 0.69f, 0.22f), Color(1.0f, 1.0f, 0.0f), 1.2f, 0.2f);
|
auto gold= std::make_shared<CookTorranceShader>(Color(0.83f, 0.69f, 0.22f), Color(1.0f, 1.0f, 0.0f), 1.2f, 0.2f);
|
||||||
auto blueMetallic = std::make_shared<BrdfShader>("data/blue-metallic-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
auto blueMetallic = std::make_shared<BrdfShader>("../data/blue-metallic-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
||||||
auto darkRed = std::make_shared<BrdfShader>("data/dark-red-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
auto darkRed = std::make_shared<BrdfShader>("../data/dark-red-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Set up the walls
|
// Set up the walls
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), mirror));
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), mirror));
|
||||||
|
|
||||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), mirror));
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), mirror));
|
||||||
|
@ -48,27 +60,36 @@ int main() {
|
||||||
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, 0.0f, 0.0f), 1.0f, blueMetallic));
|
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, 0.0f, 0.0f), 1.0f, blueMetallic));
|
||||||
scene.add(std::make_shared<Sphere>(Vector3d(0.0f, 2.0f, 0.0f), 1.0f, orange));
|
scene.add(std::make_shared<Sphere>(Vector3d(0.0f, 2.0f, 0.0f), 1.0f, orange));
|
||||||
scene.add(std::make_shared<Sphere>(Vector3d(3.0f, 0.0f, 0.0f), 1.0f, darkRed));
|
scene.add(std::make_shared<Sphere>(Vector3d(3.0f, 0.0f, 0.0f), 1.0f, darkRed));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, -3.3f, -4.0f), 1.0f, mirror));
|
||||||
|
|
||||||
// Add the teapot
|
// Add the teapot
|
||||||
auto teapot = std::make_shared<ObjModel>(gold);
|
auto teapot = std::make_shared<ObjModel>(gold);
|
||||||
teapot->loadObj("data/teapot.obj", Vector3d(3.0f, 3.0f, 3.0f), Vector3d(0.0f, -5.0f, 0.0f));
|
teapot->loadObj("../data/teapot.obj", Vector3d(3.0f, 3.0f, 3.0f), Vector3d(0.0f, -5.0f, 0.0f));
|
||||||
scene.add(teapot);
|
scene.add(teapot);
|
||||||
|
|
||||||
// Add ambient light
|
// Add ambient light
|
||||||
scene.add(std::make_shared<AmbientLight>(0.15f));
|
scene.add(std::make_shared<AmbientLight>(0.15f));
|
||||||
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, -4.0f), 15.0f));
|
//scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, -4.0f), 15.0f));
|
||||||
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, 4.0f), 15.0f));
|
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 2.5f, -4.0f), 7.0f));
|
||||||
|
|
||||||
|
|
||||||
// Set up the camera
|
|
||||||
PerspectiveCamera camera;
|
|
||||||
camera.setFovAngle(90.0f);
|
|
||||||
camera.setPosition(Vector3d(0.0f, 0.0f, -10.0f));
|
|
||||||
camera.setForwardDirection(Vector3d(0.0f, 0.0f, 1.0f));
|
|
||||||
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
|
||||||
|
|
||||||
// Render the scene
|
// Render the scene
|
||||||
SimpleRenderer renderer;
|
// SimpleRenderer renderer;
|
||||||
renderer.renderImage(scene, camera, 512, 512).save("result.png");
|
// renderer.renderImage(scene, camera, 1024, 1024).save("result.png");
|
||||||
|
|
||||||
|
|
||||||
|
// initialize renderer: aperture = lens thickness, secondaryRayCount = how many rays per pixel are created
|
||||||
|
// focalLength = the area which is in focus
|
||||||
|
DOFRenderer renderer(0.2, 100, 10.0f);
|
||||||
|
|
||||||
|
// Use DOFRenderer to raytrace !!! careful more pixels lead to insane rendering times
|
||||||
|
Texture image = renderer.renderImage(scene, camera, 1024, 1024);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// save images
|
||||||
|
image.save("result.png");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
#include "light/ambientlight.h"
|
#include "light/ambientlight.h"
|
||||||
|
|
||||||
Light::Illumination AmbientLight::illuminate(Scene const &scene, Ray const &ray) const {
|
Light::Illumination AmbientLight::illuminate(Scene const &scene, Ray const &ray) const {
|
||||||
return {this->color * this->intensity, -ray.normal};
|
return {this->color * this->intensity, -ray.normal, 0};
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ public:
|
||||||
struct Illumination {
|
struct Illumination {
|
||||||
Color color;
|
Color color;
|
||||||
Vector3d direction;
|
Vector3d direction;
|
||||||
|
float distance;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructor / Destructor
|
// Constructor / Destructor
|
||||||
|
|
|
@ -12,6 +12,7 @@ Light::Illumination PointLight::illuminate(Scene const &scene, Ray const &ray) c
|
||||||
|
|
||||||
// Precompute the distance from the light source
|
// Precompute the distance from the light source
|
||||||
float const distance = length(target - this->position);
|
float const distance = length(target - this->position);
|
||||||
|
illum.distance = distance;
|
||||||
|
|
||||||
// Define a secondary ray from the surface point to the light source.
|
// Define a secondary ray from the surface point to the light source.
|
||||||
Ray lightRay;
|
Ray lightRay;
|
||||||
|
@ -20,8 +21,10 @@ Light::Illumination PointLight::illuminate(Scene const &scene, Ray const &ray) c
|
||||||
lightRay.length = distance - LGT_EPS;
|
lightRay.length = distance - LGT_EPS;
|
||||||
|
|
||||||
// If the target is not in shadow...
|
// If the target is not in shadow...
|
||||||
if (!scene.findOcclusion(lightRay))
|
if (!scene.findOcclusion(lightRay)) {
|
||||||
// ... compute the attenuation and light color
|
// ... compute the attenuation and light color
|
||||||
illum.color = 1.0f / (distance * distance) * this->color * this->intensity;
|
Color rayTransparency = scene.getTransparency(lightRay, distance);
|
||||||
|
illum.color = 1.0f / (distance * distance) * this->color * this->intensity * rayTransparency;
|
||||||
|
}
|
||||||
return illum;
|
return illum;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ Light::Illumination SpotLight::illuminate(Scene const &scene, Ray const &ray) co
|
||||||
|
|
||||||
// Precompute the distance from the light source
|
// Precompute the distance from the light source
|
||||||
float const distance = length(target - this->position);
|
float const distance = length(target - this->position);
|
||||||
|
illum.distance = distance;
|
||||||
|
|
||||||
// Define a secondary ray from the surface point to the light source
|
// Define a secondary ray from the surface point to the light source
|
||||||
Ray lightRay;
|
Ray lightRay;
|
||||||
|
@ -28,7 +29,8 @@ Light::Illumination SpotLight::illuminate(Scene const &scene, Ray const &ray) co
|
||||||
// ... and not in shadow ...
|
// ... and not in shadow ...
|
||||||
if (!scene.findOcclusion(lightRay)) {
|
if (!scene.findOcclusion(lightRay)) {
|
||||||
// ... compute the attenuation and light color ...
|
// ... compute the attenuation and light color ...
|
||||||
illum.color = 1.0f / (distance * distance) * this->color * this->intensity;
|
Color rayTransparency = scene.getTransparency(lightRay, distance);
|
||||||
|
illum.color = 1.0f / (distance * distance) * this->color * this->intensity * rayTransparency;
|
||||||
// ... then compute the falloff towards the edge of the cone
|
// ... then compute the falloff towards the edge of the cone
|
||||||
if (this->alphaMin < alpha)
|
if (this->alphaMin < alpha)
|
||||||
illum.color *= 1.0f - (alpha - this->alphaMin) / (this->alphaMax - this->alphaMin);
|
illum.color *= 1.0f - (alpha - this->alphaMin) / (this->alphaMax - this->alphaMin);
|
||||||
|
|
36
light/sunlight.cpp
Normal file
36
light/sunlight.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include "sunlight.h"
|
||||||
|
|
||||||
|
|
||||||
|
SunLight::SunLight(Vector3d const &direction, float intensity, Color const &color) : Light(intensity, color),
|
||||||
|
direction(normalized(direction))
|
||||||
|
{}
|
||||||
|
|
||||||
|
Light::Illumination SunLight::illuminate(Scene const &scene, Ray const &ray) const
|
||||||
|
{
|
||||||
|
Vector3d const target = ray.origin + (ray.length - LGT_EPS) * ray.direction;
|
||||||
|
|
||||||
|
// Illumination object
|
||||||
|
Illumination illum;
|
||||||
|
illum.direction = this->direction;
|
||||||
|
illum.distance = INFINITY;
|
||||||
|
|
||||||
|
// Define a secondary ray from the surfa ce point to the light source.
|
||||||
|
Ray lightRay;
|
||||||
|
lightRay.origin = target;
|
||||||
|
lightRay.direction = -illum.direction;
|
||||||
|
lightRay.length = INFINITY;
|
||||||
|
|
||||||
|
// If the target is not in shadow...
|
||||||
|
if (!scene.findOcclusion(lightRay))
|
||||||
|
{
|
||||||
|
// Look at angleIntensity of light
|
||||||
|
float angleIntensity = 1;
|
||||||
|
// Only if normal is relevant, calculate angleIntensity
|
||||||
|
if (ray.normal != Vector3d(0, 0, 0))
|
||||||
|
angleIntensity = dotProduct(-ray.normal, this->direction); // 0 if light is behind surface, 1 if light is in front of surface
|
||||||
|
|
||||||
|
Color rayTransparency = scene.getTransparency(lightRay, INFINITY);
|
||||||
|
illum.color = this->color * this->intensity * angleIntensity * rayTransparency;
|
||||||
|
}
|
||||||
|
return illum;
|
||||||
|
}
|
20
light/sunlight.h
Normal file
20
light/sunlight.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef CG1_TRACER_SUNLIGHT_H
|
||||||
|
#define CG1_TRACER_SUNLIGHT_H
|
||||||
|
|
||||||
|
#include "scene/scene.h"
|
||||||
|
#include "light.h"
|
||||||
|
|
||||||
|
class SunLight : public Light
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SunLight(Vector3d const &direction, float intensity, Color const &color = Color(1, 1, 1));
|
||||||
|
|
||||||
|
// Light functions
|
||||||
|
Illumination illuminate(Scene const &scene, Ray const &ray) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector3d direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_SUNLIGHT_H
|
75
post_processing/bloom.cpp
Normal file
75
post_processing/bloom.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "bloom.h"
|
||||||
|
|
||||||
|
Bloom::Bloom(CImg<float> &image, float threshold, Texture& thresholdImg) : image(image), threshold(threshold) {}
|
||||||
|
|
||||||
|
|
||||||
|
CImg<float> Bloom::bloom(int kernelSize, float sigma, float intensity) {
|
||||||
|
|
||||||
|
CImg<float> brightPixels = image.get_threshold(threshold);
|
||||||
|
|
||||||
|
// Apply gaussian blur to bright pixels
|
||||||
|
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma);
|
||||||
|
CImg<float> blurred = convolution(image, kernel);
|
||||||
|
blurred *= intensity;
|
||||||
|
|
||||||
|
// Add blurred image back to original image
|
||||||
|
cimg_forXYC(image, x, y, c) {
|
||||||
|
float value = image(x, y, 0, c) + blurred(x, y, 0, c);
|
||||||
|
image(x, y, 0, c) = (value > 1.0f) ? 1.0f : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Function to compute Gaussian kernel
|
||||||
|
CImg<float> Bloom::computeGaussianKernel(int kernelSize, float sigma) {
|
||||||
|
// Create kernel
|
||||||
|
CImg<float> kernel(kernelSize, kernelSize, 1, 1);
|
||||||
|
|
||||||
|
// Compute Gaussian kernel
|
||||||
|
float sum = 0.0f;
|
||||||
|
int i, j;
|
||||||
|
for (i = 0; i < kernelSize; i++) {
|
||||||
|
for (j = 0; j < kernelSize; j++) {
|
||||||
|
kernel(i, j) = exp(-0.5f * (pow((i - kernelSize / 2.f) / sigma, 2.f) +
|
||||||
|
pow((j - kernelSize / 2.f) / sigma, 2.f))) / (2 * M_PI * sigma * sigma);
|
||||||
|
sum += kernel(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize kernel
|
||||||
|
kernel /= sum;
|
||||||
|
|
||||||
|
return kernel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to perform convolution
|
||||||
|
CImg<float> Bloom::convolution(CImg<float> &img, CImg<float> &kernel) {
|
||||||
|
int kernelSize = kernel.width();
|
||||||
|
int imgRows = img.height();
|
||||||
|
int imgCols = img.width();
|
||||||
|
CImg<float> result(imgCols, imgRows, 1, 3);
|
||||||
|
float sum;
|
||||||
|
int i, j, m, n;
|
||||||
|
int kernelRadius = kernelSize / 2;
|
||||||
|
|
||||||
|
// Perform convolution
|
||||||
|
cimg_forXYC(img, i, j, c) {
|
||||||
|
sum = 0;
|
||||||
|
cimg_forY(kernel, m) {
|
||||||
|
cimg_forX(kernel, n) {
|
||||||
|
int x = i + n - kernelRadius;
|
||||||
|
int y = j + m - kernelRadius;
|
||||||
|
if (x >= 0 && x < imgCols && y >= 0 && y < imgRows) {
|
||||||
|
sum += img(x, y, 0, c) * kernel(n, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result(i, j, 0, c) = sum;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
25
post_processing/bloom.h
Normal file
25
post_processing/bloom.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
#ifndef CG1_TRACER_BLOOM_H
|
||||||
|
#define CG1_TRACER_BLOOM_H
|
||||||
|
|
||||||
|
#include "common/texture.h"
|
||||||
|
#include "common/vector3d.h"
|
||||||
|
|
||||||
|
class Bloom {
|
||||||
|
|
||||||
|
public:
|
||||||
|
Bloom(CImg<float>& image, float threshold, Texture& thresholdImg);
|
||||||
|
CImg<float> bloom(int kernelSize, float sigma, float intensity);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CImg<float> convolution(CImg<float> &img, CImg<float> &kernel);
|
||||||
|
CImg<float> computeGaussianKernel(int kernelSize, float sigma);
|
||||||
|
|
||||||
|
CImg<float> image;
|
||||||
|
|
||||||
|
float threshold;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_BLOOM_H
|
116
renderer/depthoffieldrenderer.cpp
Normal file
116
renderer/depthoffieldrenderer.cpp
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include "depthoffieldrenderer.h"
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
|
||||||
|
DOFRenderer::DOFRenderer(float _aperture, int _secondaryRayCount, float _focalLength) : aperture(_aperture),
|
||||||
|
numSamples(_secondaryRayCount), focalLength(_focalLength) {}
|
||||||
|
|
||||||
|
std::random_device DOFRenderer::rd;
|
||||||
|
std::mt19937 DOFRenderer::gen(DOFRenderer::rd());
|
||||||
|
|
||||||
|
Color DOFRenderer::sample(const Ray &ray, const Scene& scene, const Camera& camera) const {
|
||||||
|
|
||||||
|
std::uniform_real_distribution<float> dis(-1.0, 1.0);
|
||||||
|
|
||||||
|
// calculate the point of focus
|
||||||
|
Vector3d focusPoint = ray.origin + ray.direction * focalLength;
|
||||||
|
|
||||||
|
// Final color
|
||||||
|
Color finalColor;
|
||||||
|
|
||||||
|
// Calculate all secondary Rays
|
||||||
|
for (int i = 0; i < numSamples; i++) {
|
||||||
|
// create a random point on the aperture
|
||||||
|
Vector3d rnd = Vector3d(dis(gen), dis(gen), 0);
|
||||||
|
Vector3d apertureOffset = aperture * (rnd.x * camera.getRightDirection() + rnd.y * camera.getUpDirection());
|
||||||
|
|
||||||
|
// create the new ray with the offset point
|
||||||
|
Vector3d dofRayOrigin = ray.origin + apertureOffset;
|
||||||
|
Vector3d dofRayDirection = normalized(focusPoint - dofRayOrigin);
|
||||||
|
Ray dofRay(dofRayOrigin, dofRayDirection);
|
||||||
|
|
||||||
|
// get Color of the new Ray
|
||||||
|
finalColor += scene.traceRay(dofRay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// trace the new ray and return the color
|
||||||
|
return finalColor /= float(numSamples);;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DOFRenderer::renderThread(const Scene *scene, Camera const *camera, Texture *image, const DOFRenderer *renderer, int width, int widthStep, int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k, int const stepSize) {
|
||||||
|
float const aspectRatio = static_cast<float>(height) / width;
|
||||||
|
for (int y = heightOffset; y < height; y += heightStep) {
|
||||||
|
for (int x = widthOffset; x < width; x += widthStep) {
|
||||||
|
Ray ray = camera->createRay((static_cast<float>(x) / width * 2 - 1), -(static_cast<float>(y) / height * 2 - 1) * aspectRatio);
|
||||||
|
|
||||||
|
// Trace rays with DOF
|
||||||
|
image->setPixelAt(x, y, clamped(renderer->sample(ray, *scene, *camera)));
|
||||||
|
|
||||||
|
// Super hacky progress bar!
|
||||||
|
if (++*k % stepSize == 0) {
|
||||||
|
std::cout << "=" << std::flush;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Texture DOFRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) {
|
||||||
|
Texture image(width, height);
|
||||||
|
|
||||||
|
// Setup timer
|
||||||
|
std::chrono::steady_clock::time_point start, stop;
|
||||||
|
|
||||||
|
// Reset Ray counting
|
||||||
|
Ray::resetRayCount();
|
||||||
|
|
||||||
|
// Super-hacky progress bar!
|
||||||
|
std::cout << "(SimpleRenderer): Begin rendering..." << std::endl;
|
||||||
|
std::cout << "| 0%";
|
||||||
|
int const barSize = 50;
|
||||||
|
int const stepSize = (width * height) / barSize;
|
||||||
|
for (int i = 0; i < barSize - 3 - 5; ++i)
|
||||||
|
std::cout << " ";
|
||||||
|
std::cout << "100% |" << std::endl << "|";
|
||||||
|
std::atomic<int> k(0);
|
||||||
|
|
||||||
|
/* Start timer */ start = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
// Spawn a thread for every logical processor -1, calling the renderThread function
|
||||||
|
int const nThreads = std::thread::hardware_concurrency();
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
for (int t = 0; t < nThreads - 1; ++t) {
|
||||||
|
threads.emplace_back(renderThread, &scene, &camera, &image, this, width, nThreads, t, height, 1, 0, &k, stepSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the renderThread function yourself
|
||||||
|
renderThread(&scene, &camera, &image, this, width, nThreads, nThreads - 1, height, 1, 0, &k, stepSize);
|
||||||
|
|
||||||
|
// Rejoin the threads
|
||||||
|
for (int t = 0; t < nThreads - 1; ++t) {
|
||||||
|
threads[t].join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop timer
|
||||||
|
stop = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
std::cout << "| Done!" << std::endl;
|
||||||
|
|
||||||
|
// Calculate the Time taken in seconds
|
||||||
|
double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(stop - start).count();
|
||||||
|
|
||||||
|
std::cout << "Time: " << seconds << "s" << std::endl;
|
||||||
|
|
||||||
|
// Get the number of seconds per ray
|
||||||
|
int rays = Ray::getRayCount();
|
||||||
|
|
||||||
|
std::cout << "Paths: " << rays << std::endl;
|
||||||
|
std::cout << "Paths per second: " << std::fixed << std::setprecision(0) << rays / seconds << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
35
renderer/depthoffieldrenderer.h
Normal file
35
renderer/depthoffieldrenderer.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef DEPTHOFFIELDSHADER_H
|
||||||
|
#define DEPTHOFFIELDSHADER_H
|
||||||
|
|
||||||
|
#include "camera/camera.h"
|
||||||
|
#include <random>
|
||||||
|
#include "renderer/renderer.h"
|
||||||
|
#include "scene/simplescene.h"
|
||||||
|
|
||||||
|
|
||||||
|
class DOFRenderer : public Renderer {
|
||||||
|
static void renderThread(const Scene *scene, const Camera *camera, Texture *image, const DOFRenderer *renderer, int width, int widthStep,
|
||||||
|
int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k,
|
||||||
|
const int stepSize);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
DOFRenderer(float _aperture, int _secondaryRayCount, float _focalLength);
|
||||||
|
~DOFRenderer() override = default;
|
||||||
|
|
||||||
|
//Render Functions
|
||||||
|
Texture renderImage(Scene const &scene, Camera const &camera, int width, int height) override;
|
||||||
|
|
||||||
|
// DOF sampler
|
||||||
|
Color sample(const Ray &ray, const Scene& scene, const Camera& camera) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float aperture, focalLength;
|
||||||
|
int numSamples;
|
||||||
|
|
||||||
|
static std::random_device rd;
|
||||||
|
static std::mt19937 gen;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -73,6 +73,5 @@ Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, in
|
||||||
std::cout << "Paths: " << rays << std::endl;
|
std::cout << "Paths: " << rays << std::endl;
|
||||||
std::cout << "Paths per second: " << std::fixed << std::setprecision(0) << rays / seconds << std::endl;
|
std::cout << "Paths per second: " << std::fixed << std::setprecision(0) << rays / seconds << std::endl;
|
||||||
|
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
|
@ -3,11 +3,12 @@
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "renderer/renderer.h"
|
#include "renderer/renderer.h"
|
||||||
|
#include <renderer/depthoffieldrenderer.h>
|
||||||
|
|
||||||
class SimpleRenderer : public Renderer {
|
class SimpleRenderer : public Renderer {
|
||||||
static void renderThread(const Scene *scene, Camera const *camera, Texture *image, int width, int widthStep,
|
static void renderThread(const Scene *scene, const Camera *camera, Texture *image, int width, int widthStep,
|
||||||
int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k,
|
int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k,
|
||||||
int const stepSize);
|
const int stepSize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor / Destructor
|
// Constructor / Destructor
|
||||||
|
|
|
@ -221,3 +221,25 @@ std::unique_ptr<Node> FastScene::build(Vector3d const &minimumBounds, Vector3d c
|
||||||
node->child[1] = this->build(minimumSplit, maximumBounds, rightPrimitives, depth);
|
node->child[1] = this->build(minimumSplit, maximumBounds, rightPrimitives, depth);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color FastScene::getTransparency(Ray &ray, float maxDistance) const
|
||||||
|
{
|
||||||
|
// TODO: Not taking advantage of the tree structure!
|
||||||
|
|
||||||
|
ray.length = maxDistance;
|
||||||
|
ray.primitive = nullptr;
|
||||||
|
|
||||||
|
Color transparency(1, 1, 1);
|
||||||
|
for (auto i: this->primitives())
|
||||||
|
{
|
||||||
|
Ray r = ray;
|
||||||
|
if (i->intersect(r) && r.length < maxDistance && i->shader()->isTransparent())
|
||||||
|
{
|
||||||
|
Color t = i->shader()->transparency(*this, r, maxDistance);
|
||||||
|
transparency.r *= t.r;
|
||||||
|
transparency.g *= t.g;
|
||||||
|
transparency.b *= t.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transparency;
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
// Raytracing functions
|
// Raytracing functions
|
||||||
bool findIntersection(Ray &ray) const override;
|
bool findIntersection(Ray &ray) const override;
|
||||||
bool findOcclusion(Ray &ray) const override;
|
bool findOcclusion(Ray &ray) const override;
|
||||||
|
Color getTransparency(Ray &ray, float maxDistance) const override;
|
||||||
int countNodeIntersections(const Ray &ray) const;
|
int countNodeIntersections(const Ray &ray) const;
|
||||||
|
|
||||||
// Setup functions
|
// Setup functions
|
||||||
|
|
|
@ -41,6 +41,7 @@ public:
|
||||||
Color traceRay(Ray &ray) const;
|
Color traceRay(Ray &ray) const;
|
||||||
virtual bool findIntersection(Ray &ray) const = 0;
|
virtual bool findIntersection(Ray &ray) const = 0;
|
||||||
virtual bool findOcclusion(Ray &ray) const = 0;
|
virtual bool findOcclusion(Ray &ray) const = 0;
|
||||||
|
virtual Color getTransparency(Ray &ray, float maxDistance) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Color backgroundColor;
|
Color backgroundColor;
|
||||||
|
|
|
@ -2,16 +2,38 @@
|
||||||
#include "primitive/primitive.h"
|
#include "primitive/primitive.h"
|
||||||
#include "shader/shader.h"
|
#include "shader/shader.h"
|
||||||
|
|
||||||
bool SimpleScene::findIntersection(Ray &ray) const {
|
bool SimpleScene::findIntersection(Ray &ray) const
|
||||||
|
{
|
||||||
bool hit = false;
|
bool hit = false;
|
||||||
for (auto i : this->primitives())
|
for (auto i: this->primitives())
|
||||||
hit |= i->intersect(ray);
|
hit |= i->intersect(ray);
|
||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SimpleScene::findOcclusion(Ray &ray) const {
|
bool SimpleScene::findOcclusion(Ray &ray) const
|
||||||
for (auto i : this->primitives())
|
{
|
||||||
|
for (auto i: this->primitives())
|
||||||
if (i->intersect(ray) && !i->shader()->isTransparent())
|
if (i->intersect(ray) && !i->shader()->isTransparent())
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color SimpleScene::getTransparency(Ray &ray, float maxDistance) const
|
||||||
|
{
|
||||||
|
ray.length = maxDistance;
|
||||||
|
ray.primitive = nullptr;
|
||||||
|
|
||||||
|
Color transparency(1, 1, 1);
|
||||||
|
for (auto i: this->primitives())
|
||||||
|
{
|
||||||
|
Ray r = ray;
|
||||||
|
if (i->intersect(r) && r.length < maxDistance && i->shader()->isTransparent())
|
||||||
|
{
|
||||||
|
Color t = i->shader()->transparency(*this, r, maxDistance);
|
||||||
|
transparency.r *= t.r;
|
||||||
|
transparency.g *= t.g;
|
||||||
|
transparency.b *= t.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transparency;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ public:
|
||||||
// Raytracing functions
|
// Raytracing functions
|
||||||
bool findIntersection(Ray &ray) const override;
|
bool findIntersection(Ray &ray) const override;
|
||||||
bool findOcclusion(Ray &ray) const override;
|
bool findOcclusion(Ray &ray) const override;
|
||||||
|
Color getTransparency(Ray &ray, float maxDistance) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
259
shader/cloudshader.cpp
Normal file
259
shader/cloudshader.cpp
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
#include "cloudshader.h"
|
||||||
|
#include "common/noise/cloudnoise.h"
|
||||||
|
|
||||||
|
|
||||||
|
Color CloudShader::shade(const Scene &scene, const Ray &ray) const
|
||||||
|
{
|
||||||
|
Vector3d hitPoint = ray.origin + ray.direction * ray.length; // Potentially add epsilon
|
||||||
|
|
||||||
|
// Collect getNoise through the cloud
|
||||||
|
float cloudLength = 0.0f; // Length of cloud in ray direction
|
||||||
|
|
||||||
|
// Get background color behind cloud and information about the clouds length
|
||||||
|
Ray cloudRay = ray;
|
||||||
|
cloudRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
|
||||||
|
cloudRay.length = INFINITY;
|
||||||
|
cloudRay.primitive = nullptr;
|
||||||
|
|
||||||
|
// Get out of cloud primitive first
|
||||||
|
if (ray.primitive->intersect(cloudRay))
|
||||||
|
{
|
||||||
|
// Get length
|
||||||
|
cloudLength = cloudRay.length;
|
||||||
|
|
||||||
|
// Prepare ray for background color
|
||||||
|
cloudRay.setRemainingBounces(cloudRay.getRemainingBounces() + 1);
|
||||||
|
cloudRay.origin = cloudRay.origin + (cloudRay.length + REFR_EPS) * cloudRay.direction;
|
||||||
|
cloudRay.length = INFINITY;
|
||||||
|
cloudRay.primitive = nullptr;
|
||||||
|
}
|
||||||
|
Color background = scene.traceRay(cloudRay);
|
||||||
|
|
||||||
|
if (cloudLength == 0.0f) return background; // No cloud or at edge
|
||||||
|
|
||||||
|
// Calculate step length
|
||||||
|
float stepLength = settings.densitySteps;
|
||||||
|
int noiseSamples = std::floor(cloudLength / stepLength);
|
||||||
|
|
||||||
|
// Step through cloud
|
||||||
|
float transmittance = 1.0f;
|
||||||
|
Color cloudColor = Color(0, 0, 0);
|
||||||
|
for (int i = 0; i < noiseSamples; ++i)
|
||||||
|
{
|
||||||
|
// Get sample point
|
||||||
|
Vector3d lengthDirection = (float) i * stepLength * ray.direction;
|
||||||
|
Vector3d samplePoint = hitPoint + lengthDirection;
|
||||||
|
|
||||||
|
// Get data at point
|
||||||
|
float sampleDensity = getCloudDensity(samplePoint, ray.primitive) * stepLength;
|
||||||
|
|
||||||
|
if (sampleDensity <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cloudColor += lightMarch(scene, samplePoint, lengthDirection, ray.primitive) * sampleDensity * transmittance;
|
||||||
|
transmittance *= calcBeer(sampleDensity * settings.lightAbsorptionThroughCloud);
|
||||||
|
|
||||||
|
if (transmittance < TRANSMITTANCE_BREAK) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return background * transmittance + cloudColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CloudShader::isTransparent() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudShader::CloudShader(const CloudSettings &settings) : settings(settings),
|
||||||
|
cloudNoise(CloudNoise(settings.noiseSize, settings.seed))
|
||||||
|
{
|
||||||
|
cloudNoise.invert = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CloudShader::getCloudDensity(Vector3d point, Primitive const *primitive) const
|
||||||
|
{
|
||||||
|
//! Requires the unscaled point
|
||||||
|
float edgeDensity = getEdgeDensity(point, primitive);
|
||||||
|
|
||||||
|
point /= settings.scale;
|
||||||
|
float density = cloudNoise.getNoise(point);
|
||||||
|
|
||||||
|
// Threshold
|
||||||
|
// TODO: Smooth out!
|
||||||
|
density = std::max(0.0f, density + settings.densityOffset) * settings.densityIntensity;
|
||||||
|
|
||||||
|
return density * edgeDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CloudShader::getEdgeDensity(const Vector3d &point, const Primitive *primitive) const
|
||||||
|
{
|
||||||
|
if (primitive == nullptr)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3d size = Vector3d(0, 0, 0);
|
||||||
|
size.x = primitive->maximumBounds(0) - primitive->minimumBounds(0);
|
||||||
|
size.y = primitive->maximumBounds(1) - primitive->minimumBounds(1);
|
||||||
|
size.z = primitive->maximumBounds(2) - primitive->minimumBounds(2);
|
||||||
|
|
||||||
|
Vector3d center = Vector3d(0, 0, 0);
|
||||||
|
center.x = primitive->maximumBounds(0) + primitive->minimumBounds(0);
|
||||||
|
center.y = primitive->maximumBounds(1) + primitive->minimumBounds(1);
|
||||||
|
center.z = primitive->maximumBounds(2) + primitive->minimumBounds(2);
|
||||||
|
center /= 2;
|
||||||
|
|
||||||
|
Vector3d distance = point - center;
|
||||||
|
distance.x = std::abs(distance.x);
|
||||||
|
distance.y = std::abs(distance.y);
|
||||||
|
distance.z = std::abs(distance.z);
|
||||||
|
|
||||||
|
Vector3d distanceFromEdge = size / 2 - distance;
|
||||||
|
distanceFromEdge.x = std::max(0.0f, distanceFromEdge.x);
|
||||||
|
distanceFromEdge.y = std::max(0.0f, distanceFromEdge.y);
|
||||||
|
distanceFromEdge.z = std::max(0.0f, distanceFromEdge.z);
|
||||||
|
|
||||||
|
float fallOff = std::min(distanceFromEdge.x, std::min(distanceFromEdge.y, distanceFromEdge.z)) /
|
||||||
|
settings.edgeFadeOffDistance;
|
||||||
|
|
||||||
|
return std::min(1.0f, fallOff);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color CloudShader::lightMarch(const Scene &scene, Vector3d currentInCloudPosition, Vector3d lengthDistance,
|
||||||
|
const Primitive *cloudObject) const
|
||||||
|
{
|
||||||
|
Color cloudColor = Color(0, 0, 0);
|
||||||
|
|
||||||
|
// For alle lights
|
||||||
|
for (const auto &light: scene.lights())
|
||||||
|
{
|
||||||
|
Ray ray = Ray(currentInCloudPosition - lengthDistance, normalized(lengthDistance));
|
||||||
|
ray.length = length(lengthDistance);
|
||||||
|
ray.primitive = cloudObject;
|
||||||
|
auto illumination = light->illuminate(scene, ray);
|
||||||
|
|
||||||
|
// Handle ambient lights
|
||||||
|
if (illumination.distance == 0.0f)
|
||||||
|
{
|
||||||
|
cloudColor += illumination.color;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Light ray from object to light
|
||||||
|
Ray lightRay;
|
||||||
|
lightRay.origin = currentInCloudPosition;
|
||||||
|
lightRay.direction = -illumination.direction;
|
||||||
|
lightRay.primitive = cloudObject;
|
||||||
|
lightRay.length = 0; // Starting in cloud itself
|
||||||
|
|
||||||
|
float density = this->rayDensity(lightRay, illumination.distance);
|
||||||
|
|
||||||
|
// Proper light calculation
|
||||||
|
float transmittance = calcBeer(density * settings.lightAbsorptionTowardsLight);
|
||||||
|
|
||||||
|
transmittance *= phase(normalized(lengthDistance), lightRay.direction);
|
||||||
|
|
||||||
|
cloudColor += transmittance * illumination.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
float darknessFactor = settings.darknessThreshold +
|
||||||
|
(1.0f - settings.darknessThreshold);
|
||||||
|
return cloudColor * darknessFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color CloudShader::transparency(const Scene &scene, const Ray &ray, float maxLength) const
|
||||||
|
{
|
||||||
|
float density = rayDensity(ray, maxLength);
|
||||||
|
|
||||||
|
float transmittance = calcBeer(density * settings.shadowLightAbsorption);
|
||||||
|
transmittance = 1 - (1 - transmittance) * settings.shadowIntensity;
|
||||||
|
|
||||||
|
return Color(1, 1, 1) * transmittance;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CloudShader::rayDensity(const Ray &ray, float maxLength) const
|
||||||
|
{
|
||||||
|
Vector3d startPoint = ray.origin + ray.direction * (ray.length + REFR_EPS);
|
||||||
|
|
||||||
|
// Determine length of cloud
|
||||||
|
Ray cloudRay;
|
||||||
|
cloudRay.origin = startPoint;
|
||||||
|
cloudRay.length = INFINITY;
|
||||||
|
cloudRay.direction = ray.direction;
|
||||||
|
cloudRay.primitive = nullptr;
|
||||||
|
|
||||||
|
// Get out of cloud primitive first
|
||||||
|
if (ray.primitive != nullptr && !ray.primitive->intersect(cloudRay) || cloudRay.length == INFINITY ||
|
||||||
|
cloudRay.length <= 0)
|
||||||
|
{
|
||||||
|
// Assume ray started in cloud
|
||||||
|
cloudRay.length = ray.length;
|
||||||
|
cloudRay.primitive = ray.primitive;
|
||||||
|
}
|
||||||
|
float cloudLength = std::min(cloudRay.length, maxLength - ray.length);
|
||||||
|
|
||||||
|
// Calculate step length
|
||||||
|
float stepLength = settings.densitySteps;
|
||||||
|
int noiseSamples = std::floor(cloudLength / stepLength);
|
||||||
|
|
||||||
|
// Step through cloud
|
||||||
|
float density = 0.0f;
|
||||||
|
for (int i = 0; i < noiseSamples; ++i)
|
||||||
|
{
|
||||||
|
// Get sample point
|
||||||
|
Vector3d samplePoint = startPoint + (float) i * stepLength * ray.direction;
|
||||||
|
|
||||||
|
// Get data at point
|
||||||
|
density += getCloudDensity(samplePoint, ray.primitive) * stepLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is length left, check if it is in the cloud recursively
|
||||||
|
if (cloudLength < maxLength - ray.length)
|
||||||
|
{
|
||||||
|
Vector3d endPoint = startPoint + (cloudLength + REFR_EPS) * ray.direction;
|
||||||
|
Ray recursiveRay = cloudRay;
|
||||||
|
recursiveRay.origin = endPoint;
|
||||||
|
recursiveRay.length = 0;
|
||||||
|
recursiveRay.primitive = nullptr;
|
||||||
|
|
||||||
|
if (ray.primitive != nullptr && ray.primitive->intersect(recursiveRay) && recursiveRay.length > 0)
|
||||||
|
{
|
||||||
|
density += rayDensity(recursiveRay, maxLength - (cloudLength + REFR_EPS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return density;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CloudShader::phase(Vector3d visualRay, Vector3d illuminationRay) const
|
||||||
|
{
|
||||||
|
// The angle between the visual and illumination rays
|
||||||
|
float cosTheta = dotProduct(visualRay, illuminationRay);
|
||||||
|
|
||||||
|
// The Dual-Lob Henyey-Greenstein function
|
||||||
|
float blend = .5;
|
||||||
|
float phaseBlend = calcDualHenyeyGreenstein(cosTheta, settings.phaseA) * (1 - blend) +
|
||||||
|
calcDualHenyeyGreenstein(cosTheta, -settings.phaseB) * blend;
|
||||||
|
|
||||||
|
// Clamp the result to the range [0, 1]
|
||||||
|
phaseBlend = std::max(std::min(phaseBlend, 1.0f), 0.0f);
|
||||||
|
|
||||||
|
return settings.phaseOffset + phaseBlend * settings.phaseIntensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CloudShader::calcBeer(float d)
|
||||||
|
{
|
||||||
|
float beer = std::exp(-d);
|
||||||
|
return beer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float CloudShader::calcDualHenyeyGreenstein(float cosTheta, float g)
|
||||||
|
{
|
||||||
|
float g2 = g * g;
|
||||||
|
return (1 - g2) / (4 * 3.1415f * std::pow(1 + g2 - 2 * g * (cosTheta), 1.5f));
|
||||||
|
}
|
67
shader/cloudshader.h
Normal file
67
shader/cloudshader.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef CG1_TRACER_CLOUDSHADER_H
|
||||||
|
#define CG1_TRACER_CLOUDSHADER_H
|
||||||
|
|
||||||
|
#include "scene/scene.h"
|
||||||
|
#include "shader.h"
|
||||||
|
#include "light/light.h"
|
||||||
|
#include "primitive/primitive.h"
|
||||||
|
#include "common/noise/worleynoise.h"
|
||||||
|
|
||||||
|
float const TRANSMITTANCE_BREAK = 0.0001f; // If transmittance goes below this limit, the cloud is considered opaque
|
||||||
|
|
||||||
|
struct CloudSettings
|
||||||
|
{
|
||||||
|
int noiseSize = 128; // 64
|
||||||
|
unsigned int seed = 0; // 0 for random seed
|
||||||
|
float densitySteps = .2f; // .2f
|
||||||
|
float scale = 30; // 30
|
||||||
|
float densityOffset = -.55f; // -.55f
|
||||||
|
float densityIntensity = 5.0f; // 5.0f
|
||||||
|
float darknessThreshold = .1f; // .1f
|
||||||
|
float shadowIntensity = .6f; // .6f
|
||||||
|
float shadowLightAbsorption = 1; // 1
|
||||||
|
float lightAbsorptionTowardsLight = 0.1f; // .3f // How Bright should the clouds be? Lower is brighter
|
||||||
|
float lightAbsorptionThroughCloud = .8f; // .8f // How dark should the background be where the cloud is? Higher values mean darker background
|
||||||
|
float phaseA = .8f; // .5f
|
||||||
|
float phaseB = .4f; // .3f
|
||||||
|
float phaseOffset = .8f; // .8f
|
||||||
|
float phaseIntensity = .1f; // 1.0f
|
||||||
|
float edgeFadeOffDistance = .5f; // .5f
|
||||||
|
};
|
||||||
|
|
||||||
|
class CloudShader : public Shader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CloudShader(CloudSettings const &settings = CloudSettings());
|
||||||
|
|
||||||
|
// Shader functions
|
||||||
|
Color shade(Scene const &scene, Ray const &ray) const;
|
||||||
|
|
||||||
|
Color transparency(const Scene &scene, const Ray &ray, float maxLength) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CloudSettings settings;
|
||||||
|
|
||||||
|
|
||||||
|
bool isTransparent() const;
|
||||||
|
|
||||||
|
Noise cloudNoise;
|
||||||
|
|
||||||
|
float getCloudDensity(Vector3d point, const Primitive *primitive = nullptr) const;
|
||||||
|
|
||||||
|
Color lightMarch(const Scene &scene, Vector3d currentInCloudPosition, Vector3d lengthDistance,
|
||||||
|
const Primitive *cloudObject) const;
|
||||||
|
|
||||||
|
float rayDensity(const Ray &ray, float maxLength) const;
|
||||||
|
|
||||||
|
float phase(Vector3d visualRay, Vector3d illuminationRay) const;
|
||||||
|
|
||||||
|
static float calcDualHenyeyGreenstein(float cosTheta, float g) ;
|
||||||
|
|
||||||
|
static float calcBeer(float d) ;
|
||||||
|
|
||||||
|
float getEdgeDensity(const Vector3d &point, const Primitive *primitive) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_CLOUDSHADER_H
|
12
shader/depthshader.cpp
Normal file
12
shader/depthshader.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "depthshader.h"
|
||||||
|
|
||||||
|
Color DepthShader::shade(const Scene &scene, const Ray &ray) const
|
||||||
|
{
|
||||||
|
float brightness = exp(-ray.length * 0.1f);
|
||||||
|
return brightness * nearColor + (1 - brightness) * farColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
DepthShader::DepthShader(const Color &nearColor, const Color &farColor) : nearColor(nearColor), farColor(farColor)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
21
shader/depthshader.h
Normal file
21
shader/depthshader.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef CG1_TRACER_DEPTHSHADER_H
|
||||||
|
#define CG1_TRACER_DEPTHSHADER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "shader/shader.h"
|
||||||
|
|
||||||
|
class DepthShader : public Shader {
|
||||||
|
|
||||||
|
public:
|
||||||
|
DepthShader(Color const &nearColor = Color(1, 1, 1), Color const &farColor = Color(0, 0, 0));
|
||||||
|
|
||||||
|
// Shader functions
|
||||||
|
Color shade(Scene const &scene, Ray const &ray) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Color nearColor;
|
||||||
|
Color farColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_DEPTHSHADER_H
|
15
shader/noiseshader.cpp
Normal file
15
shader/noiseshader.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "noiseshader.h"
|
||||||
|
|
||||||
|
NoiseShader::NoiseShader(std::shared_ptr<Noise> noise, float scale, Vector3d offset)
|
||||||
|
{
|
||||||
|
this->noise = noise;
|
||||||
|
this->scale = scale;
|
||||||
|
this->offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color NoiseShader::shade(const Scene &scene, const Ray &ray) const
|
||||||
|
{
|
||||||
|
Vector3d point = ray.origin + ray.direction * ray.length;
|
||||||
|
float noiseValue = noise->getNoise(point / scale + offset);
|
||||||
|
return Color(1, 1, 1) * noiseValue;
|
||||||
|
}
|
25
shader/noiseshader.h
Normal file
25
shader/noiseshader.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef CG1_TRACER_NOISESHADER_H
|
||||||
|
#define CG1_TRACER_NOISESHADER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include "shader.h"
|
||||||
|
#include "common/noise/noise.h"
|
||||||
|
|
||||||
|
class NoiseShader : public Shader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
NoiseShader(std::shared_ptr<Noise> noise, float scale = 1, Vector3d offset = Vector3d(0, 0, 0));
|
||||||
|
|
||||||
|
// Shader functions
|
||||||
|
Color shade(Scene const &scene, Ray const &ray) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float scale;
|
||||||
|
Vector3d offset;
|
||||||
|
std::shared_ptr<Noise> noise;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_NOISESHADER_H
|
|
@ -1,18 +1,27 @@
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
#include "shader/refractionshader.h"
|
#include "shader/refractionshader.h"
|
||||||
|
|
||||||
RefractionShader::RefractionShader(float indexInside, float indexOutside) : indexInside(indexInside), indexOutside(indexOutside) {}
|
RefractionShader::RefractionShader(float indexInside, float indexOutside, Color const &objectColor, float lightLoss)
|
||||||
|
: indexInside(
|
||||||
|
indexInside), indexOutside(indexOutside), objectColor(objectColor), lightLoss(lightLoss)
|
||||||
|
{}
|
||||||
|
|
||||||
Color RefractionShader::shade(Scene const &scene, Ray const &ray) const {
|
Color RefractionShader::shade(Scene const &scene, Ray const &ray) const
|
||||||
|
{
|
||||||
// Circumvent getting environment map color into the mix
|
// Circumvent getting environment map color into the mix
|
||||||
if (ray.getRemainingBounces() > 0) {
|
if (ray.getRemainingBounces() <= 0)
|
||||||
|
{
|
||||||
|
return Color(0.0f, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the normal of the primitive which was hit
|
// Get the normal of the primitive which was hit
|
||||||
Vector3d normalVector = ray.normal;
|
Vector3d normalVector = ray.normal;
|
||||||
|
|
||||||
// Calculate the index of refraction
|
// Calculate the index of refraction
|
||||||
float refractiveIndex = indexOutside / indexInside;
|
float refractiveIndex = indexOutside / indexInside;
|
||||||
// What if we are already inside the object?
|
// What if we are already inside the object?
|
||||||
if (dotProduct(normalVector, ray.direction) > 0) {
|
if (dotProduct(normalVector, ray.direction) > 0)
|
||||||
|
{
|
||||||
normalVector = -normalVector;
|
normalVector = -normalVector;
|
||||||
refractiveIndex = indexInside / indexOutside;
|
refractiveIndex = indexInside / indexOutside;
|
||||||
}
|
}
|
||||||
|
@ -30,22 +39,51 @@ Color RefractionShader::shade(Scene const &scene, Ray const &ray) const {
|
||||||
refractionRay.primitive = nullptr;
|
refractionRay.primitive = nullptr;
|
||||||
|
|
||||||
// Check whether it is a refraction.
|
// Check whether it is a refraction.
|
||||||
if (dotProduct(t, normalVector) <= 0.0) {
|
if (dotProduct(t, normalVector) <= 0.0)
|
||||||
|
{
|
||||||
refractionRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
|
refractionRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
|
||||||
refractionRay.direction = normalized(t);
|
refractionRay.direction = normalized(t);
|
||||||
} else { // Otherwise, it is a total reflection.
|
} else
|
||||||
|
{ // Otherwise, it is a total reflection.
|
||||||
refractionRay.origin = ray.origin + (ray.length - REFR_EPS) * ray.direction;
|
refractionRay.origin = ray.origin + (ray.length - REFR_EPS) * ray.direction;
|
||||||
// Next we get the reflection vector
|
// Next we get the reflection vector
|
||||||
Vector3d const reflectionVector = ray.direction - 2.0f * dotProduct(normalVector, ray.direction) * normalVector;
|
Vector3d const reflectionVector =
|
||||||
|
ray.direction - 2.0f * dotProduct(normalVector, ray.direction) * normalVector;
|
||||||
|
|
||||||
// Change the ray direction and origin
|
// Change the ray direction and origin
|
||||||
refractionRay.direction = normalized(reflectionVector);
|
refractionRay.direction = normalized(reflectionVector);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send out a new refracted ray into the scene
|
// Send out a new refracted ray into the scene
|
||||||
return scene.traceRay(refractionRay);
|
Color hitColor = scene.traceRay(refractionRay);
|
||||||
}
|
float lightRemaining = 1;
|
||||||
return Color(0.0f, 0.0f, 0.0f);
|
if (ray.primitive == refractionRay.primitive) lightRemaining = remainingLightIntensity(refractionRay.length);
|
||||||
|
|
||||||
|
return hitColor * objectColor * lightRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RefractionShader::isTransparent() const { return true; }
|
float RefractionShader::remainingLightIntensity(float distanceThroughObject) const
|
||||||
|
{
|
||||||
|
return 1 - lightLoss + exp(-distanceThroughObject / 10) * lightLoss;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RefractionShader::isTransparent() const
|
||||||
|
{ return true; }
|
||||||
|
|
||||||
|
Color RefractionShader::transparency(const Scene &scene, const Ray &ray, float maxLength) const
|
||||||
|
{
|
||||||
|
// Determine length through the object
|
||||||
|
Ray lengthRay = ray;
|
||||||
|
// Reset the ray
|
||||||
|
lengthRay.length = INFINITY;
|
||||||
|
lengthRay.primitive = nullptr;
|
||||||
|
lengthRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
|
||||||
|
|
||||||
|
scene.traceRay(lengthRay);
|
||||||
|
|
||||||
|
float transparencyDistance = std::min(maxLength - ray.length, lengthRay.length);
|
||||||
|
float lightRemaining = 1;
|
||||||
|
if (ray.primitive == lengthRay.primitive) lightRemaining = remainingLightIntensity(transparencyDistance);
|
||||||
|
|
||||||
|
return objectColor * lightRemaining;
|
||||||
|
}
|
||||||
|
|
|
@ -3,19 +3,26 @@
|
||||||
|
|
||||||
#include "shader/shader.h"
|
#include "shader/shader.h"
|
||||||
|
|
||||||
class RefractionShader : public Shader {
|
class RefractionShader : public Shader
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
RefractionShader(float indexInside, float indexOutside);
|
RefractionShader(float indexInside, float indexOutside, Color const &objectColor = Color(1, 1, 1), float lightLoss = 0);
|
||||||
|
|
||||||
// Shader functions
|
// Shader functions
|
||||||
Color shade(Scene const &scene, Ray const &ray) const override;
|
Color shade(Scene const &scene, Ray const &ray) const override;
|
||||||
|
|
||||||
bool isTransparent() const override;
|
bool isTransparent() const override;
|
||||||
|
Color transparency(const Scene &scene, const Ray &ray, float maxLength) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float indexInside;
|
float indexInside;
|
||||||
float indexOutside;
|
float indexOutside;
|
||||||
|
float lightLoss;
|
||||||
|
Color objectColor;
|
||||||
|
|
||||||
|
float remainingLightIntensity(float distanceThroughObject) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,14 +7,27 @@
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
class Scene;
|
class Scene;
|
||||||
|
|
||||||
class Shader {
|
class Shader
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
// Constructor / Desctructor
|
// Constructor / Desctructor
|
||||||
Shader() = default;
|
Shader() = default;
|
||||||
|
|
||||||
virtual ~Shader() = default;
|
virtual ~Shader() = default;
|
||||||
|
|
||||||
// Get
|
// Get
|
||||||
virtual bool isTransparent() const { return false; }
|
virtual bool isTransparent() const
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Especially used for lighting calculations.
|
||||||
|
* @brief Returns the light let through the shader in opposite direction of the given ray.
|
||||||
|
* @param ray Origin and direction of the desired path through the object. Origin might be inside or outside the object. Length of the ray is upper bound for the destination point, and might not go through the object completely.
|
||||||
|
* @param maxLength Maximum length of the ray. If the ray through the object is longer than this, it is cut off.
|
||||||
|
* @return 0 if the shader is opaque, 1 if the shader is transparent, for each color channel.
|
||||||
|
*/
|
||||||
|
virtual Color transparency(const Scene &scene, const Ray &ray, float maxLength) const
|
||||||
|
{ return isTransparent() ? Color(1, 1, 1) : Color(0, 0, 0); }
|
||||||
|
|
||||||
// Shader functions
|
// Shader functions
|
||||||
virtual Color shade(Scene const &scene, Ray const &ray) const = 0;
|
virtual Color shade(Scene const &scene, Ray const &ray) const = 0;
|
||||||
|
|
Loading…
Reference in a new issue