载入中...
搜索中...
未找到
SurfaceCapture.cpp
浏览该文件的文档.
2
3#include "common/Assert.h"
4#include "common/Diagnostic.h"
5
6#include <algorithm>
7#include <cmath>
8
9namespace eve::gpuagents {
10namespace {
11
12bool pointInTriangle2D(const glm::vec2& p, const glm::vec2& a, const glm::vec2& b, const glm::vec2& c, float& w0,
13 float& w1, float& w2) {
14 const glm::vec2 v0 = b - a;
15 const glm::vec2 v1 = c - a;
16 const glm::vec2 v2 = p - a;
17 const float den = v0.x * v1.y - v1.x * v0.y;
18 if (std::abs(den) < 1e-12f) return false;
19 const float inv = 1.f / den;
20 w1 = (v2.x * v1.y - v1.x * v2.y) * inv;
21 w2 = (v0.x * v2.y - v2.x * v0.y) * inv;
22 w0 = 1.f - w1 - w2;
23 return w0 >= -1e-4f && w1 >= -1e-4f && w2 >= -1e-4f;
24}
25
26} // namespace
27
29 if (field.height.empty() || field.resolution < 2) return;
30 const int res = field.resolution;
31 const float cell = field.worldSize / static_cast<float>(res - 1);
32 field.normals.assign(field.height.size(), glm::vec3(0.f, 1.f, 0.f));
33 for (int z = 0; z < res; ++z) {
34 for (int x = 0; x < res; ++x) {
35 const int x0 = std::max(x - 1, 0);
36 const int x1 = std::min(x + 1, res - 1);
37 const int z0 = std::max(z - 1, 0);
38 const int z1 = std::min(z + 1, res - 1);
39 const float hx0 = field.height[static_cast<size_t>(x0 + res * z)];
40 const float hx1 = field.height[static_cast<size_t>(x1 + res * z)];
41 const float hz0 = field.height[static_cast<size_t>(x + res * z0)];
42 const float hz1 = field.height[static_cast<size_t>(x + res * z1)];
43 const glm::vec3 dx(2.f * cell, hx1 - hx0, 0.f);
44 const glm::vec3 dz(0.f, hz1 - hz0, 2.f * cell);
45 glm::vec3 n = glm::cross(dz, dx);
46 const float len = glm::length(n);
47 if (len > 1e-6f)
48 n /= len;
49 else
50 n = glm::vec3(0.f, 1.f, 0.f);
51 field.normals[static_cast<size_t>(x + res * z)] = n;
52 }
53 }
54}
55
57 std::span<const std::uint32_t> indices, const glm::vec3& originMin,
58 float worldSize, int resolution, float baseHeight) {
59 if (resolution < 2) {
61 DiagnosticCode::InvalidArgument, "surface capture resolution must be >= 2", "resolution", {}, "gpuagents"));
62 }
63 if (!(worldSize > 0.f)) {
65 "surface capture worldSize must be positive", "worldSize", {},
66 "gpuagents"));
67 }
68 if (indices.size() % 3 != 0) {
70 "triangle index count must be a multiple of 3", "indices", {},
71 "gpuagents"));
72 }
73 for (std::uint32_t idx : indices) {
74 if (idx >= positions.size()) {
76 "triangle index out of range", "indices", {}, "gpuagents"));
77 }
78 }
79
80 out.initFlat(originMin, worldSize, resolution, baseHeight);
81 const float cell = worldSize / static_cast<float>(resolution - 1);
82
83 for (size_t t = 0; t + 2 < indices.size(); t += 3) {
84 const glm::vec3& A = positions[indices[t]];
85 const glm::vec3& B = positions[indices[t + 1]];
86 const glm::vec3& C = positions[indices[t + 2]];
87 const glm::vec2 a(A.x, A.z), b(B.x, B.z), c(C.x, C.z);
88 const float minX = std::min({a.x, b.x, c.x});
89 const float maxX = std::max({a.x, b.x, c.x});
90 const float minZ = std::min({a.y, b.y, c.y});
91 const float maxZ = std::max({a.y, b.y, c.y});
92 const int x0 = std::clamp(static_cast<int>(std::floor((minX - originMin.x) / cell)), 0, resolution - 1);
93 const int x1 = std::clamp(static_cast<int>(std::ceil((maxX - originMin.x) / cell)), 0, resolution - 1);
94 const int z0 = std::clamp(static_cast<int>(std::floor((minZ - originMin.z) / cell)), 0, resolution - 1);
95 const int z1 = std::clamp(static_cast<int>(std::ceil((maxZ - originMin.z) / cell)), 0, resolution - 1);
96
97 for (int z = z0; z <= z1; ++z) {
98 for (int x = x0; x <= x1; ++x) {
99 const glm::vec2 p(originMin.x + cell * static_cast<float>(x),
100 originMin.z + cell * static_cast<float>(z));
101 float w0 = 0.f, w1 = 0.f, w2 = 0.f;
102 if (!pointInTriangle2D(p, a, b, c, w0, w1, w2)) continue;
103 const float h = w0 * A.y + w1 * B.y + w2 * C.y;
104 auto& dest = out.height[static_cast<size_t>(x + resolution * z)];
105 dest = std::max(dest, h);
106 }
107 }
108 }
109
110 rebuildNormals(out);
111 return Result<void>::success();
112}
113
114} // namespace eve::gpuagents
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
EVEngine assertion entry point, backed by zeroerr.
glm::vec4 p[6]
Stable, structured diagnostics shared by engine modules.
glm::vec3 n
Definition Grass.cpp:63
std::vector< std::uint32_t > indices
std::vector< float > positions
std::int32_t c
int h
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
int idx
float t
float dz
float dx
Cell cell
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Result< void > captureFromTriangles(SurfaceField &out, std::span< const glm::vec3 > positions, std::span< const std::uint32_t > indices, const glm::vec3 &originMin, float worldSize, int resolution, float baseHeight=0.f)
Bake triangle positions into out over the given XZ domain.
static void rebuildNormals(SurfaceField &field)
Rebuild normals from the current height grid (central differences).
2.5D surface + life-field textures for Life Network.
std::vector< float > height
Height samples, resolution^2, row-major X then Z.
void initFlat(const glm::vec3 &originMin, float size, int res, float planeY=0.f)
Allocate grids and fill a flat plane at y = planeY.