some crud and such

This commit is contained in:
Yggdrasil75
2026-02-16 10:21:18 -05:00
parent d6d638cb01
commit 14b4d06495
2 changed files with 247 additions and 39 deletions

View File

@@ -35,6 +35,7 @@ public:
T data; T data;
PointType position; PointType position;
int objectId; int objectId;
int subId;
bool active; bool active;
bool visible; bool visible;
float size; float size;
@@ -45,13 +46,13 @@ public:
float reflection; float reflection;
NodeData(const T& data, const PointType& pos, bool visible, Eigen::Vector3f color, float size = 0.01f, NodeData(const T& data, const PointType& pos, bool visible, Eigen::Vector3f color, float size = 0.01f,
bool active = true, int objectId = -1, bool light = false, float emittance = 0.0f, bool active = true, int objectId = -1, int subId = 0, bool light = false, float emittance = 0.0f,
float refraction = 0.0f, float reflection = 0.0f) float refraction = 0.0f, float reflection = 0.0f)
: data(data), position(pos), objectId(objectId), active(active), visible(visible), : data(data), position(pos), objectId(objectId), subId(subId), active(active), visible(visible),
color(color), size(size), light(light), emittance(emittance), refraction(refraction), color(color), size(size), light(light), emittance(emittance), refraction(refraction),
reflection(reflection) {} reflection(reflection) {}
NodeData() : objectId(-1), active(false), visible(false), size(0.0f), light(false), NodeData() : objectId(-1), subId(0), active(false), visible(false), size(0.0f), light(false),
emittance(0.0f), refraction(0.0f), reflection(0.0f) {} emittance(0.0f), refraction(0.0f), reflection(0.0f) {}
// Helper method to get half-size for cube // Helper method to get half-size for cube
@@ -104,6 +105,30 @@ private:
Eigen::Vector3f skylight_ = {0.1f, 0.1f, 0.1f}; Eigen::Vector3f skylight_ = {0.1f, 0.1f, 0.1f};
Eigen::Vector3f backgroundColor_ = {0.53f, 0.81f, 0.92f}; Eigen::Vector3f backgroundColor_ = {0.53f, 0.81f, 0.92f};
std::map<std::pair<int, int>, std::shared_ptr<Mesh>> meshCache_;
std::set<std::pair<int, int>> dirtyMeshes_;
int nextSubIdGenerator_ = 1;
void invalidateMesh(int objectId, int subId) {
if (objectId < 0) return;
dirtyMeshes_.insert({objectId, subId});
}
void collectNodesBySubId(OctreeNode* node, int objId, int subId, std::vector<std::shared_ptr<NodeData>>& results) const {
if (!node) return;
if (node->isLeaf) {
for (const auto& pt : node->points) {
if (pt->active && pt->objectId == objId && pt->subId == subId) {
results.push_back(pt);
}
}
} else {
for (const auto& child : node->children) {
if (child) collectNodesBySubId(child.get(), objId, subId, results);
}
}
}
float lodFalloffRate_ = 0.1f; // Lower = better, higher = worse. 0-1 float lodFalloffRate_ = 0.1f; // Lower = better, higher = worse. 0-1
float lodMinDistance_ = 100.0f; float lodMinDistance_ = 100.0f;
@@ -855,34 +880,45 @@ public:
auto pointData = find(oldPos, tolerance); auto pointData = find(oldPos, tolerance);
if (!pointData) return false; if (!pointData) return false;
int oldSubId = pointData->subId;
int targetObjId = (newObjectId != -2) ? newObjectId : pointData->objectId;
T dataCopy = pointData->data; int finalSubId = oldSubId;
bool activeCopy = pointData->active;
bool visibleCopy = pointData->visible;
Eigen::Vector3f colorCopy = pointData->color;
float sizeCopy = pointData->size;
int objectIdCopy = pointData->objectId;
bool lightCopy = pointData->light;
float emittanceCopy = pointData->emittance;
float refractionCopy = pointData->refraction;
float reflectionCopy = pointData->reflection;
// Remove the old point if (oldSubId == 0 && targetObjId == pointData->objectId) {
if (!remove(oldPos, tolerance)) { finalSubId = nextSubIdGenerator_++;
return false;
auto neighbors = findInRadius(oldPos, newSize * 3.0f, targetObjId);
for(auto& n : neighbors) {
if(n->subId == 0) {
n->subId = finalSubId;
invalidateMesh(targetObjId, 0);
}
}
} }
// Insert at new position with updated properties if (!remove(oldPos, tolerance)) return false;
return set(newData, newPos,
newVisible ? newVisible : visibleCopy, bool res = set(newData, newPos,
newColor != Eigen::Vector3f(1.0f, 1.0f, 1.0f) ? newColor : colorCopy, newVisible,
newSize > 0 ? newSize : sizeCopy, newColor != Eigen::Vector3f(1.0f, 1.0f, 1.0f) ? newColor : pointData->color,
newActive ? newActive : activeCopy, newSize > 0 ? newSize : pointData->size,
newObjectId != -2 ? newObjectId : objectIdCopy, newActive,
newLight ? newLight : lightCopy, targetObjId,
newEmittance > 0 ? newEmittance : emittanceCopy, finalSubId,
newRefraction >= 0 ? newRefraction : refractionCopy, newLight,
newReflection >= 0 ? newReflection : reflectionCopy); newEmittance > 0 ? newEmittance : pointData->emittance,
newRefraction >= 0 ? newRefraction : pointData->refraction,
newReflection >= 0 ? newReflection : pointData->reflection);
if(res) {
// Mark relevant meshes dirty
invalidateMesh(targetObjId, finalSubId);
if(finalSubId != oldSubId) invalidateMesh(targetObjId, oldSubId);
}
return res;
} }
bool move(const PointType& pos, const PointType& newPos) { bool move(const PointType& pos, const PointType& newPos) {
@@ -1409,6 +1445,140 @@ public:
return std::make_shared<Mesh>(objectId, vertices, polys, vertexColors); return std::make_shared<Mesh>(objectId, vertices, polys, vertexColors);
} }
std::shared_ptr<Mesh> generateSubMesh(int objectId, int subId, float isolevel = 0.5f, int resolution = 32) {
if (subId == -999) return nullptr;
std::vector<std::shared_ptr<NodeData>> nodes;
collectNodesBySubId(root_.get(), objectId, subId, nodes);
if (nodes.empty()) return nullptr;
PointType minB = nodes[0]->position;
PointType maxB = nodes[0]->position;
float maxRadius = 0.0f;
for(auto& n : nodes) {
minB = minB.cwiseMin(n->position);
maxB = maxB.cwiseMax(n->position);
maxRadius = std::max(maxRadius, n->size);
}
float padding = maxRadius * 2.5f;
minB -= PointType::Constant(padding);
maxB += PointType::Constant(padding);
PointType size = maxB - minB;
PointType step = size / static_cast<float>(resolution);
std::vector<PointType> vertices;
std::vector<Eigen::Vector3f> vertexColors;
std::vector<Eigen::Vector3i> triangles;
// Marching Cubes Loop
for(int z = 0; z < resolution; ++z) {
for(int y = 0; y < resolution; ++y) {
for(int x = 0; x < resolution; ++x) {
PointType currPos(minB.x() + x * step.x(), minB.y() + y * step.y(), minB.z() + z * step.z());
GridCell cell;
PointType offsets[8] = {{0,0,0}, {step.x(),0,0}, {step.x(),step.y(),0}, {0,step.y(),0},
{0,0,step.z()}, {step.x(),0,step.z()}, {step.x(),step.y(),step.z()}, {0,step.y(),step.z()}};
bool activeCell = false;
for(int i=0; i<8; ++i) {
cell.p[i] = currPos + offsets[i];
auto [density, color] = getScalarFieldValue(cell.p[i], objectId, maxRadius * 2.0f);
cell.val[i] = density;
cell.color[i] = color;
if(cell.val[i] >= isolevel) activeCell = true;
}
if(activeCell) {
auto owner = find(currPos + step*0.5f, maxRadius * 2.0f);
if (owner && owner->objectId == objectId && owner->subId == subId) {
polygonise(cell, isolevel, vertices, vertexColors, triangles);
}
}
}
}
}
if(vertices.empty()) return nullptr;
std::vector<std::vector<int>> polys;
for(auto& t : triangles) polys.push_back({t[0], t[1], t[2]});
return std::make_shared<Mesh>(objectId, vertices, polys, vertexColors, subId);
}
std::vector<std::shared_ptr<Mesh>> getMeshes(int objectId) {
std::vector<std::shared_ptr<Mesh>> result;
std::set<int> relevantSubIds;
for(auto const& [key, val] : meshCache_) if(key.first == objectId) relevantSubIds.insert(key.second);
for(auto const& key : dirtyMeshes_) if(key.first == objectId) relevantSubIds.insert(key.second);
for(int subId : relevantSubIds) {
if(dirtyMeshes_.count({objectId, subId})) {
auto newMesh = generateSubMesh(objectId, subId);
if(newMesh) meshCache_[{objectId, subId}] = newMesh;
else meshCache_.erase({objectId, subId});
dirtyMeshes_.erase({objectId, subId});
}
}
for(auto const& [key, mesh] : meshCache_) {
if(key.first == objectId && mesh) result.push_back(mesh);
}
return result;
}
void isolateInternalNodes(int objectId) {
std::vector<std::shared_ptr<NodeData>> nodes;
collectNodesByObjectId(root_.get(), objectId, nodes);
if(nodes.empty()) return;
float checkRad = nodes[0]->size * 1.5f;
for(auto& node : nodes) {
int hiddenSides = 0;
PointType dirs[6] = {{1,0,0}, {-1,0,0}, {0,1,0}, {0,-1,0}, {0,0,1}, {0,0,-1}};
for(int i=0; i<6; ++i) {
auto neighbor = find(node->position + dirs[i] * node->size, checkRad);
if(neighbor && neighbor->objectId == objectId && neighbor->active && neighbor->refraction < 0.01f) {
hiddenSides++;
}
}
if(hiddenSides == 6) {
if(node->subId != -999) {
invalidateMesh(objectId, node->subId);
node->subId = -999;
}
}
}
}
bool moveObject(int objectId, const PointType& offset) {
if (!root_) return false;
std::vector<std::shared_ptr<NodeData>> nodes;
collectNodesByObjectId(root_.get(), objectId, nodes);
if(nodes.empty()) return false;
for(auto& n : nodes) remove(n->position);
for(auto& n : nodes) {
n->position += offset;
insertRecursive(root_.get(), n, 0);
}
for (auto& [key, mesh] : meshCache_) {
if (key.first == objectId && mesh) {
mesh->translate(offset);
}
}
return true;
}
void printStats(std::ostream& os = std::cout) const { void printStats(std::ostream& os = std::cout) const {
if (!root_) { if (!root_) {
os << "[Octree Stats] Tree is null/empty." << std::endl; os << "[Octree Stats] Tree is null/empty." << std::endl;

View File

@@ -35,6 +35,7 @@ struct Triangle2D {
class Mesh { class Mesh {
private: private:
int id; int id;
int _subId;
std::vector<Vector3f> _vertices; std::vector<Vector3f> _vertices;
std::vector<std::vector<int>> _polys; std::vector<std::vector<int>> _polys;
std::vector<Color> _colors; std::vector<Color> _colors;
@@ -46,30 +47,61 @@ private:
inline static float edgeFunction(const Vector2f& a, const Vector2f& b, const Vector2f& c) { inline static float edgeFunction(const Vector2f& a, const Vector2f& b, const Vector2f& c) {
return (c.x() - a.x()) * (b.y() - a.y()) - (c.y() - a.y()) * (b.x() - a.x()); return (c.x() - a.x()) * (b.y() - a.y()) - (c.y() - a.y()) * (b.x() - a.x());
} }
public: public:
Mesh(int id, const std::vector<Vector3f>& verts, const std::vector<std::vector<int>>& polys, const std::vector<Color>& colors) Mesh(int id, const std::vector<Vector3f>& verts, const std::vector<std::vector<int>>& polys, const std::vector<Color>& colors, int subId = 0)
: id(id), _vertices(verts), _polys(polys), _colors(colors) { : id(id), _subId(subId), _vertices(verts), _polys(polys), _colors(colors) {
_needs_triangulation = true; _needs_triangulation = true;
_needs_norm_calc = true; _needs_norm_calc = true;
} }
int getId() const {
return id;
}
int getSubId() const {
return _subId;
}
void setSubId(int s) {
_subId = s;
}
std::vector<Vector3f> vertices() { std::vector<Vector3f> vertices() {
return _vertices; return _vertices;
} }
bool vertices(std::vector<Vector3f> verts) { bool updateVertex(size_t index, const Vector3f& newPos) {
if (verts.size() != _colors.size()) { if (index < _vertices.size()) {
if (_colors.size() == 1) { _vertices[index] = newPos;
_vertices = verts;
_needs_norm_calc = true;
return true;
}
return false;
} else {
_vertices = verts;
_needs_norm_calc = true; _needs_norm_calc = true;
return true; return true;
} }
return false;
}
void translate(const Vector3f& offset) {
for(auto& v : _vertices) {
v += offset;
}
_needs_norm_calc = false;
}
void replace(const std::vector<Vector3f>& verts, const std::vector<std::vector<int>>& polys, const std::vector<Color>& colors) {
_vertices = verts;
_polys = polys;
_colors = colors;
_needs_triangulation = true;
_needs_norm_calc = true;
}
bool vertices(std::vector<Vector3f> verts) {
if (verts.size() != _colors.size() && _colors.size() != 1) {
return false;
}
_vertices = verts;
_needs_norm_calc = true;
return true;
} }
std::vector<std::vector<int>> polys() { std::vector<std::vector<int>> polys() {
@@ -319,6 +351,11 @@ public:
_meshes.push_back(mesh); _meshes.push_back(mesh);
updateStats(); updateStats();
} }
void addMeshes(const std::vector<std::shared_ptr<Mesh>>& meshes) {
_meshes.insert(_meshes.end(), meshes.begin(), meshes.end());
updateStats();
}
void clear() { void clear() {
_meshes.clear(); _meshes.clear();
@@ -400,6 +437,7 @@ public:
os << "========================================\n"; os << "========================================\n";
os << " Scene STATS \n"; os << " Scene STATS \n";
os << "========================================\n"; os << "========================================\n";
os << "Total Meshes: " << _meshes.size() << "\n";
for (auto m : _meshes) { for (auto m : _meshes) {
m->printStats(os); m->printStats(os);
} }