This commit is contained in:
Yggdrasil75
2026-01-28 14:34:58 -05:00
parent 19462868ea
commit 4febc51784
3 changed files with 790 additions and 116 deletions

View File

@@ -13,24 +13,23 @@ struct Camera {
Vector3f direction;
Vector3f up;
float fov;
float movementSpeed;
float rotationSpeed;
Camera(const Vector3f& pos, const Vector3f& viewdir, const Vector3f& up, float fov = 80)
: origin(pos), direction(viewdir), up(up.normalized()), fov(fov) {}
Camera(const Vector3f& pos, const Vector3f& viewdir, const Vector3f& up, float fov = 80,
float moveSpeed = 1.0f, float rotSpeed = 0.5f)
: origin(pos), direction(viewdir.normalized()), up(up.normalized()), fov(fov), movementSpeed(moveSpeed), rotationSpeed(rotSpeed) {}
void rotateYaw(float angle) {
float cosA = cos(angle);
float sinA = sin(angle);
Vector3f right = direction.cross(up).normalized();
// Rotate around up vector (yaw)
angle *= rotationSpeed;
Matrix3f rotation;
rotation = Eigen::AngleAxisf(angle, up);
direction = rotation * direction;
direction.normalize();
}
void rotatePitch(float angle) {
// Clamp pitch to avoid gimbal lock
angle *= rotationSpeed;
Vector3f right = direction.cross(up).normalized();
// Rotate around right vector (pitch)
@@ -43,6 +42,30 @@ struct Camera {
up = right.cross(direction).normalized();
}
void moveForward(float distance) {
origin += forward() * distance * movementSpeed;
}
void moveBackward(float distance) {
origin -= forward() * distance * movementSpeed;
}
void moveRight(float distance) {
origin += right() * distance * movementSpeed;
}
void moveLeft(float distance) {
origin -= right() * distance * movementSpeed;
}
void moveUp(float distance) {
origin += up * distance * movementSpeed;
}
void moveDown(float distance) {
origin -= up * distance * movementSpeed;
}
Vector3f forward() const {
return direction.normalized();
}
@@ -55,17 +78,32 @@ struct Camera {
return fov * (M_PI / 180.0f);
}
// Additional useful methods
void moveForward(float distance) {
origin += forward() * distance;
// Look at a specific point
void lookAt(const Vector3f& target) {
direction = (target - origin).normalized();
// Recalculate up vector
Vector3f worldUp(0, 1, 0);
if (direction.cross(worldUp).norm() < 0.001f) {
worldUp = Vector3f(0, 0, 1);
}
Vector3f right = direction.cross(worldUp).normalized();
up = right.cross(direction).normalized();
}
void moveRight(float distance) {
origin += right() * distance;
// Set position directly
void setPosition(const Vector3f& pos) {
origin = pos;
}
void moveUp(float distance) {
origin += up * distance;
// Set view direction directly
void setDirection(const Vector3f& dir) {
direction = dir.normalized();
// Recalculate up
Vector3f worldUp(0, 1, 0);
Vector3f right = direction.cross(worldUp).normalized();
up = right.cross(direction).normalized();
}
// Get view matrix (lookAt matrix)
@@ -88,7 +126,7 @@ struct Camera {
}
// Get projection matrix (perspective)
Eigen::Matrix4f getProjectionMatrix(float aspectRatio, float nearPlane = 0.1f, float farPlane = 100.0f) const {
Eigen::Matrix4f getProjectionMatrix(float aspectRatio, float nearPlane = 0.1f, float farPlane = 1000.0f) const {
float fovrad = fovRad();
float tanHalfFov = tan(fovrad / 2.0f);
@@ -102,6 +140,14 @@ struct Camera {
return projection;
}
void mouseLook(float deltaX, float deltaY) {
float yaw = -deltaX * 0.001f;
float pitch = -deltaY * 0.001f;
rotateYaw(yaw);
rotatePitch(pitch);
}
};
#endif

View File

@@ -14,6 +14,7 @@
#include <functional>
#include <iostream>
#include <iomanip>
#include <fstream>
#ifdef SSE
#include <immintrin.h>
@@ -44,6 +45,10 @@ public:
float reflection = 0.0f) : data(data), position(pos), active(active), visible(visible),
color(color), size(size), light(light), emittance(emittance), refraction(refraction),
reflection(reflection) {}
// Default constructor for serialization
NodeData() : active(false), visible(false), size(0.0f), light(false),
emittance(0.0f), refraction(0.0f), reflection(0.0f) {}
};
struct OctreeNode {
@@ -139,6 +144,116 @@ private:
return false;
}
template<typename V>
void writeVal(std::ofstream& out, const V& val) const {
out.write(reinterpret_cast<const char*>(&val), sizeof(V));
}
template<typename V>
void readVal(std::ifstream& in, V& val) {
in.read(reinterpret_cast<char*>(&val), sizeof(V));
}
void writeVec3(std::ofstream& out, const Eigen::Vector3f& vec) const {
writeVal(out, vec.x());
writeVal(out, vec.y());
writeVal(out, vec.z());
}
void readVec3(std::ifstream& in, Eigen::Vector3f& vec) {
float x, y, z;
readVal(in, x); readVal(in, y); readVal(in, z);
vec = Eigen::Vector3f(x, y, z);
}
void serializeNode(std::ofstream& out, const OctreeNode* node) const {
writeVal(out, node->isLeaf);
if (node->isLeaf) {
size_t pointCount = node->points.size();
writeVal(out, pointCount);
for (const auto& pt : node->points) {
// Write raw data T (Must be POD)
writeVal(out, pt->data);
// Write properties
writeVec3(out, pt->position);
writeVal(out, pt->active);
writeVal(out, pt->visible);
writeVal(out, pt->size);
writeVec3(out, pt->color);
writeVal(out, pt->light);
writeVal(out, pt->emittance);
writeVal(out, pt->refraction);
writeVal(out, pt->reflection);
}
} else {
// Write bitmask of active children
uint8_t childMask = 0;
for (int i = 0; i < 8; ++i) {
if (node->children[i] != nullptr) {
childMask |= (1 << i);
}
}
writeVal(out, childMask);
// Recursively write only existing children
for (int i = 0; i < 8; ++i) {
if (node->children[i]) {
serializeNode(out, node->children[i].get());
}
}
}
}
void deserializeNode(std::ifstream& in, OctreeNode* node) {
bool isLeaf;
readVal(in, isLeaf);
node->isLeaf = isLeaf;
if (isLeaf) {
size_t pointCount;
readVal(in, pointCount);
node->points.reserve(pointCount);
for (size_t i = 0; i < pointCount; ++i) {
auto pt = std::make_shared<NodeData>();
readVal(in, pt->data);
readVec3(in, pt->position);
readVal(in, pt->active);
readVal(in, pt->visible);
readVal(in, pt->size);
readVec3(in, pt->color);
readVal(in, pt->light);
readVal(in, pt->emittance);
readVal(in, pt->refraction);
readVal(in, pt->reflection);
node->points.push_back(pt);
}
} else {
uint8_t childMask;
readVal(in, childMask);
PointType center = node->center;
for (int i = 0; i < 8; ++i) {
if ((childMask >> i) & 1) {
// Reconstruct bounds for child
PointType childMin, childMax;
for (int d = 0; d < Dim; ++d) {
bool high = (i >> d) & 1;
childMin[d] = high ? center[d] : node->bounds.first[d];
childMax[d] = high ? node->bounds.second[d] : center[d];
}
node->children[i] = std::make_unique<OctreeNode>(childMin, childMax);
deserializeNode(in, node->children[i].get());
} else {
node->children[i] = nullptr;
}
}
}
}
void bitonic_sort_8(std::array<std::pair<int, float>, 8>& arr) const noexcept {
#ifdef SSE
alignas(32) float values[8];
@@ -280,6 +395,8 @@ public:
root_(std::make_unique<OctreeNode>(minBound, maxBound)), maxPointsPerNode(maxPointsPerNode),
maxDepth(maxDepth), size(0) {}
Octree() : root_(nullptr), maxPointsPerNode(16), maxDepth(16), size(0) {}
bool set(const T& data, const PointType& pos, bool visible, Eigen::Vector3f color, float size, bool active,
bool light = false, float emittance = 0.0f, float refraction = 0.0f, float reflection = 0.0f) {
auto pointData = std::make_shared<NodeData>(data, pos, visible, color, size, active,
@@ -291,6 +408,53 @@ public:
return false;
}
bool save(const std::string& filename) const {
if (!root_) return false;
std::ofstream out(filename, std::ios::binary);
if (!out) return false;
uint32_t magic = 0x79676733;
writeVal(out, magic);
writeVal(out, maxDepth);
writeVal(out, maxPointsPerNode);
writeVal(out, size);
writeVec3(out, root_->bounds.first);
writeVec3(out, root_->bounds.second);
serializeNode(out, root_.get());
out.close();
return true;
}
// Load Octree from binary file
bool load(const std::string& filename) {
std::ifstream in(filename, std::ios::binary);
if (!in) return false;
uint32_t magic;
readVal(in, magic);
if (magic != 0x0C78E3) {
std::cerr << "Invalid Octree file format" << std::endl;
return false;
}
readVal(in, maxDepth);
readVal(in, maxPointsPerNode);
readVal(in, size);
PointType minBound, maxBound;
readVec3(in, minBound);
readVec3(in, maxBound);
root_ = std::make_unique<OctreeNode>(minBound, maxBound);
deserializeNode(in, root_.get());
in.close();
return true;
}
std::vector<std::shared_ptr<NodeData>> voxelTraverse(const PointType& origin, const PointType& direction,
float maxDist, bool stopAtFirstHit) {
std::vector<std::shared_ptr<NodeData>> hits;
@@ -580,6 +744,34 @@ public:
}
bool empty() const { return size == 0; }
void clear() {
if (!root_) return;
std::function<void(OctreeNode*)> clearNode = [&](OctreeNode* node) {
if (!node) return;
node->points.clear();
node->points.shrink_to_fit();
for (int i = 0; i < 8; ++i) {
if (node->children[i]) {
clearNode(node->children[i].get());
node->children[i].reset(nullptr);
}
}
node->isLeaf = true;
};
clearNode(root_.get());
PointType minBound = root_->bounds.first;
PointType maxBound = root_->bounds.second;
root_ = std::make_unique<OctreeNode>(minBound, maxBound);
size = 0;
}
};
#endif