From b7106c2af81c57e4b249669e9c5c033023c827a7 Mon Sep 17 00:00:00 2001 From: Bram Verhulst Date: Tue, 8 Oct 2024 21:37:45 +0200 Subject: [PATCH] Add camera and shadows (week2) --- project/src/Camera.h | 70 ++++++++++++++++++++++++++++++++++------ project/src/Renderer.cpp | 24 ++++++++++++-- project/src/Scene.cpp | 19 +++++++++-- project/src/Utils.h | 31 +++++++++--------- 4 files changed, 114 insertions(+), 30 deletions(-) diff --git a/project/src/Camera.h b/project/src/Camera.h index 3e62779..78c802c 100644 --- a/project/src/Camera.h +++ b/project/src/Camera.h @@ -33,9 +33,16 @@ namespace dae Matrix CalculateCameraToWorld() { - //todo: W2 -// throw std::runtime_error("Not Implemented Yet"); - return {}; + right = Vector3::Cross(Vector3::UnitY, forward).Normalized(); + up = Vector3::Cross(forward, right).Normalized(); + + Matrix matrix { + Vector4{right, 0}, + Vector4{up, 0}, + Vector4{forward, 0}, + Vector4{origin, 0}, + }; + return matrix; } void Update(Timer* pTimer) @@ -44,14 +51,59 @@ namespace dae //Keyboard Input const uint8_t* pKeyboardState = SDL_GetKeyboardState(nullptr); + { + float speed{10.f}; + if (pKeyboardState[SDL_SCANCODE_W]) { + origin += forward * deltaTime * speed; + } + if (pKeyboardState[SDL_SCANCODE_S]) { + origin -= forward * deltaTime * speed; + } + if (pKeyboardState[SDL_SCANCODE_D]) { + origin += right * deltaTime * speed; + } + if (pKeyboardState[SDL_SCANCODE_A]) { + origin -= right * deltaTime * speed; + } - //Mouse Input - int mouseX{}, mouseY{}; - const uint32_t mouseState = SDL_GetRelativeMouseState(&mouseX, &mouseY); + if (pKeyboardState[SDL_SCANCODE_Q]) { + origin -= Vector3::UnitY * deltaTime * speed; + } + if (pKeyboardState[SDL_SCANCODE_E]) { + origin += Vector3::UnitY * deltaTime * speed; + } + } + int mouseX{}, mouseY{}; + const uint32_t mouseState = SDL_GetRelativeMouseState(&mouseX, &mouseY); - //todo: W2 - //throw std::runtime_error("Not Implemented Yet"); - } + bool dirty = false; + + float speed{ 0.15f }; + + if(mouseX) + { + totalYaw += mouseX * speed; + totalPitch = std::fmod(totalPitch, 180.f); + dirty = true; + } + + if(mouseY) + { + totalPitch += mouseY * speed; + totalPitch = std::clamp(totalPitch, -85.f, 85.f); + dirty = true; + } + + if(dirty) + { + Matrix rotMat{ + Matrix::CreateRotationX(TO_RADIANS * totalPitch) * Matrix::CreateRotationY(TO_RADIANS * totalYaw) + }; + + forward = rotMat.TransformVector(Vector3::UnitZ); + right = rotMat.TransformVector(Vector3::UnitX); + } + } }; } diff --git a/project/src/Renderer.cpp b/project/src/Renderer.cpp index 7dea984..03f2bff 100644 --- a/project/src/Renderer.cpp +++ b/project/src/Renderer.cpp @@ -26,6 +26,8 @@ void Renderer::Render(Scene *pScene) const { auto &materials = pScene->GetMaterials(); auto &lights = pScene->GetLights(); + Matrix CameraToWorld = camera.CalculateCameraToWorld(); + float apsectRatio = static_cast(m_Width) / m_Height; float fov = tan((camera.fovAngle * (PI / 180.f)) / 2); for (int px{}; px < m_Width; ++px) { @@ -35,20 +37,38 @@ void Renderer::Render(Scene *pScene) const { Vector3 rayDir = Vector3{NDCx, NDCy, 1}; + rayDir = CameraToWorld.TransformVector((rayDir)); rayDir.Normalize(); + Ray ray{camera.origin, rayDir}; + //set the color based on the ray direction ColorRGB finalColor{0.f, 0.f, 0.f}; HitRecord closestHit{}; - Plane testPlane{{0.f, -50.f, 0.f}, {0.f, 1.f, 0.f}, 0}; -// GeometryUtils::HitTest_Plane(testPlane, ray, closestHit); pScene->GetClosestHit(ray, closestHit); if (closestHit.didHit) { finalColor = materials[closestHit.materialIndex]->Shade(); + for(const Light& light : lights) + { + Vector3 lightDirection{ LightUtils::GetDirectionToLight(light, closestHit.origin) }; + const float lightDistance = lightDirection.Normalize(); + + const Ray lightRay{ + closestHit.origin + closestHit.normal * 0.01f, + lightDirection, 0.0001f, lightDistance + }; + + if(pScene->DoesHit(lightRay)) + { + finalColor *= 0.5; + break; + } + } + } finalColor.MaxToOne(); diff --git a/project/src/Scene.cpp b/project/src/Scene.cpp index 397bce6..ea1a9e2 100644 --- a/project/src/Scene.cpp +++ b/project/src/Scene.cpp @@ -46,9 +46,22 @@ namespace dae { } - bool Scene::DoesHit(const Ray &ray) const { - //todo W2 - throw std::runtime_error("Not Implemented Yet"); + bool Scene::DoesHit(const Ray& ray) const + { + HitRecord hit; + + for(const Sphere& sphere : m_SphereGeometries) + { + if(GeometryUtils::HitTest_Sphere(sphere, ray, hit, true)) + return true; + } + + for(const Plane& plane : m_PlaneGeometries) + { + if(GeometryUtils::HitTest_Plane(plane, ray, hit, true)) + return true; + } + return false; } diff --git a/project/src/Utils.h b/project/src/Utils.h index ba0914b..e4381cd 100644 --- a/project/src/Utils.h +++ b/project/src/Utils.h @@ -17,27 +17,26 @@ namespace dae if(tInSphere < 0) return false; //Looking away from sphere - const float od2 = std::pow(Vector3::Reject(CameraToOrigin, ray.direction).Magnitude(),2); - const float thc = std::sqrt(radius2 - od2); + float originToInsideDist2 = CameraToOrigin.SqrMagnitude() - tInSphere * tInSphere; + if(originToInsideDist2 > radius2) + return false; // 'inside' point is outside of sphere - float t0 = tInSphere - thc; - float t1 = tInSphere + thc; + float tDiff = std::sqrt(radius2 - originToInsideDist2); + float t = tInSphere - tDiff; - if(t0 < 0 && t1 < 0) return false; //Both intersections are behind the camera + const bool hit = t > ray.min && t < ray.max; - if(t0 < 0) t0 = t1; //If t0 is behind the camera, use t1 - if (!ignoreHitRecord && t0 < hitRecord.t){ - hitRecord.t = t0; - hitRecord.origin = ray.origin + ray.direction * t0; + if (!ignoreHitRecord && hit){ + hitRecord.t = t; + hitRecord.origin = ray.origin + ray.direction * t; hitRecord.normal = (hitRecord.origin - sphere.origin).Normalized(); hitRecord.materialIndex = sphere.materialIndex; hitRecord.didHit = true; - return true; } - return false; + return hit; } @@ -54,8 +53,10 @@ namespace dae float dot = Vector3::Dot(plane.normal, ray.direction); if(dot < 0) { // float t = Vector3::Dot(plane.origin - ray.origin, plane.normal) / dot; - float t = Vector3::Dot(plane.origin - ray.origin, plane.normal) / Vector3::Dot(ray.direction, plane.normal); - bool hit = t >= 0; + float t = Vector3::Dot(plane.origin - ray.origin, plane.normal); + t /= dot; + + const bool hit = t > ray.min && t < ray.max; if(hit && !ignoreHitRecord){ hitRecord.t = t; @@ -113,9 +114,7 @@ namespace dae //Direction from target to light inline Vector3 GetDirectionToLight(const Light& light, const Vector3 origin) { - //todo W3 - throw std::runtime_error("Not Implemented Yet"); - return {}; + return { light.origin - origin }; } inline ColorRGB GetRadiance(const Light& light, const Vector3& target)