Primitive sampling

This commit is contained in:
IlyaShurupov 2023-10-18 12:05:01 +03:00 committed by Ilya Shurupov
parent 368ae81251
commit 77db3f4ab5
9 changed files with 242 additions and 80 deletions

View file

@ -35,6 +35,10 @@ bool TrigCache::castRay(const Ray& ray) const {
static halnf a, f, u, v; static halnf a, f, u, v;
static halnf t; static halnf t;
if (ray.dir.dot(mNormal) > 0) {
return false;
}
h = ray.dir.cross(mEdgeP1P3); h = ray.dir.cross(mEdgeP1P3);
a = mEdgeP1P2.dot(h); a = mEdgeP1P2.dot(h);

View file

@ -51,7 +51,7 @@ void renderCommand(const String& scenePath) {
auto start = get_time(); auto start = get_time();
rayt.render(scene, output); rayt.render(scene, output, settings);
auto end = get_time(); auto end = get_time();

View file

@ -46,26 +46,68 @@ bool loadMeshes(tp::Scene& scene, const tp::String& objetsPath) {
return scene.mObjects.size(); return scene.mObjects.size();
} }
bool getVector(lua_State* L, const char* name, tp::Vec3F& out, const char* parent) { // Function to read a Lua table representing RenderSettings
lua_getglobal(L, name); int readRenderSettings(lua_State* L, tp::RayTracer::RenderSettings& settings) {
lua_getglobal(L, "RenderSettings");
if (lua_istable(L, -1)) { if (!lua_istable(L, -1)) {
lua_pushstring(L, "x"); printf("RenderSettings is not a table.\n");
lua_gettable(L, -2); return 0; // Error
}
// Read depth field
lua_getfield(L, -1, "depth");
if (lua_isnumber(L, -1)) { if (lua_isnumber(L, -1)) {
out.x = lua_tonumber(L, -1); settings.depth = (int) lua_tonumber(L, -1);
} else { } else {
printf("Component of vector '%s' is not found in %s\n\n", name, parent); printf("RenderSettings 'depth' field is missing or not a number.\n");
return false; lua_pop(L, 1); // Pop the 'depth' field
return 0; // Error
}
lua_pop(L, 1); // Pop the 'depth' field
// Read spray field
lua_getfield(L, -1, "spray");
if (lua_isnumber(L, -1)) {
settings.spray = (int) lua_tonumber(L, -1);
} else {
printf("RenderSettings 'spray' field is missing or not a number.\n");
lua_pop(L, 1); // Pop the 'spray' field
return 0; // Error
}
lua_pop(L, 1); // Pop the 'spray' field
return 1; // Success
} }
lua_pop(L, 1); // Function to read a Lua table representing a light
int readLight(lua_State* L, tp::PointLight* light) {
} else { lua_getfield(L, -1, "pos"); // Get the "pos" field from the light table
printf("Vector '%s' is not found in %s\n\n", name, parent); if (!lua_istable(L, -1)) {
return false; printf("Light is missing the 'pos' table.\n");
return 0; // Error
} }
for (int i = 0; i < 3; i++) {
lua_rawgeti(L, -1, i + 1); // Index is 1-based in Lua
if (!lua_isnumber(L, -1)) {
printf("Light 'pos' field is not a number at index %d.\n", i);
lua_pop(L, 2); // Pop both the number and the 'pos' table
return 0; // Error
}
light->pos[i] = lua_tonumber(L, -1);
lua_pop(L, 1); // Pop the number
}
lua_pop(L, 1); // Pop the 'pos' table
lua_getfield(L, -1, "intensity"); // Get the "intensity" field from the light table
if (!lua_isnumber(L, -1)) {
printf("Light is missing the 'intensity' field or it's not a number.\n");
lua_pop(L, 1); // Pop the 'intensity' field
return 0; // Error
}
light->intensity = lua_tonumber(L, -1);
lua_pop(L, 1); // Pop the 'intensity' field
return 1; // Success
} }
void loadScene(tp::Scene& scene, const tp::String& scenePath, tp::RayTracer::RenderSettings& settings) { void loadScene(tp::Scene& scene, const tp::String& scenePath, tp::RayTracer::RenderSettings& settings) {
@ -154,5 +196,38 @@ void loadScene(tp::Scene& scene, const tp::String& scenePath, tp::RayTracer::Ren
scene.mCamera.setFar(100); scene.mCamera.setFar(100);
scene.mCamera.setRatio((tp::halnf) size_y / (tp::halnf) size_x); scene.mCamera.setRatio((tp::halnf) size_y / (tp::halnf) size_x);
// ---------- LIGHTS
{
lua_getglobal(L, "Lights");
if (!lua_istable(L, -1)) {
printf("Lights is not a table.\n");
lua_close(L);
return; // Error
}
// Read and process each light in the "Lights" table
int numLights = lua_rawlen(L, -1); // Get the number of lights in the table
for (int i = 1; i <= numLights; i++) {
lua_rawgeti(L, -1, i); // Get the i-th element (light) from the table
if (lua_istable(L, -1)) {
tp::PointLight light;
if (!readLight(L, &light)) {
printf("Cant read lights data\n");
lua_close(L);
return; // Error
}
scene.mLights.append(light);
}
lua_pop(L, 1); // Pop the i-th light table
}
}
// ----------- settings --------------
if (!readRenderSettings(L, settings)) {
printf("Cant Read Render Settings");
lua_close(L);
return; // Error
}
lua_close(L); lua_close(L);
} }

View file

@ -6,3 +6,10 @@ Camera = {
size_x = 400, size_x = 400,
size_y = 600, size_y = 600,
} }
Lights = {
{
pos = { 4, 3, 3 },
intensity = 4
}
}

View file

@ -11,31 +11,31 @@ v -1.039076 -1.039076 -1.285234
v 1.039076 -1.039076 1.792917 v 1.039076 -1.039076 1.792917
v 1.039076 -1.039076 -1.285234 v 1.039076 -1.039076 -1.285234
vt 0.625000 0.500000 vt 0.625000 0.500000
vt 0.875000 0.500000
vt 0.875000 0.750000
vt 0.625000 0.750000 vt 0.625000 0.750000
vt 0.875000 0.750000
vt 0.875000 0.500000
vt 0.375000 0.750000 vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000 vt 0.375000 1.000000
vt 0.625000 1.000000
vt 0.375000 0.000000 vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000 vt 0.375000 0.250000
vt 0.625000 0.250000
vt 0.625000 0.000000
vt 0.125000 0.500000 vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.125000 0.750000 vt 0.125000 0.750000
vn 0.0000 0.0000 1.0000 vt 0.375000 0.500000
vn 1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 0.0000 0.0000 -1.0000 vn 0.0000 0.0000 -1.0000
vn -1.0000 0.0000 0.0000 vn -1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 1.0000 0.0000 0.0000
usemtl Material usemtl Material
s off s off
f 1/1/1 5/2/1 7/3/1 3/4/1 f 1/1/1 3/2/1 7/3/1 5/4/1
f 4/5/2 3/4/2 7/6/2 8/7/2 f 4/5/2 8/6/2 7/7/2 3/2/2
f 8/8/3 7/9/3 5/10/3 6/11/3 f 8/8/3 6/9/3 5/10/3 7/11/3
f 6/12/4 2/13/4 4/5/4 8/14/4 f 6/12/4 8/13/4 4/5/4 2/14/4
f 6/11/5 5/10/5 1/1/5 2/13/5 f 6/9/5 2/14/5 1/1/5 5/10/5
o Cube.001 o Cube.001
v 0.411013 -0.208216 -1.264212 v 0.411013 -0.208216 -1.264212
v 0.411013 -0.208216 -0.612621 v 0.411013 -0.208216 -0.612621

View file

@ -3,6 +3,22 @@ Meshes = "meshes.obj"
Camera = { Camera = {
pos = { 0.5, 4.5, 0.2 }, pos = { 0.5, 4.5, 0.2 },
size_x = 500, size_x = 600,
size_y = 700, size_y = 800,
}
Lights = {
{
pos = { -0.5, 3.5, 1 },
intensity = 1
},
{
pos = { 0, 0, 1 },
intensity = 0.5
},
}
RenderSettings = {
depth = 1,
spray = 10,
} }

View file

@ -10,75 +10,7 @@
#include <cstdio> #include <cstdio>
using namespace tp; /*
ModuleManifest* sDependencies[] = {&gModuleMath, &gModuleCommandLine, &gModuleConnection, nullptr};
ModuleManifest tp::gModuleRayTracer = ModuleManifest("RayTracer", nullptr, nullptr, sDependencies);
void RayTracer::castRay(const Ray& ray, RayCastData& out, alnf far) {
out.hit = false;
far *= far;
for (auto obj : mScene->mObjects) {
for (auto trig : obj->mCache.TrigCaches) {
if (trig->castRay(ray)) {
// printf("Hit\n");
auto dist = (trig->getHitPos() - ray.pos).length2();
if (far > dist) {
out.trig = &trig.data();
out.hitPos = trig->getHitPos();
out.obj = &obj.data();
out.hit = true;
far = dist;
}
}
}
}
}
void RayTracer::render(const Scene& scene, RayTracer::RenderBuffer& buff) {
mScene = &scene;
mBuff = &buff;
auto pos = mScene->mCamera.getPos();
auto fov = mScene->mCamera.getFOV();
auto height = sqrt(mScene->mCamera.getRatio());
auto width = 1.f / height;
auto forward = mScene->mCamera.getForward();
auto up = mScene->mCamera.getUp();
auto right = forward.cross(up);
auto planeCenter = pos + (forward * halnf(width / (2.f * tan(fov / 2.f))));
auto planeCenterOffset = (up * (halnf) height / 2.f) - (right * (halnf) width / 2.f);
auto planeLeftTop = planeCenter + planeCenterOffset;
RayCastData castData;
Ray ray = {
{0, 0, 0},
pos
};
Vec3F iterPoint = {0, 0, 0};
Vec3F deltaX = right * halnf(width / (alnf) buff.size().x);
Vec3F deltaY = up * halnf(-height / (alnf) buff.size().y);
for (RayTracer::RenderBuffer::Index i = 0; i < buff.size().x; i++) {
for (RayTracer::RenderBuffer::Index j = 0; j < buff.size().y; j++) {
iterPoint = planeLeftTop + ((deltaX * (halnf) i) + (deltaY * (halnf) j));
ray.dir = (iterPoint - pos).unitV();
castRay(ray, castData, mScene->mCamera.getFar());
if (castData.hit) {
Vec3F normal = castData.trig->getNormal();
if (1) { if (1) {
const auto& points = castData.obj->mCache.TransformedPoints; const auto& points = castData.obj->mCache.TransformedPoints;
const auto& normals = castData.obj->mCache.TransformedNormals; const auto& normals = castData.obj->mCache.TransformedNormals;
@ -108,17 +40,132 @@ void RayTracer::render(const Scene& scene, RayTracer::RenderBuffer& buff) {
// Interpolate the normal using barycentric coordinates // Interpolate the normal using barycentric coordinates
normal = n1 * barycentric.x + n2 * barycentric.y + n3 * barycentric.z; normal = n1 * barycentric.x + n2 * barycentric.y + n3 * barycentric.z;
} }
*/
using namespace tp;
ModuleManifest* sDependencies[] = {&gModuleMath, &gModuleCommandLine, &gModuleConnection, nullptr};
ModuleManifest tp::gModuleRayTracer = ModuleManifest("RayTracer", nullptr, nullptr, sDependencies);
void RayTracer::castRay(const Ray& ray, RayCastData& out, alnf far) {
out.hit = false;
far *= far;
for (auto obj : mScene->mObjects) {
for (auto trig : obj->mCache.TrigCaches) {
if (trig->castRay(ray)) {
// printf("Hit\n");
auto dist = (trig->getHitPos() - ray.pos).length2();
if (far > dist && dist > EPSILON) {
out.trig = &trig.data();
out.hitPos = trig->getHitPos();
out.obj = &obj.data();
out.hit = true;
far = dist;
}
}
}
}
}
void RayTracer::cycle(const RayCastData& castData, LightData& out, uhalni depth) {
if (depth) {
depth--;
Vec3F normal = castData.trig->getNormal();
normal.normalize(); normal.normalize();
RGBA col = {normal.x * 0.5f + 0.5f, normal.y * 0.5f + 0.5f, normal.z * 0.5f + 0.5f, 1.f}; const auto delta1 = castData.trig->mEdgeP1P2.unitV();
const auto delta2 = normal.cross(delta1);
for (auto idx : Range(mSettings.spray)) {
RayCastData materialCastData;
LightData lightData;
auto d1 = ((halnf) randomFloat() - 0.5f) * 2;
auto d2 = ((halnf) randomFloat() - 0.5f) * 2;
auto sprayNormal = (normal + delta1 * d1 + delta2 * d2).normalize();
castRay({sprayNormal, castData.hitPos}, materialCastData, mScene->mCamera.getFar());
if (materialCastData.hit) {
cycle(materialCastData, lightData, depth);
out.intensity += lightData.intensity * 0.2;
}
}
}
// cast for light
for (auto light : mScene->mLights) {
RayCastData lightCastData;
auto dir = light->pos - castData.hitPos;
auto length = (halnf) dir.length();
Ray lightRay = {dir.unitV(), castData.hitPos};
if (lightRay.dir.dot(castData.trig->mNormal) < 0) {
continue;
}
castRay(lightRay, lightCastData, length);
if (lightCastData.hit) {
continue;
}
out.intensity += light->intensity / (length * length);
}
}
void RayTracer::render(const Scene& scene, RayTracer::RenderBuffer& buff, const RenderSettings& settings) {
mScene = &scene;
mBuff = &buff;
mSettings = settings;
auto pos = mScene->mCamera.getPos();
auto fov = mScene->mCamera.getFOV();
auto height = sqrt(mScene->mCamera.getRatio());
auto width = 1.f / height;
auto forward = mScene->mCamera.getForward();
auto up = mScene->mCamera.getUp();
auto right = forward.cross(up);
auto planeCenter = pos + (forward * halnf(width / (2.f * tan(fov / 2.f))));
auto planeCenterOffset = (up * (halnf) height / 2.f) - (right * (halnf) width / 2.f);
auto planeLeftTop = planeCenter + planeCenterOffset;
RayCastData castData;
Ray ray = {
{0, 0, 0},
pos
};
Vec3F iterPoint = {0, 0, 0};
Vec3F deltaX = right * halnf(width / (alnf) buff.size().x);
Vec3F deltaY = up * halnf(-height / (alnf) buff.size().y);
for (RayTracer::RenderBuffer::Index i = 0; i < buff.size().x; i++) {
for (RayTracer::RenderBuffer::Index j = 0; j < buff.size().y; j++) {
iterPoint = planeLeftTop + ((deltaX * (halnf) i) + (deltaY * (halnf) j));
ray.dir = (iterPoint - pos).unitV();
castRay(ray, castData, mScene->mCamera.getFar());
if (castData.hit) {
LightData lightData;
cycle(castData, lightData, mSettings.depth);
lightData.intensity = clamp(lightData.intensity, 0.f, 1.f);
RGBA col = {lightData.intensity, lightData.intensity, lightData.intensity, 1.f};
buff.set({i, j}, col); buff.set({i, j}, col);
// auto depth = 1 - clamp((halnf) (castData.hitPos - ray.pos).length(), 0.f, mScene->mCamera.getFar()) / mScene->mCamera.getFar();
// buff.set({i, j}, {depth, depth, depth, 1.f});
} else { } else {
buff.set({i, j}, RGBA(0.f, 0.f, 0.f, 0.f)); buff.set({i, j}, 0.f);
} }
} }
} }

View file

@ -21,12 +21,19 @@ namespace tp {
TopologyCache mCache; TopologyCache mCache;
}; };
struct PointLight {
Vec3F pos;
halnf fallOut = 1.f;
halnf intensity = 1.f;
};
class Scene { class Scene {
public: public:
Scene() = default; Scene() = default;
public: public:
Buffer<Object> mObjects; Buffer<Object> mObjects;
Buffer<PointLight> mLights;
Camera mCamera; Camera mCamera;
}; };
@ -35,14 +42,14 @@ namespace tp {
typedef Buffer2D<RGBA> RenderBuffer; typedef Buffer2D<RGBA> RenderBuffer;
struct RenderSettings { struct RenderSettings {
alni samplesiPerPixel = 1; uhalni depth = 2;
alni rayBounces = 1; uhalni spray = 1;
Vec2I size; Vec2I size;
}; };
public: public:
RayTracer() = default; RayTracer() = default;
void render(const Scene& scene, RenderBuffer& buff); void render(const Scene& scene, RenderBuffer& buff, const RenderSettings& settings);
private: private:
struct RayCastData { struct RayCastData {
@ -52,7 +59,13 @@ namespace tp {
bool hit = false; bool hit = false;
}; };
struct LightData {
halnf intensity = 0;
};
private:
void castRay(const Ray& ray, RayCastData& out, alnf far); void castRay(const Ray& ray, RayCastData& out, alnf far);
void cycle(const RayCastData& ray, LightData& out, uhalni depth);
private: private:
RenderSettings mSettings; RenderSettings mSettings;