it does something

This commit is contained in:
Dynamitos
2025-01-26 19:43:06 +01:00
parent 98020d4455
commit cc2f92aaab
12 changed files with 199 additions and 89 deletions
+4 -4
View File
@@ -10,8 +10,8 @@ int main()
Window window(1920, 1080);
scene.startRender(
Camera{
.position = glm::vec3(0, 10, 10),
.direction = glm::vec3(0, -1, -1),
.position = glm::vec3(5, 5, 5),
.direction = glm::vec3(-1, -1, -1),
},
RenderParameter{
.width = 1920,
@@ -25,8 +25,8 @@ int main()
{
scene.startRender(
Camera{
.position = glm::vec3(0, 10, 10),
.direction = glm::vec3(0, -1, -1),
.position = glm::vec3(5, 5, 5),
.direction = glm::vec3(-1, -1, -1),
},
RenderParameter{
.width = 1920,
+11 -12
View File
@@ -6,9 +6,9 @@
Renderer::Renderer()
{
bvh.addPointLight(PointLight{
.position = glm::vec3(2, 0, 2),
.color = glm::vec3(0, 1, 0),
bvh.addDirectionalLight(DirectionalLight{
.direction = glm::normalize(glm::vec3(-0.4f, -0.2f, -0.6f)),
.color = glm::vec3(1, 1, 1),
});
bvh.addModels(ModelLoader::loadModel("../res/models/cube.fbx"),
glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
@@ -40,6 +40,8 @@ glm::vec3 rand01(glm::uvec3 x)
return glm::vec3(x) * (1.0f / float(0xffffffffU));
}
thread_local glm::vec3 rnd01;
void Renderer::render(Camera camera, RenderParameter params)
{
for (int samp = 0; samp < params.numSamples; ++samp)
@@ -64,8 +66,8 @@ void Renderer::render(Camera camera, RenderParameter params)
//-- sample sensor
glm::uvec2 pix = glm::uvec2(w, h);
glm::vec3 rnd1 = rand01(glm::uvec3(pix, samp));
glm::vec2 rnd2 = 2.0f * glm::vec2(rnd1); // vvv tent filter sample
rnd01 = rand01(glm::uvec3(pix, samp));
glm::vec2 rnd2 = 2.0f * glm::vec2(rnd01); // vvv tent filter sample
glm::vec2 tent =
glm::vec2(rnd2.x < 1 ? sqrt(rnd2.x) - 1 : 1 - sqrt(2 - rnd2.x), rnd2.y < 1 ? sqrt(rnd2.y) - 1 : 1 - sqrt(2 - rnd2.y));
glm::vec2 s =
@@ -82,20 +84,17 @@ void Renderer::render(Camera camera, RenderParameter params)
glm::vec3 lensX = glm::cross(lensN, glm::vec3(0, 1, 0)); // the exact vector doesnt matter
glm::vec3 lensY = glm::cross(lensN, lensX);
glm::vec3 lensSample = lensP + rnd1.x * camera.A * lensX + rnd1.y * camera.A * lensY;
glm::vec3 lensSample = lensP + rnd01.x * camera.A * lensX + rnd01.y * camera.A * lensY;
glm::vec3 focalPoint = cam.origin + (camera.S_O + S_I) * cam.direction;
float t = glm::dot(focalPoint - r.origin, lensN) / glm::dot(r.direction, lensN);
glm::vec3 focus = r.origin + t * r.direction;
r = Ray(lensSample, normalize(focus - lensSample)); // TODO: Fix lens
auto intersection = bvh.traceRay(r);
Payload payload;
bvh.traceRay(r, payload, 1e-4, 1e20);
if (intersection.has_value())
{
accumulator[w + h * params.width] = intersection->shadingInfo.albedo;
}
accumulator[w + h * params.width] += payload.accumulatedRadiance / float(params.numSamples);
}
co_return;
}(w, samp));
+132 -28
View File
@@ -1,5 +1,6 @@
#include "Scene.h"
#include <algorithm>
#include <numbers>
#include <ranges>
void Scene::addModel(PModel model, glm::mat4 transform)
@@ -36,7 +37,8 @@ void Scene::generate()
for (uint32_t i = 0; i < model->indices.size(); ++i)
{
indicesPool.push_back(model->indices[i]);
edgesPool.push_back(model->edges[i]);
edgesPool.push_back(model->edges[i * 2 + 0]);
edgesPool.push_back(model->edges[i * 2 + 1]);
faceNormalsPool.push_back(model->faceNormals[i]);
}
pendingNodes.push_back(std::make_unique<Node>(model->boundingBox, ref));
@@ -73,9 +75,11 @@ void Scene::generate()
hierarchy = std::move(pendingNodes[0]);
}
std::optional<IntersectionInfo> Scene::traceRay(Ray ray) const
extern glm::vec3 rnd01;
void Scene::traceRay(Ray ray, Payload& payload, const float tmin, const float tmax) const noexcept
{
auto results = generateIntersections(hierarchy, ray);
auto results = generateIntersections(hierarchy, ray, tmin, tmax);
float closestT = std::numeric_limits<float>::max();
IntersectionInfo info;
for (uint32_t i = 0; i < results.size(); ++i)
@@ -88,31 +92,85 @@ std::optional<IntersectionInfo> Scene::traceRay(Ray ray) const
}
if (closestT < std::numeric_limits<float>::max())
{
return info;
// russian roulette ray termination
float p = std::max(std::max(info.brdf.albedo.x, info.brdf.albedo.y), info.brdf.albedo.z);
if (payload.depth > 5)
{
if (rnd01.z >= p)
return;
else
payload.accumulatedMaterial /= p;
}
// emissive
payload.accumulatedRadiance += payload.accumulatedMaterial * info.brdf.emissive * payload.emissive;
payload.accumulatedMaterial *= info.brdf.albedo;
// direct lighting
for (const auto& d : directionalLights)
{
// if there is an intersection, the light is occluded so no lighting
if (!testIntersection(hierarchy, Ray(info.hitInfo.position, -d.direction), 1e-4, 1e20))
{
payload.accumulatedRadiance += info.brdf.evaluate(info.hitInfo, -ray.direction, d.direction, d.color);
}
}
for (const auto& p : pointLights)
{
glm::vec3 lightDir = p.position - info.hitInfo.position;
// if (!testIntersection(hierarchy, Ray(info.hitInfo.position, -lightDir), 1e-4, 1))
{
float d = glm::length(lightDir);
float illuminance = std::max(1 - d / p.attenuation, 0.0f);
payload.accumulatedRadiance += illuminance * info.brdf.evaluate(info.hitInfo, -ray.direction, lightDir, p.color);
}
return {};
}
std::vector<IntersectionInfo> Scene::generateIntersections(const PNode& currentNode, Ray ray) const
// TODO: Next Event Estimation for mesh lights
// indirect lighting
float r1 = 2 * std::numbers::pi * rnd01.x;
float r2 = rnd01.y;
float r2s = sqrt(r2);
glm::vec3 w = info.hitInfo.normalLight;
glm::vec3 u = glm::normalize(glm::cross(std::abs(w.x) > 0.1 ? glm::vec3(0, 1, 0) : glm::vec3(1, 0, 0), w));
glm::vec3 v = glm::cross(w, u);
ray = Ray(info.hitInfo.position, glm::normalize(u * cos(r1) * r2s + v * sin(r1) * r2s + w * sqrt(1 - r2)));
payload.emissive = 0;
payload.depth++;
traceRay(ray, payload, tmin, tmax);
}
}
bool Scene::testIntersection(const PNode& currentNode, const Ray ray, const float tmin, float tmax) const noexcept
{
if (!currentNode->aabb.intersects(ray, 0, std::numeric_limits<float>::max()))
if (!currentNode->aabb.intersects(ray, tmin, tmax))
{
return false;
}
if (currentNode->model.numIndices > 0)
{
return testModel(currentNode->model, ray, tmin, tmax);
}
auto leftResults = testIntersection(currentNode->left, ray, tmin, tmax);
auto rightResults = testIntersection(currentNode->right, ray, tmin, tmax);
return leftResults || rightResults;
}
std::vector<IntersectionInfo> Scene::generateIntersections(const PNode& currentNode, const Ray ray, const float tmin,
float tmax) const noexcept
{
if (!currentNode->aabb.intersects(ray, tmin, tmax))
{
return {};
}
if (currentNode->model.numIndices > 0)
{
auto result = intersectModel(currentNode->model, ray);
if (result.has_value())
{
return {*result};
return intersectModel(currentNode->model, ray, tmin, tmax);
}
else
{
return {};
}
}
auto leftResults = generateIntersections(currentNode->left, ray);
auto rightResults = generateIntersections(currentNode->right, ray);
auto leftResults = generateIntersections(currentNode->left, ray, tmin, tmax);
auto rightResults = generateIntersections(currentNode->right, ray, tmin, tmax);
for (auto& it : rightResults)
{
@@ -121,9 +179,8 @@ std::vector<IntersectionInfo> Scene::generateIntersections(const PNode& currentN
return leftResults;
}
std::optional<IntersectionInfo> Scene::intersectModel(const ModelReference& reference, const Ray ray) const
bool Scene::testModel(const ModelReference& reference, const Ray ray, const float tmin, float tmax) const noexcept
{
std::optional<IntersectionInfo> intersection = {};
float distance = 0;
for (size_t posIndex = 0, edgeIndex = 0, normalIndex = 0; posIndex < reference.numIndices; posIndex++, edgeIndex += 2, normalIndex++)
@@ -163,29 +220,76 @@ std::optional<IntersectionInfo> Scene::intersectModel(const ModelReference& refe
if (resultVector.z < 0 || resultVector.z > 1)
continue;
if (resultVector.x < 1e-6)
if (resultVector.x < tmin || resultVector.x > tmax)
continue;
return true;
}
return false;
}
std::vector<IntersectionInfo> Scene::intersectModel(const ModelReference& reference, const Ray ray, const float tmin,
float tmax) const noexcept
{
std::vector<IntersectionInfo> intersection = {};
float distance = 0;
for (size_t posIndex = 0, edgeIndex = 0, normalIndex = 0; posIndex < reference.numIndices; posIndex++, edgeIndex += 2, normalIndex++)
{
const auto i0 = indicesPool[reference.indicesOffset + posIndex].x;
const auto i1 = indicesPool[reference.indicesOffset + posIndex].y;
const auto i2 = indicesPool[reference.indicesOffset + posIndex].z;
const auto& p0 = positionPool[reference.positionOffset + i0];
const auto& p1 = positionPool[reference.positionOffset + i1];
const auto& p2 = positionPool[reference.positionOffset + i2];
const auto& t0 = texCoordsPool[reference.positionOffset + i0];
const auto& t1 = texCoordsPool[reference.positionOffset + i1];
const auto& t2 = texCoordsPool[reference.positionOffset + i2];
const auto& e0 = edgesPool[reference.indicesOffset + edgeIndex];
const auto& e1 = edgesPool[reference.indicesOffset + edgeIndex + 1];
const auto& n = faceNormalsPool[reference.indicesOffset + normalIndex];
const auto s = ray.origin - p0;
const auto s1 = glm::cross(ray.direction, e1);
const auto s2 = glm::cross(s, e0);
const float fraction = 1.0f / glm::dot(s1, e0);
const auto resultVector = glm::vec3(glm::dot(s2, e1), glm::dot(s1, s), glm::dot(s2, ray.direction)) * fraction;
const float b3 = 1.0f - resultVector.y - resultVector.z;
const auto texCoords = t0 * resultVector.y + t1 * resultVector.z + t2 * b3;
if (b3 < 0 || b3 > 1)
continue;
if (resultVector.y < 0 || resultVector.y > 1)
continue;
if (resultVector.z < 0 || resultVector.z > 1)
continue;
if (!intersection.has_value() || resultVector.x < distance)
{
intersection = IntersectionInfo{
if (resultVector.x < tmin || resultVector.x > tmax)
continue;
intersection.push_back(IntersectionInfo{
.hitInfo =
{
.t = resultVector.x,
.position = ray.origin + ray.direction * resultVector.x,
.normal = n,
.normalLight = n, // todo: flip based on something, idk what
.texCoords = texCoords,
},
.shadingInfo =
.brdf =
{
.albedo = glm::vec3(texCoords, 0.0f),
.emissive = glm::vec3(0.0f, 0.0f, 0.0f),
.type = MaterialType::DIFFUSE,
},
};
});
distance = resultVector.x;
}
}
return intersection;
}
+13 -10
View File
@@ -15,27 +15,27 @@ struct ModelReference
struct PointLight
{
glm::vec3 position;
glm::vec3 color;
float attenuation;
glm::vec3 position = glm::vec3(0, 0, 0);
glm::vec3 color = glm::vec3(1, 1, 1);
float attenuation = 1;
};
struct DirectionalLight
{
glm::vec3 direction;
glm::vec3 color;
glm::vec3 direction = glm::vec3(0, 1, 0);
glm::vec3 color = glm::vec3(1, 1, 1);
};
class Scene
{
public:
void addPointLight(PointLight point) { points.push_back(point); }
void addPointLight(PointLight point) { pointLights.push_back(point); }
void addDirectionalLight(DirectionalLight dir) { directionalLights.push_back(dir); }
void addModel(PModel model, glm::mat4 transform);
void addModels(std::vector<PModel> models, glm::mat4 transform);
void generate();
std::optional<IntersectionInfo> traceRay(Ray ray) const;
void traceRay(Ray ray, Payload& payload, const float tmin, const float tmax) const noexcept;
private:
std::vector<glm::vec3> positionPool;
@@ -44,7 +44,7 @@ private:
std::vector<glm::vec3> edgesPool;
std::vector<glm::vec3> faceNormalsPool;
std::vector<PointLight> points;
std::vector<PointLight> pointLights;
std::vector<DirectionalLight> directionalLights;
DECLARE_REF(Node)
@@ -60,6 +60,9 @@ private:
PNode hierarchy;
std::vector<PModel> models;
std::vector<IntersectionInfo> generateIntersections(const PNode& currentNode, Ray ray) const;
std::optional<IntersectionInfo> intersectModel(const ModelReference& reference, Ray ray) const;
// tests if a ray intersects any geometry, no hit information, for shadow rays
bool testIntersection(const PNode& currentNode, const Ray ray, const float tmin, const float tmax) const noexcept;
std::vector<IntersectionInfo> generateIntersections(const PNode& currentNode, const Ray ray, const float tmin, const float tmax) const noexcept;
bool testModel(const ModelReference& reference, const Ray ray, const float tmin, const float tmax) const noexcept;
std::vector<IntersectionInfo> intersectModel(const ModelReference& reference, const Ray ray, const float tmin, const float tmax) const noexcept;
};
+3 -1
View File
@@ -1,7 +1,9 @@
#include "BRDF.h"
#include "Model.h"
glm::vec3 BlinnPhong::evaluate(HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor)
glm::vec3 BRDF::evaluate(HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor)
{
// todo: switch for materialtype, this is blinnphong
glm::vec3 normal = hit.normal;
float diffuse = std::max(glm::dot(normal, lightDir), 0.0f);
glm::vec3 h = glm::normalize(lightDir + viewDir);
+6 -5
View File
@@ -1,17 +1,18 @@
#pragma once
#include "Material.h"
#include <glm/glm.hpp>
class BRDF
enum class MaterialType
{
virtual glm::vec3 evaluate(HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor) = 0;
BlinnPhong
};
class BlinnPhong : public BRDF
struct BRDF
{
glm::vec3 albedo = glm::vec3(1, 1, 1);
float alpha = 1;
glm::vec3 specularColor = glm::vec3(1, 1, 1);
float shininess = 0;
glm::vec3 emissive = glm::vec3(0, 0, 0);
virtual glm::vec3 evaluate(HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor);
MaterialType materialType;
glm::vec3 evaluate(struct HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor);
};
+8 -2
View File
@@ -1,6 +1,12 @@
#include "Material.h"
#include "BRDF.h"
std::unique_ptr<BRDF> Material::evaluate(HitInfo hitInfo)
BRDF Material::evaluate(HitInfo hitInfo)
{
return std::make_unique<BlinnPhong>();
return BRDF{
.albedo = glm::vec3(hitInfo.texCoords, 0),
.alpha = 1,
.emissive = glm::vec3(0, 0, 0),
.materialType = MaterialType::BlinnPhong,
};
}
+1 -8
View File
@@ -4,17 +4,10 @@
#include "Ray.h"
#include "BRDF.h"
enum class MaterialType
{
DIFFUSE,
SPECULAR,
REFRACTIVE,
};
class Material
{
public:
std::unique_ptr<BRDF> evaluate(HitInfo hitInfo);
BRDF evaluate(HitInfo hitInfo);
PTexture albedoTexture;
PTexture emissiveTexture;
};
+1 -1
View File
@@ -8,7 +8,7 @@
struct IntersectionInfo
{
HitInfo hitInfo;
MaterialInfo shadingInfo;
BRDF brdf;
};
class Model
{
+6 -3
View File
@@ -4,15 +4,15 @@
struct Payload
{
glm::vec3 accumulatedRadiance = glm::vec3(0);
glm::vec3 accumulatedMaterial = glm::vec3(0);
glm::vec3 accumulatedMaterial = glm::vec3(1);
uint32_t depth = 0;
float emissive = 1;
};
struct Ray
{
glm::vec3 origin;
glm::vec3 direction;
uint32_t depth = 0;
Payload payload;
};
struct HitInfo
@@ -20,5 +20,8 @@ struct HitInfo
float t;
glm::vec3 position;
glm::vec3 normal;
// not entirely sure what that does
// its the normal being flipped based on some dot product
glm::vec3 normalLight;
glm::vec2 texCoords;
};
+1 -1
View File
@@ -51,7 +51,7 @@ Window::Window(int width, int height) : width(width), height(height)
uniform sampler2D tex;
void main() { color = texture(tex, texcoords); });
void main() { color = texture(tex, vec2(texcoords.x, -texcoords.y)); });
glShaderSource(vertShader, 1, &vertCode, nullptr);
glCompileShader(vertShader);
int success;
-1
View File
@@ -20,6 +20,5 @@ class Window
GLuint program;
GLuint vertShader;
GLuint fragShader;
GLuint textureLocation;
GLFWwindow* window;
};