Apply formating to all files. CLeanup

This commit is contained in:
IlyaShurupov 2023-10-22 17:07:28 +03:00
parent 43e374f269
commit 744c01c5d0
928 changed files with 14515 additions and 21480 deletions

View file

@ -12,89 +12,89 @@
using namespace tp;
void writeImage(const RayTracer::RenderBuffer& output, const char* name) {
// Save the data to a PNG file
struct urgb {
uint1 r, g, b, a;
};
// Save the data to a PNG file
struct urgb {
uint1 r, g, b, a;
};
Buffer2D<urgb> converted;
converted.reserve(output.size());
Buffer2D<urgb> converted;
converted.reserve(output.size());
for (RayTracer::RenderBuffer::Index i = 0; i < output.size().x; i++) {
for (RayTracer::RenderBuffer::Index j = 0; j < output.size().y; j++) {
converted.get({i, j}).r = uint1(output.get({i, j}).r * 255);
converted.get({i, j}).g = uint1(output.get({i, j}).g * 255);
converted.get({i, j}).b = uint1(output.get({i, j}).b * 255);
converted.get({i, j}).a = uint1(output.get({i, j}).a * 255);
}
}
for (RayTracer::RenderBuffer::Index i = 0; i < output.size().x; i++) {
for (RayTracer::RenderBuffer::Index j = 0; j < output.size().y; j++) {
converted.get({ i, j }).r = uint1(output.get({ i, j }).r * 255);
converted.get({ i, j }).g = uint1(output.get({ i, j }).g * 255);
converted.get({ i, j }).b = uint1(output.get({ i, j }).b * 255);
converted.get({ i, j }).a = uint1(output.get({ i, j }).a * 255);
}
}
if (stbi_write_png(name, converted.size().x, converted.size().y, 4, converted.getBuff(), converted.size().x * 4) != 0) {
// Image saved successfully
printf("Image saved successfully.\n");
} else {
printf("Error saving the image.\n");
}
if (stbi_write_png(name, converted.size().x, converted.size().y, 4, converted.getBuff(), converted.size().x * 4) != 0) {
// Image saved successfully
printf("Image saved successfully.\n");
} else {
printf("Error saving the image.\n");
}
}
static void* printStatus(void* arg) {
auto percentage = (const halnf*) arg;
auto old = *percentage;
while (*percentage < 0.99f) {
sleep(500);
if (old != *percentage && (*percentage - old) > 0.01) {
printf("Progress - %f\n", (*percentage) * 100);
old = *percentage;
}
}
pthread_exit(NULL);
auto percentage = (const halnf*) arg;
auto old = *percentage;
while (*percentage < 0.99f) {
sleep(500);
if (old != *percentage && (*percentage - old) > 0.01) {
printf("Progress - %f\n", (*percentage) * 100);
old = *percentage;
}
}
pthread_exit(NULL);
}
void renderCommand(const String& scenePath) {
Scene scene;
Scene scene;
RayTracer::RenderSettings settings;
RayTracer::RenderSettings settings;
loadScene(scene, scenePath, settings);
loadScene(scene, scenePath, settings);
RayTracer::OutputBuffers output;
RayTracer rayt;
RayTracer::OutputBuffers output;
RayTracer rayt;
pthread_t my_thread;
int ret;
pthread_t my_thread;
int ret;
printf("\nStarting Render:\n\n");
printf("\nStarting Render:\n\n");
ret = pthread_create(&my_thread, NULL, &printStatus, &rayt.mProgress.percentage);
if (ret != 0) {
printf("Error: pthread_create() failed\n");
exit(EXIT_FAILURE);
}
ret = pthread_create(&my_thread, NULL, &printStatus, &rayt.mProgress.percentage);
if (ret != 0) {
printf("Error: pthread_create() failed\n");
exit(EXIT_FAILURE);
}
auto start = get_time();
auto start = get_time();
rayt.render(scene, output, settings);
rayt.render(scene, output, settings);
auto end = get_time();
auto end = get_time();
pthread_join(my_thread, NULL);
pthread_join(my_thread, NULL);
printf("\nRender finished with average render time per sample - %i (ms)\n", end - start);
printf("\nRender finished with average render time per sample - %i (ms)\n", end - start);
writeImage(output.normals, "normals.png");
writeImage(output.color, "color.png");
writeImage(output.depth, "depth.png");
writeImage(output.normals, "normals.png");
writeImage(output.color, "color.png");
writeImage(output.depth, "depth.png");
}
int main(int argc, const char** argv) {
tp::ModuleManifest* deps[] = {&gModuleRayTracer, nullptr};
tp::ModuleManifest module("Rayt", nullptr, nullptr, deps);
tp::ModuleManifest* deps[] = { &gModuleRayTracer, nullptr };
tp::ModuleManifest module("Rayt", nullptr, nullptr, deps);
if (module.initialize()) {
renderCommand("scene.lua");
if (module.initialize()) {
renderCommand("scene.lua");
module.deinitialize();
}
module.deinitialize();
}
return 0;
return 0;
}

View file

@ -9,238 +9,238 @@ extern "C" {
#include "OBJ_Loader.h"
bool loadMeshes(tp::Scene& scene, const tp::String& objetsPath) {
using namespace tp;
using namespace tp;
objl::Loader Loader;
objl::Loader Loader;
if (!Loader.LoadFile(objetsPath.read())) {
std::cout << "Failed to Load File. May have failed to find it or it was not an .obj file.\n";
return false;
}
if (!Loader.LoadFile(objetsPath.read())) {
std::cout << "Failed to Load File. May have failed to find it or it was not an .obj file.\n";
return false;
}
for (auto& curMesh : Loader.LoadedMeshes) {
scene.mObjects.append(Object());
for (auto& curMesh : Loader.LoadedMeshes) {
scene.mObjects.append(Object());
auto object = &scene.mObjects.last();
auto object = &scene.mObjects.last();
for (auto& vertex : curMesh.Vertices) {
// printf("{ %f, %f, %f }, \n", vertex.Position.X, vertex.Position.Y, vertex.Position.Z);
object->mTopology.Points.append(Vec3F {vertex.Position.X, vertex.Position.Y, vertex.Position.Z});
object->mTopology.Normals.append(Vec3F {vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z});
}
for (auto& vertex : curMesh.Vertices) {
// printf("{ %f, %f, %f }, \n", vertex.Position.X, vertex.Position.Y, vertex.Position.Z);
object->mTopology.Points.append(Vec3F{ vertex.Position.X, vertex.Position.Y, vertex.Position.Z });
object->mTopology.Normals.append(Vec3F{ vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z });
}
for (int j = 0; j < curMesh.Indices.size(); j += 3) {
int idx1 = (int) curMesh.Indices[j];
int idx2 = (int) curMesh.Indices[j + 1];
int idx3 = (int) curMesh.Indices[j + 2];
// printf("{ %i, %i, %i },\n", idx1, idx2, idx3);
object->mTopology.Indexes.append(Vec3I {idx1, idx2, idx3});
}
for (int j = 0; j < curMesh.Indices.size(); j += 3) {
int idx1 = (int) curMesh.Indices[j];
int idx2 = (int) curMesh.Indices[j + 1];
int idx3 = (int) curMesh.Indices[j + 2];
// printf("{ %i, %i, %i },\n", idx1, idx2, idx3);
object->mTopology.Indexes.append(Vec3I{ idx1, idx2, idx3 });
}
if (object->mTopology.Normals.size() != object->mTopology.Points.size()) {
printf("Logic error loading normals\n");
}
if (object->mTopology.Normals.size() != object->mTopology.Points.size()) {
printf("Logic error loading normals\n");
}
object->mCache.Source = &object->mTopology;
object->mCache.updateCache();
}
object->mCache.Source = &object->mTopology;
object->mCache.updateCache();
}
return scene.mObjects.size();
return scene.mObjects.size();
}
// Function to read a Lua table representing RenderSettings
int readRenderSettings(lua_State* L, tp::RayTracer::RenderSettings& settings) {
lua_getglobal(L, "RenderSettings");
if (!lua_istable(L, -1)) {
printf("RenderSettings is not a table.\n");
return 0; // Error
}
lua_getglobal(L, "RenderSettings");
if (!lua_istable(L, -1)) {
printf("RenderSettings is not a table.\n");
return 0; // Error
}
// Read depth field
lua_getfield(L, -1, "depth");
if (lua_isnumber(L, -1)) {
settings.depth = (int) lua_tonumber(L, -1);
} else {
printf("RenderSettings 'depth' field is missing or not a number.\n");
lua_pop(L, 1); // Pop the 'depth' field
return 0; // Error
}
lua_pop(L, 1); // Pop the 'depth' field
// Read depth field
lua_getfield(L, -1, "depth");
if (lua_isnumber(L, -1)) {
settings.depth = (int) lua_tonumber(L, -1);
} else {
printf("RenderSettings 'depth' field is missing or not a number.\n");
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
// 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
// Read depth field
lua_getfield(L, -1, "multisampling");
if (lua_isnumber(L, -1)) {
settings.multisampling = (int) lua_tonumber(L, -1);
} else {
printf("RenderSettings 'depth' field is missing or not a number.\n");
lua_pop(L, 1); // Pop the 'depth' field
return 0; // Error
}
lua_pop(L, 1); // Pop the 'depth' field
// Read depth field
lua_getfield(L, -1, "multisampling");
if (lua_isnumber(L, -1)) {
settings.multisampling = (int) lua_tonumber(L, -1);
} else {
printf("RenderSettings 'depth' field is missing or not a number.\n");
lua_pop(L, 1); // Pop the 'depth' field
return 0; // Error
}
lua_pop(L, 1); // Pop the 'depth' field
return 1; // Success
return 1; // Success
}
// Function to read a Lua table representing a light
int readLight(lua_State* L, tp::PointLight* light) {
lua_getfield(L, -1, "pos"); // Get the "pos" field from the light table
if (!lua_istable(L, -1)) {
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, "pos"); // Get the "pos" field from the light table
if (!lua_istable(L, -1)) {
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
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
return 1; // Success
}
void loadScene(tp::Scene& scene, const tp::String& scenePath, tp::RayTracer::RenderSettings& settings) {
lua_State* L = luaL_newstate();
luaL_openlibs(L);
lua_State* L = luaL_newstate();
luaL_openlibs(L);
if (luaL_dofile(L, "script.lua") != 0) {
lua_close(L);
printf("Cant open scene script.\n");
return;
}
if (luaL_dofile(L, "script.lua") != 0) {
lua_close(L);
printf("Cant open scene script.\n");
return;
}
lua_getglobal(L, "Meshes");
lua_getglobal(L, "Meshes");
if (lua_isstring(L, -1)) {
tp::String meshesPath = lua_tostring(L, -1);
if (lua_isstring(L, -1)) {
tp::String meshesPath = lua_tostring(L, -1);
if (!loadMeshes(scene, meshesPath)) {
printf("No 'meshes' loaded - check ur .obj path and validate content of .obj .\n");
return;
}
if (!loadMeshes(scene, meshesPath)) {
printf("No 'meshes' loaded - check ur .obj path and validate content of .obj .\n");
return;
}
} else {
printf("No 'meshes' path given.\n");
return;
}
} else {
printf("No 'meshes' path given.\n");
return;
}
// --- camera
// --- camera
// Access Camera table
lua_getglobal(L, "Camera");
if (!lua_istable(L, -1)) {
printf("Camera is not a table.\n");
lua_close(L);
return;
}
// Access Camera table
lua_getglobal(L, "Camera");
if (!lua_istable(L, -1)) {
printf("Camera is not a table.\n");
lua_close(L);
return;
}
// Verify you are inside the "Camera" table
int cameraTableIndex = lua_gettop(L); // Get the index of the "Camera" table
// Verify you are inside the "Camera" table
int cameraTableIndex = lua_gettop(L); // Get the index of the "Camera" table
// Access the "pos" field and validate it
lua_getfield(L, cameraTableIndex, "pos");
if (!lua_istable(L, -1) || lua_rawlen(L, -1) != 3) {
printf("Invalid 'pos' field in Camera table.\n");
lua_close(L);
return;
}
// Access the "pos" field and validate it
lua_getfield(L, cameraTableIndex, "pos");
if (!lua_istable(L, -1) || lua_rawlen(L, -1) != 3) {
printf("Invalid 'pos' field in Camera table.\n");
lua_close(L);
return;
}
// Read the values from the table
float pos[3];
for (int i = 0; i < 3; i++) {
lua_rawgeti(L, -1, i + 1);
if (lua_isnumber(L, -1)) {
pos[i] = lua_tonumber(L, -1);
} else {
printf("Invalid 'pos' field value at index %d.\n", i + 1);
lua_close(L);
return;
}
lua_pop(L, 1);
}
// Read the values from the table
float pos[3];
for (int i = 0; i < 3; i++) {
lua_rawgeti(L, -1, i + 1);
if (lua_isnumber(L, -1)) {
pos[i] = lua_tonumber(L, -1);
} else {
printf("Invalid 'pos' field value at index %d.\n", i + 1);
lua_close(L);
return;
}
lua_pop(L, 1);
}
// Access the "size_x" field and validate it
lua_getfield(L, cameraTableIndex, "size_x");
if (!lua_isnumber(L, -1)) {
printf("Invalid or missing 'size_x' field in Camera table.\n");
lua_close(L);
return;
}
int size_x = lua_tointeger(L, -1);
lua_pop(L, 1); // Pop the 'size_x' value from the stack
// Access the "size_x" field and validate it
lua_getfield(L, cameraTableIndex, "size_x");
if (!lua_isnumber(L, -1)) {
printf("Invalid or missing 'size_x' field in Camera table.\n");
lua_close(L);
return;
}
int size_x = lua_tointeger(L, -1);
lua_pop(L, 1); // Pop the 'size_x' value from the stack
// Access the "size_y" field and validate it
lua_getfield(L, cameraTableIndex, "size_y");
if (!lua_isnumber(L, -1)) {
printf("Invalid or missing 'size_y' field in Camera table.\n");
lua_close(L);
return;
}
int size_y = lua_tointeger(L, -1);
// Access the "size_y" field and validate it
lua_getfield(L, cameraTableIndex, "size_y");
if (!lua_isnumber(L, -1)) {
printf("Invalid or missing 'size_y' field in Camera table.\n");
lua_close(L);
return;
}
int size_y = lua_tointeger(L, -1);
settings.size = {(tp::halnf) size_x, (tp::halnf) size_y};
settings.size = { (tp::halnf) size_x, (tp::halnf) size_y };
scene.mCamera.lookAtPoint({0, 0, 0}, {pos[0], pos[1], pos[2]}, {0, 0, 1});
scene.mCamera.setFOV(3.14 / 4);
scene.mCamera.setFar(100);
scene.mCamera.setRatio((tp::halnf) size_y / (tp::halnf) size_x);
scene.mCamera.lookAtPoint({ 0, 0, 0 }, { pos[0], pos[1], pos[2] }, { 0, 0, 1 });
scene.mCamera.setFOV(3.14 / 4);
scene.mCamera.setFar(100);
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
}
// ---------- 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
}
}
// 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
}
// ----------- settings --------------
if (!readRenderSettings(L, settings)) {
printf("Cant Read Render Settings");
lua_close(L);
return; // Error
}
lua_close(L);
lua_close(L);
}

View file

@ -44,198 +44,195 @@ normal = n1 * barycentric.x + n2 * barycentric.y + n3 * barycentric.z;
using namespace tp;
ModuleManifest* sDependencies[] = {&gModuleMath, &gModuleCommandLine, &gModuleConnection, nullptr};
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;
out.hit = false;
far *= far;
far *= far;
for (auto obj : mScene->mObjects) {
for (auto trig : obj->mCache.TrigCaches) {
if (trig->castRay(ray)) {
// printf("Hit\n");
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();
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;
if (far > dist && dist > EPSILON) {
out.trig = &trig.data();
out.hitPos = trig->getHitPos();
out.obj = &obj.data();
out.hit = true;
far = dist;
}
}
}
}
far = dist;
}
}
}
}
}
void RayTracer::cycle(const RayCastData& castData, LightData& out, uhalni depth) {
if (depth) {
depth--;
if (depth) {
depth--;
Vec3F normal = castData.trig->getNormal();
normal.normalize();
Vec3F normal = castData.trig->getNormal();
normal.normalize();
const auto delta1 = castData.trig->mEdgeP1P2.unitV();
const auto delta2 = normal.cross(delta1);
const auto delta1 = castData.trig->mEdgeP1P2.unitV();
const auto delta2 = normal.cross(delta1);
for (auto idx : Range(mSettings.spray)) {
RayCastData materialCastData;
LightData lightData;
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 d1 = ((halnf) randomFloat() - 0.5f) * 2;
auto d2 = ((halnf) randomFloat() - 0.5f) * 2;
auto sprayNormal = (normal + delta1 * d1 + delta2 * d2).normalize();
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;
}
}
}
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();
// 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};
Ray lightRay = { dir.unitV(), castData.hitPos };
if (lightRay.dir.dot(castData.trig->mNormal) < 0) {
continue;
}
castRay(lightRay, lightCastData, length);
if (lightRay.dir.dot(castData.trig->mNormal) < 0) {
continue;
}
castRay(lightRay, lightCastData, length);
if (lightCastData.hit) {
continue;
}
if (lightCastData.hit) {
continue;
}
out.intensity += light->intensity / (length * length);
}
out.intensity += light->intensity / (length * length);
}
}
void RayTracer::render(const Scene& scene, OutputBuffers& out, const RenderSettings& settings) {
out.color.reserve({settings.size.x, settings.size.y});
out.normals.reserve({settings.size.x, settings.size.y});
out.depth.reserve({settings.size.x, settings.size.y});
out.color.reserve({ settings.size.x, settings.size.y });
out.normals.reserve({ settings.size.x, settings.size.y });
out.depth.reserve({ settings.size.x, settings.size.y });
mScene = &scene;
mSettings = settings;
mScene = &scene;
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 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;
auto planeLeftTop = planeCenter + planeCenterOffset;
RayCastData castData;
RayCastData castData;
Ray ray = {
{0, 0, 0},
pos
};
Ray ray = { { 0, 0, 0 }, pos };
Vec3F iterPoint = {0, 0, 0};
Vec3F deltaX = right * halnf(width / (alnf) mSettings.size.x);
Vec3F deltaY = up * halnf(-height / (alnf) mSettings.size.y);
Vec3F iterPoint = { 0, 0, 0 };
Vec3F deltaX = right * halnf(width / (alnf) mSettings.size.x);
Vec3F deltaY = up * halnf(-height / (alnf) mSettings.size.y);
ualni maxIterations = mSettings.size.x * mSettings.size.y;
ualni currIter = 0;
ualni maxIterations = mSettings.size.x * mSettings.size.y;
ualni currIter = 0;
halnf maxDepth = 0;
halnf minDepth = mScene->mCamera.getFar() * mSettings.multisampling;
halnf maxDepth = 0;
halnf minDepth = mScene->mCamera.getFar() * mSettings.multisampling;
auto accumulateColor = [](RGBA& col, const RGBA& in) {
col.r += in.r;
col.g += in.g;
col.b += in.b;
col.a = 1;
};
auto accumulateColor = [](RGBA& col, const RGBA& in) {
col.r += in.r;
col.g += in.g;
col.b += in.b;
col.a = 1;
};
auto divideColor = [](RGBA& col, const halnf num) {
col.r /= num;
col.g /= num;
col.b /= num;
};
auto divideColor = [](RGBA& col, const halnf num) {
col.r /= num;
col.g /= num;
col.b /= num;
};
for (auto i = 0; i < mSettings.size.x; i++) {
for (auto j = 0; j < mSettings.size.y; j++) {
for (auto sample = 0; sample < mSettings.multisampling; sample++) {
auto randX = randomFloat();
auto randY = randomFloat();
for (auto i = 0; i < mSettings.size.x; i++) {
for (auto j = 0; j < mSettings.size.y; j++) {
for (auto sample = 0; sample < mSettings.multisampling; sample++) {
auto randX = randomFloat();
auto randY = randomFloat();
iterPoint = planeLeftTop + ((deltaX * (halnf) (i + randX)) + (deltaY * (halnf) (j + randY)));
ray.dir = (iterPoint - pos).unitV();
iterPoint = planeLeftTop + ((deltaX * (halnf) (i + randX)) + (deltaY * (halnf) (j + randY)));
ray.dir = (iterPoint - pos).unitV();
castRay(ray, castData, mScene->mCamera.getFar());
castRay(ray, castData, mScene->mCamera.getFar());
if (castData.hit) {
LightData lightData;
cycle(castData, lightData, mSettings.depth);
if (castData.hit) {
LightData lightData;
cycle(castData, lightData, mSettings.depth);
const auto normal = castData.trig->getNormal();
const auto depth = (halnf) (castData.hitPos - ray.pos).length();
const auto normal = castData.trig->getNormal();
const auto depth = (halnf) (castData.hitPos - ray.pos).length();
lightData.intensity = clamp(lightData.intensity, 0.f, 1.f);
RGBA col = {lightData.intensity, lightData.intensity, lightData.intensity, 1.f};
lightData.intensity = clamp(lightData.intensity, 0.f, 1.f);
RGBA col = { lightData.intensity, lightData.intensity, lightData.intensity, 1.f };
accumulateColor(out.color.get({i, j}), col);
accumulateColor(out.normals.get({i, j}), {normal.x * 0.5f + 0.5f, normal.y * 0.5f + 0.5f, normal.z * 0.5f + 0.5f, 1.f});
accumulateColor(out.depth.get({i, j}), {depth, depth, depth, 1.f});
accumulateColor(out.color.get({ i, j }), col);
accumulateColor(out.normals.get({ i, j }), { normal.x * 0.5f + 0.5f, normal.y * 0.5f + 0.5f, normal.z * 0.5f + 0.5f, 1.f });
accumulateColor(out.depth.get({ i, j }), { depth, depth, depth, 1.f });
} else {
out.color.set({i, j}, 0.f);
out.normals.set({i, j}, 0.f);
out.depth.set({i, j}, 0.f);
}
} else {
out.color.set({ i, j }, 0.f);
out.normals.set({ i, j }, 0.f);
out.depth.set({ i, j }, 0.f);
}
// auto tmp = buff.get({i, j});
// printf(" %f, %f, %f, %f, ", tmp.r, tmp.g, tmp.b, tmp.a);
}
// auto tmp = buff.get({i, j});
// printf(" %f, %f, %f, %f, ", tmp.r, tmp.g, tmp.b, tmp.a);
}
mProgress.percentage = (halnf) currIter / (halnf) maxIterations;
currIter++;
}
}
mProgress.percentage = (halnf) currIter / (halnf) maxIterations;
currIter++;
}
}
for (auto i = 0; i < mSettings.size.x * mSettings.size.y; i++) {
divideColor(out.color.getBuff()[i], (halnf) mSettings.multisampling);
divideColor(out.normals.getBuff()[i], (halnf) mSettings.multisampling);
divideColor(out.depth.getBuff()[i], (halnf) mSettings.multisampling);
}
for (auto i = 0; i < mSettings.size.x * mSettings.size.y; i++) {
divideColor(out.color.getBuff()[i], (halnf) mSettings.multisampling);
divideColor(out.normals.getBuff()[i], (halnf) mSettings.multisampling);
divideColor(out.depth.getBuff()[i], (halnf) mSettings.multisampling);
}
for (auto i = 0; i < mSettings.size.x * mSettings.size.y; i++) {
if (!out.depth.getBuff()[i].a) {
continue;
}
const auto depth = out.depth.getBuff()[i].r;
if (maxDepth < depth) {
maxDepth = depth;
}
if (minDepth > depth) {
minDepth = depth;
}
}
for (auto i = 0; i < mSettings.size.x * mSettings.size.y; i++) {
if (!out.depth.getBuff()[i].a) {
continue;
}
const auto depth = out.depth.getBuff()[i].r;
if (maxDepth < depth) {
maxDepth = depth;
}
if (minDepth > depth) {
minDepth = depth;
}
}
for (auto i = 0; i < mSettings.size.x * mSettings.size.y; i++) {
auto& col = out.depth.getBuff()[i];
if (col.a == 1.f) {
col.r = (col.r - minDepth) / (maxDepth - minDepth);
col.g = col.r;
col.b = col.r;
}
}
for (auto i = 0; i < mSettings.size.x * mSettings.size.y; i++) {
auto& col = out.depth.getBuff()[i];
if (col.a == 1.f) {
col.r = (col.r - minDepth) / (maxDepth - minDepth);
col.g = col.r;
col.b = col.r;
}
}
}

View file

@ -10,77 +10,77 @@
namespace tp {
extern ModuleManifest gModuleRayTracer;
extern ModuleManifest gModuleRayTracer;
class Object {
public:
Object() = default;
class Object {
public:
Object() = default;
public:
Topology mTopology;
TopologyCache mCache;
};
public:
Topology mTopology;
TopologyCache mCache;
};
struct PointLight {
Vec3F pos;
halnf fallOut = 1.f;
halnf intensity = 1.f;
};
struct PointLight {
Vec3F pos;
halnf fallOut = 1.f;
halnf intensity = 1.f;
};
class Scene {
public:
Scene() = default;
class Scene {
public:
Scene() = default;
public:
Buffer<Object> mObjects;
Buffer<PointLight> mLights;
Camera mCamera;
};
public:
Buffer<Object> mObjects;
Buffer<PointLight> mLights;
Camera mCamera;
};
class RayTracer {
public:
typedef Buffer2D<RGBA> RenderBuffer;
class RayTracer {
public:
typedef Buffer2D<RGBA> RenderBuffer;
struct Progress {
halnf percentage = 0.f;
} mProgress;
struct Progress {
halnf percentage = 0.f;
} mProgress;
struct RenderSettings {
uhalni depth = 2;
uhalni spray = 1;
ualni multisampling = 1;
Vec2I size;
};
struct RenderSettings {
uhalni depth = 2;
uhalni spray = 1;
ualni multisampling = 1;
Vec2I size;
};
struct OutputBuffers {
RenderBuffer normals;
RenderBuffer color;
RenderBuffer depth;
// albedo, reflectance ...
};
struct OutputBuffers {
RenderBuffer normals;
RenderBuffer color;
RenderBuffer depth;
// albedo, reflectance ...
};
public:
RayTracer() = default;
void render(const Scene& scene, OutputBuffers& out, const RenderSettings& settings);
public:
RayTracer() = default;
void render(const Scene& scene, OutputBuffers& out, const RenderSettings& settings);
private:
struct RayCastData {
const Object* obj = nullptr;
TrigCache* trig = nullptr;
Vec3F hitPos = {0, 0, 0};
bool hit = false;
};
private:
struct RayCastData {
const Object* obj = nullptr;
TrigCache* trig = nullptr;
Vec3F hitPos = { 0, 0, 0 };
bool hit = false;
};
struct LightData {
halnf intensity = 0;
};
struct LightData {
halnf intensity = 0;
};
private:
void castRay(const Ray& ray, RayCastData& out, alnf far);
void cycle(const RayCastData& ray, LightData& out, uhalni depth);
private:
void castRay(const Ray& ray, RayCastData& out, alnf far);
void cycle(const RayCastData& ray, LightData& out, uhalni depth);
private:
RenderSettings mSettings;
const Scene* mScene = nullptr;
};
private:
RenderSettings mSettings;
const Scene* mScene = nullptr;
};
}

View file

@ -10,117 +10,114 @@
using namespace tp;
void writeImage(const RayTracer::RenderBuffer& output) {
// Save the data to a PNG file
struct urgb {
uint1 r, g, b, a;
};
// Save the data to a PNG file
struct urgb {
uint1 r, g, b, a;
};
Buffer2D<urgb> converted;
converted.reserve(output.size());
Buffer2D<urgb> converted;
converted.reserve(output.size());
for (RayTracer::RenderBuffer::Index i = 0; i < output.size().x; i++) {
for (RayTracer::RenderBuffer::Index j = 0; j < output.size().y; j++) {
converted.get({i, j}).r = uint1(output.get({i, j}).r * 255);
converted.get({i, j}).g = uint1(output.get({i, j}).g * 255);
converted.get({i, j}).b = uint1(output.get({i, j}).b * 255);
converted.get({i, j}).a = uint1(output.get({i, j}).a * 255);
}
}
for (RayTracer::RenderBuffer::Index i = 0; i < output.size().x; i++) {
for (RayTracer::RenderBuffer::Index j = 0; j < output.size().y; j++) {
converted.get({ i, j }).r = uint1(output.get({ i, j }).r * 255);
converted.get({ i, j }).g = uint1(output.get({ i, j }).g * 255);
converted.get({ i, j }).b = uint1(output.get({ i, j }).b * 255);
converted.get({ i, j }).a = uint1(output.get({ i, j }).a * 255);
}
}
stbi_write_png("output.png", converted.size().x, converted.size().y, 4, converted.getBuff(), converted.size().x * 4);
stbi_write_png("output.png", converted.size().x, converted.size().y, 4, converted.getBuff(), converted.size().x * 4);
}
bool compareCols(const RGBA& l, const RGBA& r) {
auto small = 0.0001f;
if ((l.r - r.r) > small) {
return false;
}
if ((l.g - r.g) > small) {
return false;
}
if ((l.b - r.b) > small) {
return false;
}
if ((l.a - r.a) > small) {
return false;
}
return true;
auto small = 0.0001f;
if ((l.r - r.r) > small) {
return false;
}
if ((l.g - r.g) > small) {
return false;
}
if ((l.b - r.b) > small) {
return false;
}
if ((l.a - r.a) > small) {
return false;
}
return true;
}
void testRT() {
using namespace tp;
using namespace tp;
Scene scene;
Scene scene;
scene.mCamera.lookAtPoint({0, 0, 0}, {2, 2, 2}, {0, 0, 1});
scene.mCamera.setFOV(3.14 / 4);
scene.mCamera.lookAtPoint({ 0, 0, 0 }, { 2, 2, 2 }, { 0, 0, 1 });
scene.mCamera.setFOV(3.14 / 4);
scene.mLights.append({
{0, 0, 1.1f},
1.f, 0.3f
});
scene.mLights.append({ { 0, 0, 1.1f }, 1.f, 0.3f });
scene.mObjects.append(Object());
auto& object = scene.mObjects.last();
scene.mObjects.append(Object());
auto& object = scene.mObjects.last();
object.mTopology.Points = {
{1.000000, 0.000000, 0.000000},
{0.000000, 1.000000, 0.000000},
{0.000000, 0.000000, 1.000000},
};
object.mTopology.Points = {
{ 1.000000, 0.000000, 0.000000 },
{ 0.000000, 1.000000, 0.000000 },
{ 0.000000, 0.000000, 1.000000 },
};
object.mTopology.Normals = {
{1.000000, 1.000000, 1.000000},
{1.000000, 1.000000, 1.000000},
{1.000000, 1.000000, 1.000000},
};
object.mTopology.Normals = {
{ 1.000000, 1.000000, 1.000000 },
{ 1.000000, 1.000000, 1.000000 },
{ 1.000000, 1.000000, 1.000000 },
};
object.mTopology.Indexes = {
{0, 1, 2},
};
object.mTopology.Indexes = {
{ 0, 1, 2 },
};
object.mCache.Source = &object.mTopology;
object.mCache.updateCache();
object.mCache.Source = &object.mTopology;
object.mCache.updateCache();
RayTracer::RenderSettings settings = {
0,
0,
1,
{10, 10},
};
RayTracer::RenderSettings settings = {
0,
0,
1,
{ 10, 10 },
};
RayTracer::OutputBuffers output;
// output.reserve(RayTracer::RenderBuffer::Index2D(settings.size.x, settings.size.y));
RayTracer::OutputBuffers output;
// output.reserve(RayTracer::RenderBuffer::Index2D(settings.size.x, settings.size.y));
RayTracer rt;
rt.render(scene, output, settings);
RayTracer rt;
rt.render(scene, output, settings);
TEST(compareCols(output.color.get({6, 4}), RGBA {0.560100f, 0.560100f, 0.560100f, 1.000000f}));
TEST(compareCols(output.color.get({6, 5}), RGBA {0.353739f, 0.353739f, 0.353739f, 1.000000f}));
TEST(compareCols(output.color.get({6, 6}), RGBA {0.242577f, 0.242577f, 0.242577f, 1.000000f}));
TEST(compareCols(output.color.get({6, 7}), RGBA {0.176313f, 0.176313f, 0.176313f, 1.000000f}));
TEST(compareCols(output.color.get({6, 8}), RGBA {0.000000f, 0.000000f, 0.000000f, 0.000000f}));
TEST(compareCols(output.color.get({ 6, 4 }), RGBA{ 0.560100f, 0.560100f, 0.560100f, 1.000000f }));
TEST(compareCols(output.color.get({ 6, 5 }), RGBA{ 0.353739f, 0.353739f, 0.353739f, 1.000000f }));
TEST(compareCols(output.color.get({ 6, 6 }), RGBA{ 0.242577f, 0.242577f, 0.242577f, 1.000000f }));
TEST(compareCols(output.color.get({ 6, 7 }), RGBA{ 0.176313f, 0.176313f, 0.176313f, 1.000000f }));
TEST(compareCols(output.color.get({ 6, 8 }), RGBA{ 0.000000f, 0.000000f, 0.000000f, 0.000000f }));
if (0) {
writeImage(output.color);
for (auto i = 0; i < output.color.size().x; i++) {
for (auto j = 0; j < output.color.size().y; j++) {
auto tmp = output.color.get({i, j});
printf("TEST(compareCols(output.get({%i, %i}), RGBA{ %ff, %ff, %ff, %ff }));\n", i, j, tmp.r, tmp.g, tmp.b, tmp.a);
}
}
}
if (0) {
writeImage(output.color);
for (auto i = 0; i < output.color.size().x; i++) {
for (auto j = 0; j < output.color.size().y; j++) {
auto tmp = output.color.get({ i, j });
printf("TEST(compareCols(output.get({%i, %i}), RGBA{ %ff, %ff, %ff, %ff }));\n", i, j, tmp.r, tmp.g, tmp.b, tmp.a);
}
}
}
}
int main(int argc, char* argv[]) {
tp::ModuleManifest* ModuleDependencies[] = {&tp::gModuleRayTracer, nullptr};
tp::ModuleManifest TestModule("TokenizerTest", nullptr, nullptr, ModuleDependencies);
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleRayTracer, nullptr };
tp::ModuleManifest TestModule("TokenizerTest", nullptr, nullptr, ModuleDependencies);
if (!TestModule.initialize()) {
return 1;
}
if (!TestModule.initialize()) {
return 1;
}
testRT();
testRT();
TestModule.deinitialize();
TestModule.deinitialize();
}