Added multithreading and Scene Toggling

This commit is contained in:
2024-11-04 17:03:41 +01:00
parent d8936ca9f6
commit d9282c249f
6 changed files with 206 additions and 945218 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@
//Project includes //Project includes
#include "Renderer.h" #include "Renderer.h"
#include <execution>
#include <iostream> #include <iostream>
#include "Maths.h" #include "Maths.h"
@@ -24,7 +25,11 @@ Renderer::Renderer(SDL_Window * pWindow) :
m_AspectRatio = (m_Width / float(m_Height)) ; m_AspectRatio = (m_Width / float(m_Height)) ;
m_pBufferPixels = static_cast<uint32_t*>(m_pBuffer->pixels); m_pBufferPixels = static_cast<uint32_t*>(m_pBuffer->pixels);
m_HorizontalIterator.resize(m_Width);
m_VerticalIterator.resize(m_Height);
for (uint32_t i = 0; i < m_Width; i++) m_HorizontalIterator[i] = i;
for (uint32_t i = 0; i < m_Height; i++) m_VerticalIterator[i] = i;
} }
void Renderer::Render(Scene* pScene) const void Renderer::Render(Scene* pScene) const
@@ -35,86 +40,172 @@ void Renderer::Render(Scene* pScene) const
const Matrix cameraToWorld = camera.CalculateCameraToWorld(); const Matrix cameraToWorld = camera.CalculateCameraToWorld();
for (int px{}; px < m_Width; ++px)
if (m_IsMultiThreadingEnabled)
{ {
for (int py{}; py < m_Height; ++py) std::for_each(std::execution::par ,m_HorizontalIterator.begin(), m_HorizontalIterator.end(), [this, camera, cameraToWorld, materials, lights, pScene](uint32_t px)
{
//Sets screen to black
ColorRGB finalColor{ };
//creates a vector that holds a coordinate in 3D space dependent on which pixel the loop is on
Vector3 rayDirection{ float((2 * ((px + 0.5) / m_Width) - 1) * m_AspectRatio * camera.FOV),float((1 - 2 * ((py + 0.5) / m_Height)) * camera.FOV),1};
rayDirection.Normalize();
rayDirection = cameraToWorld.TransformVector(rayDirection);
//Creates a Ray from origin to the point where the current pixel in loop is
Ray viewRay{ camera.origin,rayDirection };
HitRecord closestHit{};
pScene->GetClosestHit(viewRay, closestHit);
if (closestHit.didHit)
{ {
std::for_each(std::execution::par,m_VerticalIterator.begin(), m_VerticalIterator.end(), [this, px, camera, cameraToWorld, materials, lights, pScene](uint32_t py)
for (int idx{ 0 }; idx < lights.size(); idx++)
{
Vector3 lightVec = LightUtils::GetDirectionToLight(lights[idx], closestHit.origin);
float maxRayLenght = lightVec.Normalize();
Ray shadowRay(closestHit.origin + closestHit.normal * 0.0001f, lightVec, 0.0001f, maxRayLenght);
bool shadowDoesHit = pScene->DoesHit(shadowRay);
float observedArea = Vector3::Dot(closestHit.normal, lightVec);
if (observedArea > 0.f)
{ {
//Sets screen to black
ColorRGB finalColor{ };
if (!m_ShadowsEnabled or (m_ShadowsEnabled && !shadowDoesHit)) //creates a vector that holds a coordinate in 3D space dependent on which pixel the loop is on
Vector3 rayDirection{ float((2 * ((px + 0.5) / m_Width) - 1) * m_AspectRatio * camera.FOV),float((1 - 2 * ((py + 0.5) / m_Height)) * camera.FOV),1 };
rayDirection.Normalize();
rayDirection = cameraToWorld.TransformVector(rayDirection);
//Creates a Ray from origin to the point where the current pixel in loop is
Ray viewRay{ camera.origin,rayDirection };
HitRecord closestHit{};
pScene->GetClosestHit(viewRay, closestHit);
if (closestHit.didHit)
{ {
if (m_CurrentLightingMode == LightingMode::ObservedArea)
for (int idx{ 0 }; idx < lights.size(); idx++)
{ {
finalColor += ColorRGB{ observedArea,observedArea,observedArea }; Vector3 lightVec = LightUtils::GetDirectionToLight(lights[idx], closestHit.origin);
float maxRayLenght = lightVec.Normalize();
Ray shadowRay(closestHit.origin + closestHit.normal * 0.0001f, lightVec, 0.0001f, maxRayLenght);
bool shadowDoesHit = pScene->DoesHit(shadowRay);
float observedArea = Vector3::Dot(closestHit.normal, lightVec);
if (observedArea > 0.f)
{
if (!m_ShadowsEnabled or (m_ShadowsEnabled && !shadowDoesHit))
{
if (m_CurrentLightingMode == LightingMode::ObservedArea)
{
finalColor += ColorRGB{ observedArea,observedArea,observedArea };
}
if (m_CurrentLightingMode == LightingMode::Radiance)
{
finalColor += LightUtils::GetRadiance(lights[idx], closestHit.origin);
}
if (m_CurrentLightingMode == LightingMode::BRDF)
{
finalColor += materials[closestHit.materialIndex]->Shade(closestHit, lightVec, viewRay.direction);
}
if (m_CurrentLightingMode == LightingMode::Combined)
{
ColorRGB ObservedArea = ColorRGB{ observedArea, observedArea,observedArea };
ColorRGB Radiance = LightUtils::GetRadiance(lights[idx], closestHit.origin);
ColorRGB BRDF = materials[closestHit.materialIndex]->Shade(closestHit, lightVec, viewRay.direction);
finalColor += Radiance * BRDF * ObservedArea;
}
}
}
} }
if (m_CurrentLightingMode == LightingMode::Radiance)
{
finalColor += LightUtils::GetRadiance(lights[idx], closestHit.origin);
}
if (m_CurrentLightingMode == LightingMode::BRDF) //const float scaled_t = (closestHit.t - 50.f) / 40.f; //shades spheres based on proximity
{ //finalColor = { scaled_t,scaled_t,scaled_t };
finalColor += materials[closestHit.materialIndex]->Shade(closestHit, lightVec, viewRay.direction);
}
if (m_CurrentLightingMode == LightingMode::Combined)
{
ColorRGB ObservedArea = ColorRGB{ observedArea, observedArea,observedArea};
ColorRGB Radiance = LightUtils::GetRadiance(lights[idx], closestHit.origin);
ColorRGB BRDF = materials[closestHit.materialIndex]->Shade(closestHit, lightVec, viewRay.direction);
finalColor += Radiance * BRDF * ObservedArea;
}
//const float scaled_t = (closestHit.t) / 500.f; //shades planes based on proximity
//finalColor = { scaled_t,scaled_t,scaled_t };
} }
//Update Color in Buffer
finalColor.MaxToOne();
m_pBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBuffer->format,
static_cast<uint8_t>(finalColor.r * 255),
static_cast<uint8_t>(finalColor.g * 255),
static_cast<uint8_t>(finalColor.b * 255));
});
});
}
else
{
for (int px{}; px < m_Width; ++px)
{
for (int py{}; py < m_Height; ++py)
{
//Sets screen to black
ColorRGB finalColor{ };
//creates a vector that holds a coordinate in 3D space dependent on which pixel the loop is on
Vector3 rayDirection{ float((2 * ((px + 0.5) / m_Width) - 1) * m_AspectRatio * camera.FOV),float((1 - 2 * ((py + 0.5) / m_Height)) * camera.FOV),1 };
rayDirection.Normalize();
rayDirection = cameraToWorld.TransformVector(rayDirection);
//Creates a Ray from origin to the point where the current pixel in loop is
Ray viewRay{ camera.origin,rayDirection };
HitRecord closestHit{};
pScene->GetClosestHit(viewRay, closestHit);
if (closestHit.didHit)
{
for (int idx{ 0 }; idx < lights.size(); idx++)
{
Vector3 lightVec = LightUtils::GetDirectionToLight(lights[idx], closestHit.origin);
float maxRayLenght = lightVec.Normalize();
Ray shadowRay(closestHit.origin + closestHit.normal * 0.0001f, lightVec, 0.0001f, maxRayLenght);
bool shadowDoesHit = pScene->DoesHit(shadowRay);
float observedArea = Vector3::Dot(closestHit.normal, lightVec);
if (observedArea > 0.f)
{
if (!m_ShadowsEnabled or (m_ShadowsEnabled && !shadowDoesHit))
{
if (m_CurrentLightingMode == LightingMode::ObservedArea)
{
finalColor += ColorRGB{ observedArea,observedArea,observedArea };
}
if (m_CurrentLightingMode == LightingMode::Radiance)
{
finalColor += LightUtils::GetRadiance(lights[idx], closestHit.origin);
}
if (m_CurrentLightingMode == LightingMode::BRDF)
{
finalColor += materials[closestHit.materialIndex]->Shade(closestHit, lightVec, viewRay.direction);
}
if (m_CurrentLightingMode == LightingMode::Combined)
{
ColorRGB ObservedArea = ColorRGB{ observedArea, observedArea,observedArea };
ColorRGB Radiance = LightUtils::GetRadiance(lights[idx], closestHit.origin);
ColorRGB BRDF = materials[closestHit.materialIndex]->Shade(closestHit, lightVec, viewRay.direction);
finalColor += Radiance * BRDF * ObservedArea;
}
}
}
} }
//const float scaled_t = (closestHit.t - 50.f) / 40.f; //shades spheres based on proximity
//finalColor = { scaled_t,scaled_t,scaled_t };
//const float scaled_t = (closestHit.t) / 500.f; //shades planes based on proximity
//finalColor = { scaled_t,scaled_t,scaled_t };
} }
//Update Color in Buffer
finalColor.MaxToOne();
m_pBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBuffer->format,
//const float scaled_t = (closestHit.t - 50.f) / 40.f; //shades spheres based on proximity static_cast<uint8_t>(finalColor.r * 255),
//finalColor = { scaled_t,scaled_t,scaled_t }; static_cast<uint8_t>(finalColor.g * 255),
static_cast<uint8_t>(finalColor.b * 255));
//const float scaled_t = (closestHit.t) / 500.f; //shades planes based on proximity
//finalColor = { scaled_t,scaled_t,scaled_t };
} }
//Update Color in Buffer
finalColor.MaxToOne();
m_pBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBuffer->format,
static_cast<uint8_t>(finalColor.r * 255),
static_cast<uint8_t>(finalColor.g * 255),
static_cast<uint8_t>(finalColor.b * 255));
} }
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <vector>
struct SDL_Window; struct SDL_Window;
struct SDL_Surface; struct SDL_Surface;
@@ -39,6 +40,8 @@ namespace dae
}; };
void ToggleShadows() { m_ShadowsEnabled = !m_ShadowsEnabled; } void ToggleShadows() { m_ShadowsEnabled = !m_ShadowsEnabled; }
void ToggleMultiThreading() { m_IsMultiThreadingEnabled = !m_IsMultiThreadingEnabled; }
private: private:
@@ -52,6 +55,7 @@ namespace dae
LightingMode m_CurrentLightingMode{LightingMode::Combined}; LightingMode m_CurrentLightingMode{LightingMode::Combined};
bool m_ShadowsEnabled{true}; bool m_ShadowsEnabled{true};
bool m_IsMultiThreadingEnabled{ true };
SDL_Window* m_pWindow{}; SDL_Window* m_pWindow{};
SDL_Surface* m_pBuffer{}; SDL_Surface* m_pBuffer{};
@@ -60,5 +64,7 @@ namespace dae
int m_Width{}; int m_Width{};
int m_Height{}; int m_Height{};
float m_AspectRatio{}; float m_AspectRatio{};
std::vector<uint32_t> m_HorizontalIterator, m_VerticalIterator;
}; };
} }

View File

@@ -325,7 +325,7 @@ namespace dae {
} }
void Scene_W4::Initialize() void Scene_W4_Bunny::Initialize()
{ {
m_Camera.origin = { 0.f, 1.f, -5.f }; m_Camera.origin = { 0.f, 1.f, -5.f };
m_Camera.fovAngle = 45.f; m_Camera.fovAngle = 45.f;
@@ -366,7 +366,7 @@ namespace dae {
pMesh = AddTriangleMesh(TriangleCullMode::BackFaceCulling, matLambert_White); pMesh = AddTriangleMesh(TriangleCullMode::BackFaceCulling, matLambert_White);
Utils::ParseOBJ("Resources/Warlock.obj", Utils::ParseOBJ("Resources/lowpoly_bunny.obj",
pMesh->positions, pMesh->positions,
pMesh->normals, pMesh->normals,
pMesh->indices); pMesh->indices);
@@ -382,18 +382,18 @@ namespace dae {
//pMesh->CalculateNormals(); //pMesh->CalculateNormals();
//pMesh->Translate({ 0.f,1.5f,0.f }); //pMesh->Translate({ 0.f,1.5f,0.f });
pMesh->RotateY(90); pMesh->RotateY(60);
pMesh->UpdateTransforms(); pMesh->UpdateTransforms();
// Light // Light
AddPointLight({ 0.f, 5.f, 5.f }, 50.f, ColorRGB{ 1.f, .61f, .45f }); // Backlight AddPointLight({ 0.f, 5.f, 5.f }, 50.f, ColorRGB{ 1.f, .61f, .45f }); // Backlight
//AddPointLight({ -2.5f, 5.f, -5.f }, 70.f, ColorRGB{ 1.f, .8f, .45f }); // Front Light Left AddPointLight({ -2.5f, 5.f, -5.f }, 70.f, ColorRGB{ 1.f, .8f, .45f }); // Front Light Left
//AddPointLight({ 2.5f, 5.f, -5.f }, 50.f, ColorRGB{ .34f, .47f, .68f }); // Front Light Right AddPointLight({ 2.5f, 5.f, -5.f }, 50.f, ColorRGB{ .34f, .47f, .68f }); // Front Light Right
} }
void Scene_W4::Update(dae::Timer* pTimer) void Scene_W4_Bunny::Update(dae::Timer* pTimer)
{ {
Scene::Update(pTimer); Scene::Update(pTimer);
} }

View File

@@ -112,17 +112,17 @@ namespace dae
void Initialize() override; void Initialize() override;
}; };
//WEEK 4 Test Scene //WEEK 4 Bunny Scene
class Scene_W4 final : public Scene class Scene_W4_Bunny final : public Scene
{ {
public: public:
Scene_W4() = default; Scene_W4_Bunny() = default;
~Scene_W4() override = default; ~Scene_W4_Bunny() override = default;
Scene_W4(const Scene_W4&) = delete; Scene_W4_Bunny(const Scene_W4_Bunny&) = delete;
Scene_W4(Scene_W4&&) noexcept = delete; Scene_W4_Bunny(Scene_W4_Bunny&&) noexcept = delete;
Scene_W4& operator=(const Scene_W4&) = delete; Scene_W4_Bunny& operator=(const Scene_W4_Bunny&) = delete;
Scene_W4& operator=(Scene_W4&&) noexcept = delete; Scene_W4_Bunny& operator=(Scene_W4_Bunny&&) noexcept = delete;
void Initialize() override; void Initialize() override;
void Update(dae::Timer* pTimer) override; void Update(dae::Timer* pTimer) override;
@@ -132,7 +132,7 @@ namespace dae
}; };
//WEEK 4 Test Scene //WEEK 4 Reference Scene
class Scene_W4_ReferenceScene final : public Scene class Scene_W4_ReferenceScene final : public Scene
{ {
public: public:

View File

@@ -48,7 +48,9 @@ int main(int argc, char* args[])
const auto pRenderer = new Renderer(pWindow); const auto pRenderer = new Renderer(pWindow);
const auto pScene = new Scene_W4_ReferenceScene(); const auto pScene = new Scene_W4_ReferenceScene();
const auto pScene2 = new Scene_W4_Bunny();
pScene->Initialize(); pScene->Initialize();
pScene2->Initialize();
//Start loop //Start loop
@@ -60,6 +62,7 @@ int main(int argc, char* args[])
float printTimer = 0.f; float printTimer = 0.f;
bool isLooping = true; bool isLooping = true;
bool takeScreenshot = false; bool takeScreenshot = false;
bool isBunnyScene = false;
while (isLooping) while (isLooping)
{ {
//--------- Get input events --------- //--------- Get input events ---------
@@ -82,6 +85,14 @@ int main(int argc, char* args[])
{ {
pRenderer->CycleLightingMode(); pRenderer->CycleLightingMode();
} }
if (e.key.keysym.scancode == SDL_SCANCODE_F4)
{
pRenderer->ToggleMultiThreading();
}
if (e.key.keysym.scancode == SDL_SCANCODE_F5)
{
isBunnyScene = !isBunnyScene;
}
break; break;
} }
@@ -91,10 +102,26 @@ int main(int argc, char* args[])
//--------- Update --------- //--------- Update ---------
pScene->Update(pTimer); if (isBunnyScene)
{
pScene2->Update(pTimer);
}
else
{
pScene->Update(pTimer);
}
//--------- Render --------- //--------- Render ---------
pRenderer->Render(pScene); if (isBunnyScene)
{
pRenderer->Render(pScene2);
}
else
{
pRenderer->Render(pScene);
}
//--------- Timer --------- //--------- Timer ---------
pTimer->Update(); pTimer->Update();
@@ -119,6 +146,7 @@ int main(int argc, char* args[])
//Shutdown "framework" //Shutdown "framework"
delete pScene; delete pScene;
delete pScene2;
delete pRenderer; delete pRenderer;
delete pTimer; delete pTimer;