Files
GP1-Raytracer/project/src/Utils.h
2024-10-02 12:29:02 +02:00

203 lines
5.6 KiB
C++

#pragma once
#include <fstream>
#include "Maths.h"
#include "DataTypes.h"
namespace dae
{
namespace GeometryUtils
{
#pragma region Sphere HitTest
//SPHERE HIT-TESTS
inline bool HitTest_Sphere(const Sphere& sphere, const Ray& ray, HitRecord& hitRecord, bool ignoreHitRecord = false)
{
const float radius2 = sphere.radius * sphere.radius;
const Vector3 CameraToOrigin = sphere.origin - ray.origin;
const float tInSphere = Vector3::Dot(CameraToOrigin, ray.direction);
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 t0 = tInSphere - thc;
float t1 = tInSphere + thc;
if(t0 < 0 && t1 < 0) return false; //Both intersections are behind the camera
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;
hitRecord.normal = (hitRecord.origin - sphere.origin).Normalized();
hitRecord.materialIndex = sphere.materialIndex;
hitRecord.didHit = true;
return true;
}
return false;
}
inline bool HitTest_Sphere(const Sphere& sphere, const Ray& ray)
{
HitRecord temp{};
return HitTest_Sphere(sphere, ray, temp, true);
}
#pragma endregion
#pragma region Plane HitTest
//PLANE HIT-TESTS
inline bool HitTest_Plane(const Plane& plane, const Ray& ray, HitRecord& hitRecord, bool ignoreHitRecord = false)
{
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;
if(hit && !ignoreHitRecord){
hitRecord.t = t;
hitRecord.origin = ray.origin + ray.direction * t;
hitRecord.normal = plane.normal;
hitRecord.materialIndex = plane.materialIndex;
hitRecord.didHit = true;
}
return hit;
}
return false;
}
inline bool HitTest_Plane(const Plane& plane, const Ray& ray)
{
HitRecord temp{};
return HitTest_Plane(plane, ray, temp, true);
}
#pragma endregion
#pragma region Triangle HitTest
//TRIANGLE HIT-TESTS
inline bool HitTest_Triangle(const Triangle& triangle, const Ray& ray, HitRecord& hitRecord, bool ignoreHitRecord = false)
{
//todo W5
throw std::runtime_error("Not Implemented Yet");
return false;
}
inline bool HitTest_Triangle(const Triangle& triangle, const Ray& ray)
{
HitRecord temp{};
return HitTest_Triangle(triangle, ray, temp, true);
}
#pragma endregion
#pragma region TriangeMesh HitTest
inline bool HitTest_TriangleMesh(const TriangleMesh& mesh, const Ray& ray, HitRecord& hitRecord, bool ignoreHitRecord = false)
{
//todo W5
throw std::runtime_error("Not Implemented Yet");
return false;
}
inline bool HitTest_TriangleMesh(const TriangleMesh& mesh, const Ray& ray)
{
HitRecord temp{};
return HitTest_TriangleMesh(mesh, ray, temp, true);
}
#pragma endregion
}
namespace LightUtils
{
//Direction from target to light
inline Vector3 GetDirectionToLight(const Light& light, const Vector3 origin)
{
//todo W3
throw std::runtime_error("Not Implemented Yet");
return {};
}
inline ColorRGB GetRadiance(const Light& light, const Vector3& target)
{
//todo W3
throw std::runtime_error("Not Implemented Yet");
return {};
}
}
namespace Utils
{
//Just parses vertices and indices
#pragma warning(push)
#pragma warning(disable : 4505) //Warning unreferenced local function
static bool ParseOBJ(const std::string& filename, std::vector<Vector3>& positions, std::vector<Vector3>& normals, std::vector<int>& indices)
{
std::ifstream file(filename);
if (!file)
return false;
std::string sCommand;
// start a while iteration ending when the end of file is reached (ios::eof)
while (!file.eof())
{
//read the first word of the string, use the >> operator (istream::operator>>)
file >> sCommand;
//use conditional statements to process the different commands
if (sCommand == "#")
{
// Ignore Comment
}
else if (sCommand == "v")
{
//Vertex
float x, y, z;
file >> x >> y >> z;
positions.push_back({ x, y, z });
}
else if (sCommand == "f")
{
float i0, i1, i2;
file >> i0 >> i1 >> i2;
indices.push_back((int)i0 - 1);
indices.push_back((int)i1 - 1);
indices.push_back((int)i2 - 1);
}
//read till end of line and ignore all remaining chars
file.ignore(1000, '\n');
if (file.eof())
break;
}
//Precompute normals
for (uint64_t index = 0; index < indices.size(); index += 3)
{
uint32_t i0 = indices[index];
uint32_t i1 = indices[index + 1];
uint32_t i2 = indices[index + 2];
Vector3 edgeV0V1 = positions[i1] - positions[i0];
Vector3 edgeV0V2 = positions[i2] - positions[i0];
Vector3 normal = Vector3::Cross(edgeV0V1, edgeV0V2);
if (std::isnan(normal.x))
{
int k = 0;
}
normal.Normalize();
if (std::isnan(normal.x))
{
int k = 0;
}
normals.push_back(normal);
}
return true;
}
#pragma warning(pop)
}
}