set up frame to be more useful, minor fixes in grid, added use lod checkbox

This commit is contained in:
Yggdrasil75
2026-02-03 07:48:29 -05:00
parent 88ee3732b6
commit e54c524f26
3 changed files with 318 additions and 123 deletions

View File

@@ -28,6 +28,7 @@ struct defaults {
int gridSizecube = 10000; int gridSizecube = 10000;
bool slowRender = false; bool slowRender = false;
bool globalIllumination = true; bool globalIllumination = true;
bool useLod = true;
int rayCount = 3; int rayCount = 3;
int reflectCount = 3; int reflectCount = 3;
int lodDist = 500; int lodDist = 500;
@@ -408,7 +409,7 @@ void livePreview(Octree<int>& grid, defaults& config, const Camera& cam) {
grid.setLODMinDistance(config.lodDist); grid.setLODMinDistance(config.lodDist);
grid.setLODFalloff(config.lodDropoff); grid.setLODFalloff(config.lodDropoff);
if (config.slowRender) { if (config.slowRender) {
currentPreviewFrame = grid.renderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB, config.rayCount, config.reflectCount, config.globalIllumination); currentPreviewFrame = grid.renderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB, config.rayCount, config.reflectCount, config.globalIllumination, config.useLod);
} else { } else {
currentPreviewFrame = grid.fastRenderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB); currentPreviewFrame = grid.fastRenderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB);
} }
@@ -998,6 +999,7 @@ int main() {
ImGui::InputFloat("Lod dropoff", &config.lodDropoff); ImGui::InputFloat("Lod dropoff", &config.lodDropoff);
ImGui::InputInt("lod minimum Distance", &config.lodDist); ImGui::InputInt("lod minimum Distance", &config.lodDist);
ImGui::Checkbox("use Global illumination", &config.globalIllumination); ImGui::Checkbox("use Global illumination", &config.globalIllumination);
ImGui::Checkbox("use Lod", &config.useLod);
ImGui::End(); ImGui::End();
} }

View File

@@ -502,9 +502,6 @@ private:
return randomDir; return randomDir;
} }
float rgbToGrayscale(const Eigen::Vector3f& color) const {
return 0.2126f * color[0] + 0.7152f * color[1] + 0.0722f * color[2];
}
void collectNodesByObjectId(OctreeNode* node, int id, std::vector<std::shared_ptr<NodeData>>& results) const { void collectNodesByObjectId(OctreeNode* node, int id, std::vector<std::shared_ptr<NodeData>>& results) const {
if (!node) return; if (!node) return;
@@ -900,14 +897,14 @@ public:
if (!pointData->active) continue; if (!pointData->active) continue;
float t; float t;
// if (pointData->shape == Shape::SPHERE) { if (pointData->shape == Shape::SPHERE) {
// if (raySphereIntersect(origin, dir, pointData->position, pointData->size, t)) { if (raySphereIntersect(origin, dir, pointData->position, pointData->size, t)) {
// if (t >= 0 && t <= maxDist) { if (t >= 0 && t <= maxDist) {
// hits.emplace_back(pointData); hits.emplace_back(pointData);
// if (stopAtFirstHit) return; if (stopAtFirstHit) return;
// } }
// } }
// } else { } else {
PointType normal, hitPoint; PointType normal, hitPoint;
if (rayCubeIntersect(origin, dir, pointData.get(), t, normal, hitPoint)) { if (rayCubeIntersect(origin, dir, pointData.get(), t, normal, hitPoint)) {
if (t >= 0 && t <= maxDist) { if (t >= 0 && t <= maxDist) {
@@ -915,7 +912,7 @@ public:
if (stopAtFirstHit) return; if (stopAtFirstHit) return;
} }
} }
// } }
} }
} else { } else {
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
@@ -950,15 +947,8 @@ public:
PointType right = cam.right(); PointType right = cam.right();
frame outFrame(width, height, colorformat); frame outFrame(width, height, colorformat);
std::vector<uint8_t> colorBuffer; std::vector<float> colorBuffer;
int channels; int channels = 3;
if (colorformat == frame::colormap::B) {
channels = 1;
} else if (colorformat == frame::colormap::RGB || colorformat == frame::colormap::BGR) {
channels = 3;
} else { //BGRA and RGBA
channels = 4;
}
colorBuffer.resize(width * height * channels); colorBuffer.resize(width * height * channels);
float aspect = static_cast<float>(width) / height; float aspect = static_cast<float>(width) / height;
@@ -1005,7 +995,6 @@ public:
hitPoint = rayOrig + rayDir * t; hitPoint = rayOrig + rayDir * t;
normal = (hitPoint - center).normalized(); normal = (hitPoint - center).normalized();
} else { } else {
// Cube intersection
PointType cubeNormal; PointType cubeNormal;
if (!rayCubeIntersect(rayOrig, rayDir, obj.get(), t, normal, hitPoint)) { if (!rayCubeIntersect(rayOrig, rayDir, obj.get(), t, normal, hitPoint)) {
return globalIllumination ? skylight_ : Eigen::Vector3f::Zero(); return globalIllumination ? skylight_ : Eigen::Vector3f::Zero();
@@ -1030,11 +1019,6 @@ public:
finalColor += obj->color.cwiseProduct(incomingLight) * diffuseProb; finalColor += obj->color.cwiseProduct(incomingLight) * diffuseProb;
} }
if (refl > 0.001f) {
PointType rDir = (rayDir - 2.0f * rayDir.dot(normal) * normal).normalized();
finalColor += traceRay(hitPoint + normal * 0.002f, rDir, bounces + 1, rngState) * refl;
}
if (refr > 0.001f) { if (refr > 0.001f) {
float ior = 1.45f; float ior = 1.45f;
float η = 1.0f / ior; float η = 1.0f / ior;
@@ -1084,37 +1068,13 @@ public:
color = color.cwiseMax(0.0f).cwiseMin(1.0f); color = color.cwiseMax(0.0f).cwiseMin(1.0f);
switch(colorformat) { colorBuffer[idx ] = color[0];
case frame::colormap::B: colorBuffer[idx + 1] = color[1];
colorBuffer[idx ] = static_cast<uint8_t>(rgbToGrayscale(color) * 255.0f); colorBuffer[idx + 2] = color[2];
break;
case frame::colormap::RGB:
colorBuffer[idx ] = static_cast<uint8_t>(color[0] * 255.0f);
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
colorBuffer[idx + 2] = static_cast<uint8_t>(color[2] * 255.0f);
break;
case frame::colormap::BGR:
colorBuffer[idx ] = static_cast<uint8_t>(color[2] * 255.0f);
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
break;
case frame::colormap::RGBA:
colorBuffer[idx ] = static_cast<uint8_t>(color[0] * 255.0f);
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
colorBuffer[idx + 2] = static_cast<uint8_t>(color[2] * 255.0f);
colorBuffer[idx + 3] = 255;
break;
case frame::colormap::BGRA:
colorBuffer[idx ] = static_cast<uint8_t>(color[2] * 255.0f);
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
colorBuffer[idx + 3] = 255;
break;
}
} }
} }
outFrame.setData(colorBuffer); outFrame.setData(colorBuffer, frame::colormap::RGB);
return outFrame; return outFrame;
} }
@@ -1214,15 +1174,9 @@ public:
PointType right = cam.right(); PointType right = cam.right();
frame outFrame(width, height, colorformat); frame outFrame(width, height, colorformat);
std::vector<uint8_t> colorBuffer; std::vector<float> colorBuffer;
int channels; int channels;
if (colorformat == frame::colormap::B) { channels = 3;
channels = 1;
} else if (colorformat == frame::colormap::RGB || colorformat == frame::colormap::BGR) {
channels = 3;
} else { //BGRA and RGBA
channels = 4;
}
colorBuffer.resize(width * height * channels); colorBuffer.resize(width * height * channels);
float aspect = static_cast<float>(width) / height; float aspect = static_cast<float>(width) / height;
@@ -1262,37 +1216,13 @@ public:
color = color * lightDot; color = color * lightDot;
} }
switch(colorformat) { colorBuffer[idx ] = color[0];
case frame::colormap::B: colorBuffer[idx + 1] = color[1];
colorBuffer[idx ] = static_cast<uint8_t>(rgbToGrayscale(color) * 255.0f); colorBuffer[idx + 2] = color[2];
break;
case frame::colormap::RGB:
colorBuffer[idx ] = static_cast<uint8_t>(color[0] * 255.0f);
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
colorBuffer[idx + 2] = static_cast<uint8_t>(color[2] * 255.0f);
break;
case frame::colormap::BGR:
colorBuffer[idx ] = static_cast<uint8_t>(color[2] * 255.0f);
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
break;
case frame::colormap::RGBA:
colorBuffer[idx ] = static_cast<uint8_t>(color[0] * 255.0f);
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
colorBuffer[idx + 2] = static_cast<uint8_t>(color[2] * 255.0f);
colorBuffer[idx + 3] = 255;
break;
case frame::colormap::BGRA:
colorBuffer[idx ] = static_cast<uint8_t>(color[2] * 255.0f);
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
colorBuffer[idx + 3] = 255;
break;
}
} }
} }
outFrame.setData(colorBuffer); outFrame.setData(colorBuffer, frame::colormap::RGB);
return outFrame; return outFrame;
} }

View File

@@ -15,6 +15,8 @@
#include <future> #include <future>
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
#include <cmath>
#include <iomanip>
#include "../timing_decorator.hpp" #include "../timing_decorator.hpp"
class frame { class frame {
@@ -26,7 +28,6 @@ private:
size_t sourceSize = 0; size_t sourceSize = 0;
size_t width = 0; size_t width = 0;
size_t height = 0; size_t height = 0;
public: public:
enum class colormap { enum class colormap {
RGB, RGB,
@@ -44,7 +45,29 @@ public:
HUFFMAN, HUFFMAN,
RAW RAW
}; };
private:
size_t getChannels(colormap fmt) const {
switch (fmt) {
case colormap::RGBA: return 4;
case colormap::BGR: return 3;
case colormap::BGRA: return 4;
case colormap::B: return 1;
case colormap::RGB: default: return 3;
}
}
void resetState(size_t newSize) {
cformat = compresstype::RAW;
_compressedData.clear();
_compressedData.shrink_to_fit();
overheadmap.clear();
sourceSize = newSize;
}
float rgbToGrayscale(float r, float g, float b) const {
return 0.2126f * r + 0.7152f * g + 0.0722f * b;
}
public:
colormap colorFormat = colormap::RGB; colormap colorFormat = colormap::RGB;
compresstype cformat = compresstype::RAW; compresstype cformat = compresstype::RAW;
@@ -58,30 +81,245 @@ public:
frame() {}; frame() {};
frame(size_t w, size_t h, colormap format = colormap::RGB) frame(size_t w, size_t h, colormap format = colormap::RGB)
: width(w), height(h), colorFormat(format), cformat(compresstype::RAW) { : width(w), height(h), colorFormat(format), cformat(compresstype::RAW) {
size_t channels = 3; _data.resize(width * height * getChannels(format));
switch (format) {
case colormap::RGBA: channels = 4; break;
case colormap::BGR: channels = 3; break;
case colormap::BGRA: channels = 4; break;
case colormap::B: channels = 1; break;
default: channels = 3; break;
}
_data.resize(width * height * channels);
} }
void setData(const std::vector<uint8_t>& data) { void setData(const std::vector<uint8_t>& data) {
_data = data; _data = data;
cformat = compresstype::RAW; resetState(data.size());
_compressedData.clear(); }
_compressedData.shrink_to_fit();
overheadmap.clear(); void setData(const std::vector<uint8_t>& inputData, colormap inputFormat) {
sourceSize = data.size(); if (inputFormat == colorFormat) {
setData(inputData);
return;
}
size_t srcChannels = getChannels(inputFormat);
size_t dstChannels = getChannels(colorFormat);
size_t numPixels = width * height;
if (inputData.size() != numPixels * srcChannels) {
throw std::runtime_error("Input data size does not match frame dimensions for the specified format.");
}
std::vector<uint8_t> newData;
newData.reserve(numPixels * dstChannels);
for (size_t i = 0; i < numPixels; ++i) {
size_t px = i * srcChannels;
uint8_t r = 0, g = 0, b = 0, a = 255;
switch (inputFormat) {
case colormap::RGB: {
r = inputData[px];
g = inputData[px+1];
b = inputData[px+2];
break;
}
case colormap::RGBA:
r = inputData[px];
g = inputData[px+1];
b = inputData[px+2];
a = inputData[px+3];
break;
case colormap::BGR:
b = inputData[px];
g = inputData[px+1];
r = inputData[px+2];
break;
case colormap::BGRA:
b = inputData[px];
g = inputData[px+1];
r = inputData[px+2];
a = inputData[px+3];
break;
case colormap::B:
r = g = b = inputData[px];
break;
}
switch (colorFormat) {
case colormap::RGB:
newData.push_back(r);
newData.push_back(g);
newData.push_back(b);
break;
case colormap::RGBA:
newData.push_back(r);
newData.push_back(g);
newData.push_back(b);
newData.push_back(a);
break;
case colormap::BGR:
newData.push_back(b);
newData.push_back(g);
newData.push_back(r);
break;
case colormap::BGRA:
newData.push_back(b);
newData.push_back(g);
newData.push_back(r);
newData.push_back(a);
break;
case colormap::B:
newData.push_back(rgbToGrayscale(r, g, b));
break;
}
}
_data = std::move(newData);
resetState(_data.size());
}
void setData(const std::vector<float>& inputData) {
size_t channels = getChannels(colorFormat);
if (inputData.size() != width * height * channels) {
throw std::runtime_error("Input float data size does not match frame dimensions.");
}
std::vector<uint8_t> newData;
newData.reserve(inputData.size());
for (float val : inputData) {
// Clamp between 0.0 and 1.0, scale to 255
float v = std::max(0.0f, std::min(1.0f, val));
newData.push_back(static_cast<uint8_t>(v * 255.0f));
}
_data = std::move(newData);
resetState(_data.size());
}
void setData(const std::vector<float>& inputData, colormap inputFormat) {
size_t srcChannels = getChannels(inputFormat);
size_t dstChannels = getChannels(colorFormat);
size_t numPixels = width * height;
if (inputData.size() != numPixels * srcChannels) {
throw std::runtime_error("Input float data size does not match frame dimensions.");
}
std::vector<uint8_t> newData;
newData.reserve(numPixels * dstChannels);
auto floatToByte = [](float f) -> uint8_t {
return static_cast<uint8_t>(std::max(0.0f, std::min(1.0f, f)) * 255.0f);
};
for (size_t i = 0; i < numPixels; ++i) {
size_t px = i * srcChannels;
uint8_t r = 0, g = 0, b = 0, a = 255;
// Extract and convert floats to bytes
switch (inputFormat) {
case colormap::RGB:
r = floatToByte(inputData[px]);
g = floatToByte(inputData[px+1]);
b = floatToByte(inputData[px+2]);
break;
case colormap::RGBA:
r = floatToByte(inputData[px]);
g = floatToByte(inputData[px+1]);
b = floatToByte(inputData[px+2]);
a = floatToByte(inputData[px+3]);
break;
case colormap::BGR:
b = floatToByte(inputData[px]);
g = floatToByte(inputData[px+1]);
r = floatToByte(inputData[px+2]);
break;
case colormap::BGRA:
b = floatToByte(inputData[px]);
g = floatToByte(inputData[px+1]);
r = floatToByte(inputData[px+2]);
a = floatToByte(inputData[px+3]);
break;
case colormap::B:
r = g = b = floatToByte(inputData[px]);
break;
}
switch (colorFormat) {
case colormap::RGB:
newData.push_back(r);
newData.push_back(g);
newData.push_back(b);
break;
case colormap::RGBA:
newData.push_back(r);
newData.push_back(g);
newData.push_back(b);
newData.push_back(a);
break;
case colormap::BGR:
newData.push_back(b);
newData.push_back(g);
newData.push_back(r);
break;
case colormap::BGRA:
newData.push_back(b);
newData.push_back(g);
newData.push_back(r);
newData.push_back(a);
break;
case colormap::B:
newData.push_back(rgbToGrayscale(r, g, b));
break;
}
}
_data = std::move(newData);
resetState(_data.size());
} }
const std::vector<uint8_t>& getData() const { const std::vector<uint8_t>& getData() const {
return _data; return _data;
} }
std::vector<uint8_t> getPixel(size_t x, size_t y) const {
if (cformat != compresstype::RAW) {
throw std::runtime_error("Cannot get pixel data from a compressed frame. Decompress first.");
}
if (x >= width || y >= height) {
throw std::out_of_range("Pixel coordinates out of bounds.");
}
size_t channels = getChannels(colorFormat);
size_t index = (y * width + x) * channels;
std::vector<uint8_t> pixel;
pixel.reserve(channels);
for (size_t i = 0; i < channels; ++i) {
pixel.push_back(_data[index + i]);
}
return pixel;
}
void setPixel(size_t x, size_t y, const std::vector<uint8_t>& values) {
if (cformat != compresstype::RAW) {
throw std::runtime_error("Cannot set pixel data on a compressed frame. Decompress first.");
}
if (x >= width || y >= height) {
throw std::out_of_range("Pixel coordinates out of bounds.");
}
size_t channels = getChannels(colorFormat);
if (values.size() != channels) {
throw std::invalid_argument("Input value count does not match frame channel count.");
}
size_t index = (y * width + x) * channels;
for (size_t i = 0; i < channels; ++i) {
_data[index + i] = values[i];
}
// Since data changed, previous compression stats are invalid
resetState(_data.size());
}
// Run-Length Encoding (RLE) compression // Run-Length Encoding (RLE) compression
frame& compressFrameRLE() { frame& compressFrameRLE() {
TIME_FUNCTION; TIME_FUNCTION;
@@ -243,13 +481,27 @@ public:
void printCompressionInfo() const { void printCompressionInfo() const {
std::cout << "Compression Type: "; std::cout << "Compression Type: ";
switch (cformat) { switch (cformat) {
case compresstype::RLE: std::cout << "RLE"; break; case compresstype::RLE:
case compresstype::DIFF: std::cout << "DIFF"; break; std::cout << "RLE";
case compresstype::DIFFRLE: std::cout << "DIFF + RLE"; break; break;
case compresstype::LZ78: std::cout << "LZ78 (kinda)"; break; case compresstype::DIFF:
case compresstype::HUFFMAN: std::cout << "HUFFMAN"; break; std::cout << "DIFF";
case compresstype::RAW: std::cout << "RAW (uncompressed)"; break; break;
default: std::cout << "UNKNOWN"; break; case compresstype::DIFFRLE:
std::cout << "DIFF + RLE";
break;
case compresstype::LZ78:
std::cout << "LZ78 (kinda)";
break;
case compresstype::HUFFMAN:
std::cout << "HUFFMAN";
break;
case compresstype::RAW:
std::cout << "RAW (uncompressed)";
break;
default:
std::cout << "UNKNOWN";
break;
} }
std::cout << std::endl; std::cout << std::endl;
@@ -503,19 +755,30 @@ private:
}; };
inline std::ostream& operator<<(std::ostream& os, frame& f) {
std::ostream& operator<<(std::ostream& os, frame& f) {
os << "Frame[" << f.getWidth() << "x" << f.getHeight() << "] "; os << "Frame[" << f.getWidth() << "x" << f.getHeight() << "] ";
// Color format // Color format
os << "Format: "; os << "Format: ";
switch (f.colorFormat) { switch (f.colorFormat) {
case frame::colormap::RGB: os << "RGB"; break; case frame::colormap::RGB:
case frame::colormap::RGBA: os << "RGBA"; break; os << "RGB";
case frame::colormap::BGR: os << "BGR"; break; break;
case frame::colormap::BGRA: os << "BGRA"; break; case frame::colormap::RGBA:
case frame::colormap::B: os << "Grayscale"; break; os << "RGBA";
default: os << "Unknown"; break; break;
case frame::colormap::BGR:
os << "BGR";
break;
case frame::colormap::BGRA:
os << "BGRA";
break;
case frame::colormap::B:
os << "Grayscale";
break;
default:
os << "Unknown";
break;
} }
// Compression info // Compression info