some crud and such
This commit is contained in:
@@ -35,6 +35,7 @@ public:
|
||||
T data;
|
||||
PointType position;
|
||||
int objectId;
|
||||
int subId;
|
||||
bool active;
|
||||
bool visible;
|
||||
float size;
|
||||
@@ -45,13 +46,13 @@ public:
|
||||
float reflection;
|
||||
|
||||
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)
|
||||
: 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),
|
||||
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) {}
|
||||
|
||||
// Helper method to get half-size for cube
|
||||
@@ -105,6 +106,30 @@ private:
|
||||
Eigen::Vector3f skylight_ = {0.1f, 0.1f, 0.1f};
|
||||
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 lodMinDistance_ = 100.0f;
|
||||
|
||||
@@ -856,33 +881,44 @@ public:
|
||||
auto pointData = find(oldPos, tolerance);
|
||||
if (!pointData) return false;
|
||||
|
||||
T dataCopy = pointData->data;
|
||||
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;
|
||||
int oldSubId = pointData->subId;
|
||||
int targetObjId = (newObjectId != -2) ? newObjectId : pointData->objectId;
|
||||
|
||||
// Remove the old point
|
||||
if (!remove(oldPos, tolerance)) {
|
||||
return false;
|
||||
int finalSubId = oldSubId;
|
||||
|
||||
if (oldSubId == 0 && targetObjId == pointData->objectId) {
|
||||
finalSubId = nextSubIdGenerator_++;
|
||||
|
||||
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
|
||||
return set(newData, newPos,
|
||||
newVisible ? newVisible : visibleCopy,
|
||||
newColor != Eigen::Vector3f(1.0f, 1.0f, 1.0f) ? newColor : colorCopy,
|
||||
newSize > 0 ? newSize : sizeCopy,
|
||||
newActive ? newActive : activeCopy,
|
||||
newObjectId != -2 ? newObjectId : objectIdCopy,
|
||||
newLight ? newLight : lightCopy,
|
||||
newEmittance > 0 ? newEmittance : emittanceCopy,
|
||||
newRefraction >= 0 ? newRefraction : refractionCopy,
|
||||
newReflection >= 0 ? newReflection : reflectionCopy);
|
||||
if (!remove(oldPos, tolerance)) return false;
|
||||
|
||||
bool res = set(newData, newPos,
|
||||
newVisible,
|
||||
newColor != Eigen::Vector3f(1.0f, 1.0f, 1.0f) ? newColor : pointData->color,
|
||||
newSize > 0 ? newSize : pointData->size,
|
||||
newActive,
|
||||
targetObjId,
|
||||
finalSubId,
|
||||
newLight,
|
||||
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) {
|
||||
@@ -1409,6 +1445,140 @@ public:
|
||||
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 {
|
||||
if (!root_) {
|
||||
os << "[Octree Stats] Tree is null/empty." << std::endl;
|
||||
|
||||
@@ -35,6 +35,7 @@ struct Triangle2D {
|
||||
class Mesh {
|
||||
private:
|
||||
int id;
|
||||
int _subId;
|
||||
std::vector<Vector3f> _vertices;
|
||||
std::vector<std::vector<int>> _polys;
|
||||
std::vector<Color> _colors;
|
||||
@@ -46,31 +47,62 @@ private:
|
||||
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());
|
||||
}
|
||||
|
||||
public:
|
||||
Mesh(int id, const std::vector<Vector3f>& verts, const std::vector<std::vector<int>>& polys, const std::vector<Color>& colors)
|
||||
: id(id), _vertices(verts), _polys(polys), _colors(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), _subId(subId), _vertices(verts), _polys(polys), _colors(colors) {
|
||||
_needs_triangulation = 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() {
|
||||
return _vertices;
|
||||
}
|
||||
|
||||
bool vertices(std::vector<Vector3f> verts) {
|
||||
if (verts.size() != _colors.size()) {
|
||||
if (_colors.size() == 1) {
|
||||
_vertices = verts;
|
||||
bool updateVertex(size_t index, const Vector3f& newPos) {
|
||||
if (index < _vertices.size()) {
|
||||
_vertices[index] = newPos;
|
||||
_needs_norm_calc = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
}
|
||||
|
||||
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() {
|
||||
return _polys;
|
||||
@@ -320,6 +352,11 @@ public:
|
||||
updateStats();
|
||||
}
|
||||
|
||||
void addMeshes(const std::vector<std::shared_ptr<Mesh>>& meshes) {
|
||||
_meshes.insert(_meshes.end(), meshes.begin(), meshes.end());
|
||||
updateStats();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_meshes.clear();
|
||||
updateStats();
|
||||
@@ -400,6 +437,7 @@ public:
|
||||
os << "========================================\n";
|
||||
os << " Scene STATS \n";
|
||||
os << "========================================\n";
|
||||
os << "Total Meshes: " << _meshes.size() << "\n";
|
||||
for (auto m : _meshes) {
|
||||
m->printStats(os);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user