12float triangleDistance(
const glm::vec3&
p,
const glm::vec3&
a,
const glm::vec3&
b,
const glm::vec3&
c) {
13 const glm::vec3
ab =
b -
a;
14 const glm::vec3
ac =
c -
a;
15 const glm::vec3 ap =
p -
a;
16 const float d1 = glm::dot(
ab, ap);
17 const float d2 = glm::dot(
ac, ap);
18 if (d1 <= 0.f && d2 <= 0.f)
return glm::length(
p -
a);
20 const glm::vec3 bp =
p -
b;
21 const float d3 = glm::dot(
ab, bp);
22 const float d4 = glm::dot(
ac, bp);
23 if (d3 >= 0.f && d4 <= d3)
return glm::length(
p -
b);
25 const float vc = d1 * d4 - d3 * d2;
26 if (vc <= 0.f && d1 >= 0.f && d3 <= 0.f) {
27 const float t = d1 / (d1 - d3);
28 return glm::length(
p - (
a +
ab *
t));
31 const glm::vec3 cp =
p -
c;
32 const float d5 = glm::dot(
ab, cp);
33 const float d6 = glm::dot(
ac, cp);
34 if (d6 >= 0.f && d5 <= d6)
return glm::length(
p -
c);
36 const float vb = d5 * d2 - d1 * d6;
37 if (vb <= 0.f && d2 >= 0.f && d6 <= 0.f) {
38 const float t = d2 / (d2 - d6);
39 return glm::length(
p - (
a +
ac *
t));
42 const float va = d3 * d6 - d5 * d4;
43 if (va <= 0.f && d4 - d3 >= 0.f && d5 - d6 >= 0.f) {
44 const float t2 = (d4 - d3) / ((d4 - d3) + (d5 - d6));
45 return glm::length(
p - (
b + (
c -
b) * t2));
48 const float denom = 1.f / (va + vb + vc);
49 const float v = vb * denom;
50 const float w = vc * denom;
51 return glm::length(
p - (
a +
ab *
v +
ac *
w));
55bool pointInsideMesh(
const glm::vec3&
p,
const std::vector<glm::vec3>&
pos,
const std::vector<uint32_t>&
idx,
60 const glm::vec3
direction = glm::normalize(glm::vec3(1.f, .37139067f, .127831f));
62 for (
int tri = 0; tri < triCount; ++tri) {
63 const glm::vec3
a =
pos[
idx[uint32_t(tri) * 3 + 0]];
64 const glm::vec3
b =
pos[
idx[uint32_t(tri) * 3 + 1]];
65 const glm::vec3
c =
pos[
idx[uint32_t(tri) * 3 + 2]];
67 const glm::vec3 e1 =
b -
a;
68 const glm::vec3 e2 =
c -
a;
70 const float det = glm::dot(e1,
h);
71 if (std::fabs(det) < 1e-12f)
continue;
72 const float invDet = 1.f / det;
73 const glm::vec3
s =
p -
a;
74 const float u = invDet * glm::dot(
s,
h);
75 if (u < 0.f || u > 1.f)
continue;
76 const glm::vec3
q = glm::cross(
s, e1);
78 if (v < 0.f || u + v > 1.f)
continue;
79 const float t = invDet * glm::dot(e2,
q);
80 if (
t > 1e-8f) ++hits;
82 return (hits & 1) != 0;
92 return c.x >= 0 &&
c.y >= 0 &&
c.z >= 0 &&
c.x <
dims.x &&
c.y <
dims.y &&
c.z <
dims.z;
99 return {FLT_MAX, glm::vec3(0.f, 1.f, 0.f)};
102 const glm::vec3 outside =
p - clampedPoint;
104 const glm::ivec3
i0 = glm::min(glm::ivec3(glm::floor(
f)),
dims - glm::ivec3(2));
105 const glm::ivec3
i1 =
i0 + glm::ivec3(1);
106 const glm::vec3
t = glm::clamp(
f - glm::vec3(
i0), glm::vec3(0.f), glm::vec3(1.f));
115 const auto mix = [](
float a,
float b,
float u) {
return a + (
b -
a) *
u; };
116 const float x00 = mix(v000, v100,
t.x), x10 = mix(v010, v110,
t.x);
117 const float x01 = mix(v001, v101,
t.x), x11 = mix(v011, v111,
t.x);
118 const float y0 = mix(x00, x10,
t.y), y1 = mix(x01, x11,
t.y);
120 const float dx = mix(mix(v100 - v000, v110 - v010,
t.y), mix(v101 - v001, v111 - v011,
t.y),
t.z) /
cellSize;
121 const float dy = mix(mix(v010 - v000, v110 - v100,
t.x), mix(v011 - v001, v111 - v101,
t.x),
t.z) /
cellSize;
122 const float dz = mix(mix(v001 - v000, v101 - v100,
t.x), mix(v011 - v010, v111 - v110,
t.x),
t.y) /
cellSize;
123 const float outsideDistance = glm::length(outside);
124 return outsideDistance > 1e-7f ?
MeshSdfSample{
distance + outsideDistance, outside / outsideDistance}
138 for (
int z = 0;
z <
dims.z; ++
z) {
139 for (
int y = 0;
y <
dims.y; ++
y) {
140 for (
int x = 0;
x <
dims.x; ++
x) {
141 const glm::vec3
p = sdf.
origin + glm::vec3(
float(
x),
float(
y),
float(
z)) * sdf.
cellSize;
155 for (
int z = 0;
z <
dims.z; ++
z) {
156 for (
int y = 0;
y <
dims.y; ++
y) {
157 for (
int x = 0;
x <
dims.x; ++
x) {
158 const glm::vec3
p = sdf.
origin + glm::vec3(
float(
x),
float(
y),
float(
z)) * sdf.
cellSize;
167 const glm::ivec3& dims) {
168 const int triCount = int(
indices.size()) / 3;
169 glm::vec3 minP(FLT_MAX);
170 glm::vec3 maxP(-FLT_MAX);
172 minP = glm::min(minP,
v);
173 maxP = glm::max(maxP,
v);
175 const glm::vec3 extent = maxP - minP;
176 const glm::vec3
pad = extent * 0.25f + glm::vec3(1e-3f);
177 const glm::vec3 total = extent +
pad * 2.f;
178 const float cell = std::max({total.x / float(
dims.x), total.y / float(
dims.y), total.z / float(
dims.z)});
183 sdf.origin = minP -
pad;
184 sdf.distances.assign(
size_t(sdf.voxelCount()), FLT_MAX);
187 for (
int t = 0;
t < triCount; ++
t) {
191 const glm::vec3 tmin = glm::min(
a, glm::min(
b,
c));
192 const glm::vec3 tmax = glm::max(
a, glm::max(
b,
c));
193 const glm::ivec3 c0 = glm::clamp(glm::ivec3(glm::floor((tmin - sdf.origin) /
cell)) - glm::ivec3(1),
194 glm::ivec3(0),
dims - glm::ivec3(1));
195 const glm::ivec3 c1 = glm::clamp(glm::ivec3(glm::floor((tmax - sdf.origin) /
cell)) + glm::ivec3(1),
196 glm::ivec3(0),
dims - glm::ivec3(1));
197 for (
int z = c0.z;
z <= c1.z; ++
z) {
198 for (
int y = c0.y;
y <= c1.y; ++
y) {
199 for (
int x = c0.x;
x <= c1.x; ++
x) {
200 const glm::vec3
p = sdf.origin + glm::vec3(
float(
x),
float(
y),
float(
z)) *
cell;
201 const float d = triangleDistance(
p,
a,
b,
c);
202 float& slot = sdf.distances[size_t(sdf.index(
x,
y,
z))];
203 slot = std::min(slot,
d);
210 for (
int z = 0;
z <
dims.z; ++
z) {
211 for (
int y = 0;
y <
dims.y; ++
y) {
212 for (
int x = 0;
x <
dims.x; ++
x) {
213 const glm::vec3
p = sdf.origin + glm::vec3(
float(
x),
float(
y),
float(
z)) *
cell;
214 const size_t i = size_t(sdf.index(
x,
y,
z));
215 if (sdf.distances[i] >= FLT_MAX) {
221 for (
int tri = 0; tri < triCount; ++tri) {
230 sdf.distances[i] = -sdf.distances[i];
std::array< double, 10 > q
std::vector< std::uint32_t > indices
std::vector< float > positions
RoadLaneDirection direction
Uniform signed-distance voxel field over a box.
glm::ivec3 dims
Voxel resolution along each axis.
float cellSize
World-space size of one voxel.
glm::vec3 gradient(const glm::vec3 &p) const
Analytic trilinear gradient (outward normal) at p.
glm::vec3 origin
World-space position of voxel (0,0,0).
std::vector< float > distances
Signed distances, dims.x * dims.y * dims.z floats.
static MeshSdf makeSphere(const glm::vec3 ¢er, float radius, const glm::ivec3 &dims)
Bake an analytic sphere into the field.
MeshSdfSample sampleWithGradient(const glm::vec3 &p) const
Samples distance and analytic trilinear gradient from the same eight voxels.
int voxelCount() const
Voxel count.
float sample(const glm::vec3 &p) const
Trilinearly interpolated signed distance at p.
static MeshSdf makePlane(float planeY, const glm::ivec3 &dims, float halfExtent)
Bake a horizontal plane y = planeY into the field.
static MeshSdf makeFromTriangles(const std::vector< glm::vec3 > &positions, const std::vector< uint32_t > &indices, const glm::ivec3 &dims)
Voxelize a closed triangle mesh.
bool inBounds(const glm::ivec3 &c) const
In bounds.
int index(int x, int y, int z) const
Index.
GLSL compute kernels for the GPU surface-flow solver.
One trilinear SDF sample and its local-space analytic gradient.