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

View File

@@ -502,9 +502,6 @@ private:
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 {
if (!node) return;
@@ -900,14 +897,14 @@ public:
if (!pointData->active) continue;
float t;
// if (pointData->shape == Shape::SPHERE) {
// if (raySphereIntersect(origin, dir, pointData->position, pointData->size, t)) {
// if (t >= 0 && t <= maxDist) {
// hits.emplace_back(pointData);
// if (stopAtFirstHit) return;
// }
// }
// } else {
if (pointData->shape == Shape::SPHERE) {
if (raySphereIntersect(origin, dir, pointData->position, pointData->size, t)) {
if (t >= 0 && t <= maxDist) {
hits.emplace_back(pointData);
if (stopAtFirstHit) return;
}
}
} else {
PointType normal, hitPoint;
if (rayCubeIntersect(origin, dir, pointData.get(), t, normal, hitPoint)) {
if (t >= 0 && t <= maxDist) {
@@ -915,7 +912,7 @@ public:
if (stopAtFirstHit) return;
}
}
// }
}
}
} else {
for (int i = 0; i < 8; ++i) {
@@ -950,15 +947,8 @@ public:
PointType right = cam.right();
frame outFrame(width, height, colorformat);
std::vector<uint8_t> colorBuffer;
int channels;
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;
}
std::vector<float> colorBuffer;
int channels = 3;
colorBuffer.resize(width * height * channels);
float aspect = static_cast<float>(width) / height;
@@ -1005,7 +995,6 @@ public:
hitPoint = rayOrig + rayDir * t;
normal = (hitPoint - center).normalized();
} else {
// Cube intersection
PointType cubeNormal;
if (!rayCubeIntersect(rayOrig, rayDir, obj.get(), t, normal, hitPoint)) {
return globalIllumination ? skylight_ : Eigen::Vector3f::Zero();
@@ -1030,11 +1019,6 @@ public:
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) {
float ior = 1.45f;
float η = 1.0f / ior;
@@ -1083,38 +1067,14 @@ public:
Eigen::Vector3f color = accumulatedColor / static_cast<float>(samplesPerPixel);
color = color.cwiseMax(0.0f).cwiseMin(1.0f);
switch(colorformat) {
case frame::colormap::B:
colorBuffer[idx ] = static_cast<uint8_t>(rgbToGrayscale(color) * 255.0f);
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;
}
colorBuffer[idx ] = color[0];
colorBuffer[idx + 1] = color[1];
colorBuffer[idx + 2] = color[2];
}
}
outFrame.setData(colorBuffer);
outFrame.setData(colorBuffer, frame::colormap::RGB);
return outFrame;
}
@@ -1214,15 +1174,9 @@ public:
PointType right = cam.right();
frame outFrame(width, height, colorformat);
std::vector<uint8_t> colorBuffer;
std::vector<float> colorBuffer;
int channels;
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;
}
channels = 3;
colorBuffer.resize(width * height * channels);
float aspect = static_cast<float>(width) / height;
@@ -1262,37 +1216,13 @@ public:
color = color * lightDot;
}
switch(colorformat) {
case frame::colormap::B:
colorBuffer[idx ] = static_cast<uint8_t>(rgbToGrayscale(color) * 255.0f);
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;
}
colorBuffer[idx ] = color[0];
colorBuffer[idx + 1] = color[1];
colorBuffer[idx + 2] = color[2];
}
}
outFrame.setData(colorBuffer);
outFrame.setData(colorBuffer, frame::colormap::RGB);
return outFrame;
}

View File

@@ -15,6 +15,8 @@
#include <future>
#include <mutex>
#include <atomic>
#include <cmath>
#include <iomanip>
#include "../timing_decorator.hpp"
class frame {
@@ -26,7 +28,6 @@ private:
size_t sourceSize = 0;
size_t width = 0;
size_t height = 0;
public:
enum class colormap {
RGB,
@@ -44,7 +45,29 @@ public:
HUFFMAN,
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;
compresstype cformat = compresstype::RAW;
@@ -58,29 +81,244 @@ public:
frame() {};
frame(size_t w, size_t h, colormap format = colormap::RGB)
: width(w), height(h), colorFormat(format), cformat(compresstype::RAW) {
size_t channels = 3;
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);
_data.resize(width * height * getChannels(format));
}
void setData(const std::vector<uint8_t>& data) {
_data = data;
cformat = compresstype::RAW;
_compressedData.clear();
_compressedData.shrink_to_fit();
overheadmap.clear();
sourceSize = data.size();
resetState(data.size());
}
void setData(const std::vector<uint8_t>& inputData, colormap inputFormat) {
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 {
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
frame& compressFrameRLE() {
@@ -243,13 +481,27 @@ public:
void printCompressionInfo() const {
std::cout << "Compression Type: ";
switch (cformat) {
case compresstype::RLE: std::cout << "RLE"; break;
case compresstype::DIFF: std::cout << "DIFF"; 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;
case compresstype::RLE:
std::cout << "RLE";
break;
case compresstype::DIFF:
std::cout << "DIFF";
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;
@@ -503,19 +755,30 @@ private:
};
std::ostream& operator<<(std::ostream& os, frame& f) {
inline std::ostream& operator<<(std::ostream& os, frame& f) {
os << "Frame[" << f.getWidth() << "x" << f.getHeight() << "] ";
// Color format
os << "Format: ";
switch (f.colorFormat) {
case frame::colormap::RGB: os << "RGB"; break;
case frame::colormap::RGBA: os << "RGBA"; 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;
case frame::colormap::RGB:
os << "RGB";
break;
case frame::colormap::RGBA:
os << "RGBA";
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