it works
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user