载入中...
搜索中...
未找到
FluidSdf.cpp
浏览该文件的文档.
1#include "fluids/FluidSdf.h"
2
3#include <algorithm>
4#include <array>
5#include <cfloat>
6#include <cmath>
7
8namespace eve::fluids {
9namespace {
10
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);
19
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);
24
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));
29 }
30
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);
35
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));
40 }
41
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));
46 }
47
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));
52}
53
55bool pointInsideMesh(const glm::vec3& p, const std::vector<glm::vec3>& pos, const std::vector<uint32_t>& idx,
56 int triCount) {
57 // Axis rays frequently pass through shared vertices/edges in symmetric meshes,
58 // double-counting one crossing. A fixed irrational-looking direction preserves
59 // deterministic baking while avoiding those systematic degeneracies.
60 const glm::vec3 direction = glm::normalize(glm::vec3(1.f, .37139067f, .127831f));
61 int hits = 0;
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]];
66 // Moller-Trumbore ray from p along the fixed skew direction.
67 const glm::vec3 e1 = b - a;
68 const glm::vec3 e2 = c - a;
69 const glm::vec3 h = glm::cross(direction, e2);
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);
77 const float v = invDet * glm::dot(direction, q);
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;
81 }
82 return (hits & 1) != 0;
83}
84
85} // namespace
86
87int MeshSdf::voxelCount() const { return dims.x * dims.y * dims.z; }
88
89int MeshSdf::index(int x, int y, int z) const { return x + dims.x * (y + dims.y * z); }
90
91bool MeshSdf::inBounds(const glm::ivec3& c) const {
92 return c.x >= 0 && c.y >= 0 && c.z >= 0 && c.x < dims.x && c.y < dims.y && c.z < dims.z;
93}
94
95float MeshSdf::sample(const glm::vec3& p) const { return sampleWithGradient(p).distance; }
96
98 if (dims.x < 2 || dims.y < 2 || dims.z < 2 || !(cellSize > 0.f) || distances.size() != size_t(voxelCount()))
99 return {FLT_MAX, glm::vec3(0.f, 1.f, 0.f)};
100 const glm::vec3 maximum = origin + glm::vec3(dims - glm::ivec3(1)) * cellSize;
101 const glm::vec3 clampedPoint = glm::clamp(p, origin, maximum);
102 const glm::vec3 outside = p - clampedPoint;
103 const glm::vec3 f = (clampedPoint - origin) / cellSize;
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));
107 const float v000 = distances[size_t(index(i0.x, i0.y, i0.z))];
108 const float v100 = distances[size_t(index(i1.x, i0.y, i0.z))];
109 const float v010 = distances[size_t(index(i0.x, i1.y, i0.z))];
110 const float v110 = distances[size_t(index(i1.x, i1.y, i0.z))];
111 const float v001 = distances[size_t(index(i0.x, i0.y, i1.z))];
112 const float v101 = distances[size_t(index(i1.x, i0.y, i1.z))];
113 const float v011 = distances[size_t(index(i0.x, i1.y, i1.z))];
114 const float v111 = distances[size_t(index(i1.x, i1.y, i1.z))];
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);
119 const float distance = mix(y0, y1, t.z);
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}
125 : MeshSdfSample{distance, {dx, dy, dz}};
126}
127
128glm::vec3 MeshSdf::gradient(const glm::vec3& p) const { return sampleWithGradient(p).gradient; }
129
130MeshSdf MeshSdf::makeSphere(const glm::vec3& center, float radius, const glm::ivec3& dims) {
131 MeshSdf sdf;
132 sdf.dims = dims;
133 const float margin = radius * 0.5f;
134 const float extent = 2.f * (radius + margin);
135 sdf.cellSize = extent / float(dims.x);
136 sdf.origin = center - glm::vec3(radius + margin);
137 sdf.distances.resize(size_t(sdf.voxelCount()));
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;
142 sdf.distances[size_t(sdf.index(x, y, z))] = glm::length(p - center) - radius;
143 }
144 }
145 }
146 return sdf;
147}
148
149MeshSdf MeshSdf::makePlane(float planeY, const glm::ivec3& dims, float halfExtent) {
150 MeshSdf sdf;
151 sdf.dims = dims;
152 sdf.cellSize = (2.f * halfExtent) / float(dims.x);
153 sdf.origin = glm::vec3(-halfExtent, planeY - halfExtent, -halfExtent);
154 sdf.distances.resize(size_t(sdf.voxelCount()));
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;
159 sdf.distances[size_t(sdf.index(x, y, z))] = p.y - planeY;
160 }
161 }
162 }
163 return sdf;
164}
165
166MeshSdf MeshSdf::makeFromTriangles(const std::vector<glm::vec3>& positions, const std::vector<uint32_t>& indices,
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);
171 for (const glm::vec3& v : positions) {
172 minP = glm::min(minP, v);
173 maxP = glm::max(maxP, v);
174 }
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)});
179
180 MeshSdf sdf;
181 sdf.dims = dims;
182 sdf.cellSize = cell;
183 sdf.origin = minP - pad;
184 sdf.distances.assign(size_t(sdf.voxelCount()), FLT_MAX);
185
186 // Sweep each triangle over its expanded AABB and keep the min distance.
187 for (int t = 0; t < triCount; ++t) {
188 const glm::vec3 a = positions[indices[uint32_t(t) * 3 + 0]];
189 const glm::vec3 b = positions[indices[uint32_t(t) * 3 + 1]];
190 const glm::vec3 c = positions[indices[uint32_t(t) * 3 + 2]];
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);
204 }
205 }
206 }
207 }
208
209 // Sign from even-odd raycast per voxel center.
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) {
216 // The narrow triangle sweep leaves deep interior and far exterior
217 // cells untouched. Resolve those cells exactly once during baking;
218 // substituting one cell width destroys the SDF magnitude and makes
219 // collision projection depend on grid resolution.
220 float distance = FLT_MAX;
221 for (int tri = 0; tri < triCount; ++tri) {
222 const glm::vec3 a = positions[indices[uint32_t(tri) * 3 + 0]];
223 const glm::vec3 b = positions[indices[uint32_t(tri) * 3 + 1]];
224 const glm::vec3 c = positions[indices[uint32_t(tri) * 3 + 2]];
225 distance = std::min(distance, triangleDistance(p, a, b, c));
226 }
227 sdf.distances[i] = distance;
228 }
229 if (pointInsideMesh(p, positions, indices, triCount)) {
230 sdf.distances[i] = -sdf.distances[i];
231 }
232 }
233 }
234 }
235 return sdf;
236}
237
238} // namespace eve::fluids
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
const std::string & s
glm::vec4 p[6]
float maximum[3]
uint32_t i1
Definition Grass.cpp:61
uint32_t i0
Definition Grass.cpp:61
float u
Definition Grass.cpp:233
std::array< double, 10 > q
std::uint32_t ab
std::uint32_t ac
std::vector< std::uint32_t > indices
std::vector< float > positions
float v
std::int32_t c
int h
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float distance
int idx
float f
float radius
float d
float t
RoadLaneDirection direction
float dz
float dy
float dx
Cell cell
int margin
uint32_t index
Uniform signed-distance voxel field over a box.
Definition FluidSdf.h:28
glm::ivec3 dims
Voxel resolution along each axis.
Definition FluidSdf.h:35
float cellSize
World-space size of one voxel.
Definition FluidSdf.h:33
glm::vec3 gradient(const glm::vec3 &p) const
Analytic trilinear gradient (outward normal) at p.
Definition FluidSdf.cpp:128
glm::vec3 origin
World-space position of voxel (0,0,0).
Definition FluidSdf.h:31
std::vector< float > distances
Signed distances, dims.x * dims.y * dims.z floats.
Definition FluidSdf.h:37
static MeshSdf makeSphere(const glm::vec3 &center, float radius, const glm::ivec3 &dims)
Bake an analytic sphere into the field.
Definition FluidSdf.cpp:130
MeshSdfSample sampleWithGradient(const glm::vec3 &p) const
Samples distance and analytic trilinear gradient from the same eight voxels.
Definition FluidSdf.cpp:97
int voxelCount() const
Voxel count.
Definition FluidSdf.cpp:87
float sample(const glm::vec3 &p) const
Trilinearly interpolated signed distance at p.
Definition FluidSdf.cpp:95
static MeshSdf makePlane(float planeY, const glm::ivec3 &dims, float halfExtent)
Bake a horizontal plane y = planeY into the field.
Definition FluidSdf.cpp:149
static MeshSdf makeFromTriangles(const std::vector< glm::vec3 > &positions, const std::vector< uint32_t > &indices, const glm::ivec3 &dims)
Voxelize a closed triangle mesh.
Definition FluidSdf.cpp:166
bool inBounds(const glm::ivec3 &c) const
In bounds.
Definition FluidSdf.cpp:91
int index(int x, int y, int z) const
Index.
Definition FluidSdf.cpp:89
GLSL compute kernels for the GPU surface-flow solver.
Definition FluidTarget.h:12
One trilinear SDF sample and its local-space analytic gradient.
Definition FluidSdf.h:22
uint32_t pad[2]