mirror of
https://github.com/Nexoniarz/Fry3DX.git
synced 2026-11-03 12:34:27 +00:00
Shapes with live settings, shape editing, knife and hole tools, drawing shapes onto other objects, combining objects (add / subtract / overlap), copies, thickness, painting with stickers and layers, a Layout tab, a Print tab with checks, packed .fry files with autosave, export to GLB, glTF, FBX, OBJ, 3MF, STL and PLY, folders in Layers, its own crash screen, and a website for GitHub Pages in docs/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMSrd5oe1GpUD7E6d825KP
72 lines
3.7 KiB
C++
72 lines
3.7 KiB
C++
#include "render/clusters.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace keel {
|
|
namespace {
|
|
const float kLogRatio = std::log(kClusterFar / kClusterNear);
|
|
|
|
float sliceStart(uint32_t k) { return k == 0 ? 0.0f : kClusterNear * std::exp(kLogRatio * float(k) / kClusterZ); }
|
|
|
|
float distSq(float v, float lo, float hi) {
|
|
const float d = v < lo ? lo - v : v > hi ? v - hi : 0.0f;
|
|
return d * d;
|
|
}
|
|
} // namespace
|
|
|
|
uint32_t clusterSlice(float depth) {
|
|
if (depth <= kClusterNear) return 0;
|
|
return std::min(uint32_t(std::log(depth / kClusterNear) / kLogRatio * kClusterZ), kClusterZ - 1);
|
|
}
|
|
|
|
void buildClusters(const ClusterView& v, const std::vector<DynamicLight>& lights, size_t maxIndices, ClusterGrid& out) {
|
|
const uint32_t cellCount = kClusterX * kClusterY * kClusterZ;
|
|
out.cells.assign(cellCount, glm::uvec2(0));
|
|
out.indices.clear();
|
|
const float tanY = v.tanHalfY, tanX = v.tanHalfY * v.aspect;
|
|
std::vector<uint32_t> pairs; // cell << 12 | light
|
|
for (uint32_t li = 0; li < lights.size() && li < 4096; ++li) {
|
|
const DynamicLight& l = lights[li];
|
|
const glm::vec3 d = l.origin - v.origin;
|
|
const glm::vec3 c(glm::dot(d, v.right), glm::dot(d, v.up), glm::dot(d, v.forward)); // view space, z forward
|
|
const float r = l.radius;
|
|
if (c.z + r <= 0.0f) continue;
|
|
const uint32_t z0 = clusterSlice(std::max(c.z - r, 0.0f)), z1 = clusterSlice(c.z + r);
|
|
for (uint32_t z = z0; z <= z1; ++z) {
|
|
const float dn = std::max(sliceStart(z), 0.05f), df = z + 1 == kClusterZ ? kClusterFar : sliceStart(z + 1);
|
|
// Conservative tile range from the sphere's extent at both ends of the slice.
|
|
auto tileU = [&](float x, float depth) { return (x / (depth * tanX) + 1.0f) * 0.5f * kClusterX; };
|
|
auto tileV = [&](float y, float depth) { return (1.0f - y / (depth * tanY)) * 0.5f * kClusterY; };
|
|
float u0 = 1e9f, u1 = -1e9f, v0 = 1e9f, v1 = -1e9f;
|
|
for (float depth : {dn, df}) {
|
|
for (float x : {c.x - r, c.x + r}) u0 = std::min(u0, tileU(x, depth)), u1 = std::max(u1, tileU(x, depth));
|
|
for (float y : {c.y - r, c.y + r}) v0 = std::min(v0, tileV(y, depth)), v1 = std::max(v1, tileV(y, depth));
|
|
}
|
|
const int x0 = std::max(int(std::floor(u0)), 0), x1 = std::min(int(std::floor(u1)), int(kClusterX) - 1);
|
|
const int y0 = std::max(int(std::floor(v0)), 0), y1 = std::min(int(std::floor(v1)), int(kClusterY) - 1);
|
|
for (int y = y0; y <= y1; ++y) {
|
|
// Cell bounds in view space: y shrinks downwards (v grows), x grows rightwards.
|
|
const float yt = 1.0f - 2.0f * y / kClusterY, yb = 1.0f - 2.0f * (y + 1) / kClusterY;
|
|
const float ylo = std::min({yb * dn, yb * df}) * tanY, yhi = std::max({yt * dn, yt * df}) * tanY;
|
|
for (int x = x0; x <= x1; ++x) {
|
|
const float xl = 2.0f * x / kClusterX - 1.0f, xr = 2.0f * (x + 1) / kClusterX - 1.0f;
|
|
const float xlo = std::min({xl * dn, xl * df}) * tanX, xhi = std::max({xr * dn, xr * df}) * tanX;
|
|
if (distSq(c.x, xlo, xhi) + distSq(c.y, ylo, yhi) + distSq(c.z, dn, df) > r * r) continue;
|
|
pairs.push_back(((z * kClusterY + y) * kClusterX + x) << 12 | li);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
std::sort(pairs.begin(), pairs.end());
|
|
if (pairs.size() > maxIndices) pairs.resize(maxIndices);
|
|
out.indices.reserve(pairs.size());
|
|
for (uint32_t p : pairs) {
|
|
glm::uvec2& cell = out.cells[p >> 12];
|
|
if (cell.y == 0) cell.x = uint32_t(out.indices.size());
|
|
++cell.y;
|
|
out.indices.push_back(p & 0xFFF);
|
|
}
|
|
}
|
|
|
|
} // namespace keel
|