diff --git a/Step 3/include/engine/raytracing.h b/Step 3/include/engine/raytracing.h index 66bec7b..b0a0ff8 100644 --- a/Step 3/include/engine/raytracing.h +++ b/Step 3/include/engine/raytracing.h @@ -135,7 +135,7 @@ namespace Raytracing { void lookAt(const Vec4& lookAtPos); }; - static Random rnd{-1, 1}; + static Random rnd{-1.0, 1.0}; struct RaycasterImageBounds { int width,height, x,y; @@ -160,6 +160,7 @@ namespace Raytracing { std::mutex queueSync; std::queue* unprocessedQuads = nullptr; + Vec4 raycasti(const Ray& ray, int depth); Vec4 raycast(const Ray& ray); void runRaycastingAlgorithm(RaycasterImageBounds imageBounds, int loopX, int loopY); void runSTDThread(int threads); diff --git a/Step 3/include/engine/types.h b/Step 3/include/engine/types.h index ca69c1f..8fa6100 100644 --- a/Step 3/include/engine/types.h +++ b/Step 3/include/engine/types.h @@ -55,6 +55,11 @@ namespace Raytracing { // returns true if the ray was scattered along with the scattered ray, otherwise will return false with empty ray. // the returned vec4 is the attenuation color [[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const = 0; + // emission value for this material + // this allows for a material to glow slightly or emit full on light + // the light can of course be of any color + // and the UV coords along with the actual hit point are provided for your convince + [[nodiscard]] virtual Vec4 emission(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& hitPoint) const { return {}; } [[nodiscard]] Vec4 getBaseColor() const { return baseColor; } virtual ~Material() = default; diff --git a/Step 3/include/engine/util/std.h b/Step 3/include/engine/util/std.h index 3632ca3..b3a429d 100644 --- a/Step 3/include/engine/util/std.h +++ b/Step 3/include/engine/util/std.h @@ -77,12 +77,22 @@ namespace Raytracing { std::random_device rd; // obtain a random number from hardware std::mt19937 gen; std::uniform_real_distribution doubleDistr{0, 1}; + std::uniform_int_distribution longDistr{0, 1}; + std::uniform_int_distribution ulongDistr{0, 1}; public: Random(): gen(std::mt19937(long(rd.entropy() * 691 * 691))) {} Random(double min, double max): gen(std::mt19937(long(rd.entropy() * 691 * 691))), doubleDistr{min, max} {} + Random(long min, long max): gen(std::mt19937(long(rd.entropy() * 691 * 691))), longDistr{min, max} {} + Random(unsigned long min, unsigned long max): gen(std::mt19937(long(rd.entropy() * 691 * 691))), ulongDistr{min, max} {} double getDouble() { return doubleDistr(gen); } + long getLong(){ + return longDistr(gen); + } + unsigned long getULong(){ + return ulongDistr(gen); + } }; class String { diff --git a/Step 3/include/engine/world.h b/Step 3/include/engine/world.h index dd1e756..9b621bc 100644 --- a/Step 3/include/engine/world.h +++ b/Step 3/include/engine/world.h @@ -88,6 +88,13 @@ namespace Raytracing { [[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const override; }; + + class LightMaterial : public Material { + public: + explicit LightMaterial(const Vec4& lightColor): Material(lightColor) {} + [[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const override; + [[nodiscard]] virtual Vec4 emission(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& hitPoint) const override; + }; class TexturedMaterial : public Material { protected: @@ -97,7 +104,7 @@ namespace Raytracing { explicit TexturedMaterial(const std::string& file); [[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const override; - [[nodiscard]] Vec4 getColor(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& point) const; + [[nodiscard]] Vec4 getColor(PRECISION_TYPE u, PRECISION_TYPE v) const; ~TexturedMaterial(); }; diff --git a/Step 3/include/opencl/cl.h b/Step 3/include/opencl/cl.h index 0e18372..6ca834d 100644 --- a/Step 3/include/opencl/cl.h +++ b/Step 3/include/opencl/cl.h @@ -52,10 +52,10 @@ namespace Raytracing { int m_activePlatform; cl_platform_id* m_platformIDs; - cl_uint m_numOfPlatformIDs; + cl_uint m_numOfPlatformIDs{}; - cl_device_id m_deviceID; - cl_uint m_numOfDevices; + cl_device_id m_deviceID{}; + cl_uint m_numOfDevices{}; cl_context m_context; diff --git a/Step 3/resources/skybox.mtl b/Step 3/resources/skybox.mtl new file mode 100644 index 0000000..9b8de8c --- /dev/null +++ b/Step 3/resources/skybox.mtl @@ -0,0 +1,2 @@ +# Blender 3.3.1 MTL File: 'None' +# www.blender.org diff --git a/Step 3/resources/skybox.obj b/Step 3/resources/skybox.obj new file mode 100644 index 0000000..4bcb091 --- /dev/null +++ b/Step 3/resources/skybox.obj @@ -0,0 +1,47 @@ +# Blender 3.3.1 +# www.blender.org +mtllib skybox.mtl +o Cube +v -256.000000 -256.000000 256.000000 +v -256.000000 256.000000 256.000000 +v -256.000000 -256.000000 -256.000000 +v -256.000000 256.000000 -256.000000 +v 256.000000 -256.000000 256.000000 +v 256.000000 256.000000 256.000000 +v 256.000000 -256.000000 -256.000000 +v 256.000000 256.000000 -256.000000 +vn -1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 -1.0000 +vn 1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 1.0000 +vn -0.0000 -1.0000 -0.0000 +vn -0.0000 1.0000 -0.0000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 1.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 1.000000 1.000000 +s 0 +f 2/2/1 3/6/1 1/1/1 +f 4/8/2 7/14/2 3/4/2 +f 8/16/3 5/9/3 7/14/3 +f 6/12/4 1/1/4 5/10/4 +f 7/15/5 1/1/5 3/5/5 +f 4/8/6 6/13/6 8/16/6 +f 2/2/1 4/7/1 3/6/1 +f 4/8/2 8/16/2 7/14/2 +f 8/16/3 6/11/3 5/9/3 +f 6/12/4 2/2/4 1/1/4 +f 7/15/5 5/10/5 1/1/5 +f 4/8/6 2/3/6 6/13/6 diff --git a/Step 3/src/engine/main.cpp b/Step 3/src/engine/main.cpp index 403495e..517df19 100644 --- a/Step 3/src/engine/main.cpp +++ b/Step 3/src/engine/main.cpp @@ -36,7 +36,143 @@ namespace Raytracing{ using namespace Raytracing; +typedef unsigned long binsType; + +std::queue sort(std::queue& q, bool dir = false){ + std::queue ret; + auto size = q.size(); + binsType vals[size]; + for (int i = 0; i < size; i++){ + vals[i] = q.front(); + q.pop(); + } + for (int i = 0; i < size; i++){ + for (int j = i; j < size; j++){ + if (dir) { + if (vals[j] < vals[i]) { + auto temp = vals[j]; + vals[j] = vals[i]; + vals[i] = temp; + } + } else{ + if (vals[j] > vals[i]) { + auto temp = vals[j]; + vals[j] = vals[i]; + vals[i] = temp; + } + } + } + } + for (int i = 0; i < size; i++){ + ret.push(vals[i]); + } + return ret; +}; + int main(int argc, char** args) { + /*int numOfObjects = 50000; + binsType binCapacity = 100.0; + + Random rnd1{0, binCapacity}; + + binsType objects[numOfObjects]; + std::vector bins; + + for (int i = 0; i < numOfObjects; i++) + objects[i] = (rnd1.getULong()); + + std::queue less; + std::queue more; + + for (int i = 0; i < numOfObjects; i++){ + if (objects[i] >= binCapacity){ + bins.push_back(objects[i]); + continue; + } + if (objects[i] < binCapacity/2) + less.push(objects[i]); + else + more.push(objects[i]); + } + + //less = sort(less, true); + //more = sort(more, false); + + binsType currentBin = 0; + + + while (true){ + if (!more.empty()) { + auto moreVal = more.front(); + while (!more.empty() && moreVal + currentBin <= binCapacity){ + currentBin += moreVal; + more.pop(); + moreVal = more.front(); + } + ilog << currentBin << "\n"; + auto lessVal = less.front(); + while (!less.empty() && lessVal + currentBin <= binCapacity){ + currentBin += lessVal; + less.pop(); + lessVal = less.front(); + } + dlog << currentBin << " " << lessVal << "\n"; + } else { + if (less.empty()) + break; + auto lessVal = less.front(); + while (!less.empty() && lessVal + currentBin <= binCapacity){ + currentBin += lessVal; + less.pop(); + lessVal = less.front(); + } + wlog << currentBin << " " << lessVal << "\n"; + } + if (currentBin <= 0) + break; + bins.push_back(currentBin); + currentBin = 0; + }*/ + + /*while (!more.empty()) { + currentBin = more.front(); + more.pop(); + double lessVal = less.front(); + while (!less.empty() && currentBin + lessVal < binCapacity){ + currentBin += lessVal; + less.pop(); + lessVal = less.front(); + } + if (currentBin > 0) + bins.push_back(currentBin); + currentBin = 0; + if (less.empty()) { + double moreVal = more.front(); + while (!more.empty()){ + while (!more.empty() && currentBin + moreVal < binCapacity) { + currentBin += moreVal; + more.pop(); + moreVal = more.front(); + } + if (currentBin > 0) + bins.push_back(currentBin); + currentBin = 0; + } + } + }*/ + /*int goodCount = 0; + int greatCount = 0; + for (binsType bin : bins) { + tlog << bin << "\n"; + if (bin >= (binsType)((double)binCapacity * 0.95)) + goodCount++; + if (bin >= (binsType)((double)binCapacity * 0.99)) + greatCount++; + } + tlog << "We made " << bins.size() << " bins!\n"; + tlog << "With " << goodCount << " good bins and " << greatCount << " great bins!\n"; + + return 0;*/ // since this is linux only we can easily set our process priority to be high with a syscall // requires root. TODO: find way to doing this without root even if asking for user privilege escalation //setpriority(PRIO_PROCESS, 0, -20); @@ -126,11 +262,12 @@ int main(int argc, char** args) { Raytracing::ModelData spider = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "spider.obj"); Raytracing::ModelData house = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "house.obj"); Raytracing::ModelData plane = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "plane.obj"); - Raytracing::ModelData debugCube = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "debug.obj"); + Raytracing::ModelData debugCube = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "skybox.obj"); world.add("greenDiffuse", new Raytracing::DiffuseMaterial{Raytracing::Vec4{0, 1.0, 0, 1}}); world.add("redDiffuse", new Raytracing::DiffuseMaterial{Raytracing::Vec4{1.0, 0, 0, 1}}); world.add("blueDiffuse", new Raytracing::DiffuseMaterial{Raytracing::Vec4{0, 0, 1.0, 1}}); + world.add("light", new Raytracing::LightMaterial{Raytracing::Vec4{10.0, 10.0, 10.0}}); world.add("greenMetal", new Raytracing::MetalMaterial{Raytracing::Vec4{0.4, 1.0, 0.4, 1}}); world.add("redMetal", new Raytracing::BrushedMetalMaterial{Raytracing::Vec4{1.0, 0.4, 0.4, 1}, 0.6f}); @@ -147,7 +284,7 @@ int main(int argc, char** args) { world.add(new Raytracing::ModelObject({5, 1, 0}, house, world.getMaterial("redDiffuse"))); world.add(new Raytracing::ModelObject({0, 0, -5}, house, world.getMaterial("blueDiffuse"))); world.add(new Raytracing::ModelObject({0, 0, 5}, house, world.getMaterial("blueDiffuse"))); - world.add(new Raytracing::ModelObject({0, 5, 0}, debugCube, world.getMaterial("magic"))); + //world.add(new Raytracing::ModelObject({0, 0, 0}, debugCube, world.getMaterial("cat"))); if (parser.hasOption("--gui") || parser.hasOption("-g")) { #ifdef COMPILE_GUI diff --git a/Step 3/src/engine/raytracing.cpp b/Step 3/src/engine/raytracing.cpp index 8e502ed..67378bb 100644 --- a/Step 3/src/engine/raytracing.cpp +++ b/Step 3/src/engine/raytracing.cpp @@ -96,6 +96,10 @@ namespace Raytracing { Vec4 color; }; + Vec4 Raycaster::raycasti(const Ray& ray, int depth){ + return {}; + } + Vec4 Raycaster::raycast(const Ray& ray) { Ray localRay = ray; Vec4 color {1.0, 1.0, 1.0}; @@ -104,22 +108,28 @@ namespace Raytracing { return color; while (RTSignal->pauseRaytracing) // sleep for 1/60th of a second, or about 1 frame. std::this_thread::sleep_for(std::chrono::milliseconds(16)); + auto hit = world.checkIfHit(localRay, 0.001, infinity); if (hit.first.hit) { auto object = hit.second; auto scatterResults = object->getMaterial()->scatter(localRay, hit.first); + //auto emission = object->getMaterial()->emission(hit.first.u, hit.first.v, hit.first.hitPoint); // if the material scatters the ray, ie casts a new one, if (scatterResults.scattered) { // attenuate the recursive raycast by the material's color color = color * scatterResults.attenuationColor; localRay = scatterResults.newRay; } else { // if we don't scatter, we don't need to keep looping - color = {0.0, 0.0, 0.0}; + // but we should return whatever the material's emission is + // which for all that aren't lights (currently) is the old black color. + //color = color + emission; + color = {}; break; } } else { // since we didn't hit, we hit the sky. color = color * Vec4{0.5, 0.7, 1.0}; + //color = Vec4{}; // if we don't hit we cannot keep looping. break; } diff --git a/Step 3/src/engine/world.cpp b/Step 3/src/engine/world.cpp index 219d8e3..23f738e 100644 --- a/Step 3/src/engine/world.cpp +++ b/Step 3/src/engine/world.cpp @@ -144,9 +144,9 @@ namespace Raytracing { if (newRay.x() < EPSILON && newRay.y() < EPSILON && newRay.z() < EPSILON && newRay.w() < EPSILON) newRay = hitData.normal; - return {true, Ray{hitData.hitPoint, newRay}, getColor(hitData.u, hitData.v, hitData.hitPoint)}; + return {true, Ray{hitData.hitPoint, newRay}, getColor(hitData.u, hitData.v)}; } - Vec4 TexturedMaterial::getColor(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& point) const { + Vec4 TexturedMaterial::getColor(PRECISION_TYPE u, PRECISION_TYPE v) const { // if we are unable to load the image return the debug color. if (!data) return Vec4{0.2, 1, 0} * Vec4{u, v, 1.0}; @@ -180,6 +180,13 @@ namespace Raytracing { TexturedMaterial::~TexturedMaterial() { stbi_image_free(data); } + ScatterResults LightMaterial::scatter(const Ray& ray, const HitData& hitData) const { + // do not scatter. The light emits. + return {false, ray, baseColor}; + } + Vec4 LightMaterial::emission(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& hitPoint) const { + return baseColor; + } PRECISION_TYPE sign(PRECISION_TYPE i){ return i >= 0 ? 1 : -1;