载入中...
搜索中...
未找到
HeightmapMesh.cpp
浏览该文件的文档.
2
3#include "common/Module.h"
4#include "graphics/Graphics.h"
6
7#include <algorithm>
8#include <cmath>
9#include <cstdint>
10#include <vector>
11
13namespace {
14
15struct HeightmapArrays {
16 std::vector<float> positions;
17 std::vector<float> normals;
18 std::vector<float> texcoords;
19 std::vector<std::uint32_t> indices;
20};
21
22void buildSmooth(const procgen::Heightmap& heightmap, float cellSize, float heightScale,
23 HeightmapArrays& output) {
24 const int width = heightmap.getWidth();
25 const int height = heightmap.getHeight();
26 if (width < 2 || height < 2 || cellSize == 0.0F) return;
27 output.positions.reserve(static_cast<std::size_t>(width * height * 3));
28 output.normals.reserve(static_cast<std::size_t>(width * height * 3));
29 output.texcoords.reserve(static_cast<std::size_t>(width * height * 2));
30 output.indices.reserve(static_cast<std::size_t>((width - 1) * (height - 1) * 6));
31 auto sample = [&](int x, int y) {
32 return heightmap.height(std::clamp(x, 0, width - 1), std::clamp(y, 0, height - 1));
33 };
34 for (int y = 0; y < height; ++y) {
35 for (int x = 0; x < width; ++x) {
36 output.positions.insert(output.positions.end(),
37 {static_cast<float>(x) * cellSize,
38 heightmap.height(x, y) * heightScale,
39 static_cast<float>(y) * cellSize});
40 float nx = -(sample(x + 1, y) - sample(x - 1, y)) * 0.5F * heightScale / cellSize;
41 float ny = 1.0F;
42 float nz = -(sample(x, y + 1) - sample(x, y - 1)) * 0.5F * heightScale / cellSize;
43 const float length = std::sqrt(nx * nx + ny * ny + nz * nz);
44 if (length > 1.0e-8F) {
45 nx /= length;
46 ny /= length;
47 nz /= length;
48 }
49 output.normals.insert(output.normals.end(), {nx, ny, nz});
50 output.texcoords.insert(output.texcoords.end(),
51 {static_cast<float>(x) / static_cast<float>(width - 1),
52 static_cast<float>(y) / static_cast<float>(height - 1)});
53 }
54 }
55 for (int y = 0; y < height - 1; ++y) {
56 for (int x = 0; x < width - 1; ++x) {
57 const std::uint32_t i00 = static_cast<std::uint32_t>(y * width + x);
58 const std::uint32_t i10 = i00 + 1U;
59 const std::uint32_t i01 = i00 + static_cast<std::uint32_t>(width);
60 const std::uint32_t i11 = i01 + 1U;
61 output.indices.insert(output.indices.end(), {i00, i01, i10, i10, i01, i11});
62 }
63 }
64}
65
66void addFlatTriangle(HeightmapArrays& output, float cellSize, float heightScale,
67 float textureWidth, float textureHeight, float ax, float ay, float ah,
68 float bx, float by, float bh, float cx, float cy, float ch) {
69 const float p0x = ax * cellSize, p0y = ah * heightScale, p0z = ay * cellSize;
70 const float p1x = bx * cellSize, p1y = bh * heightScale, p1z = by * cellSize;
71 const float p2x = cx * cellSize, p2y = ch * heightScale, p2z = cy * cellSize;
72 float nx = (p1y - p0y) * (p2z - p0z) - (p1z - p0z) * (p2y - p0y);
73 float ny = (p1z - p0z) * (p2x - p0x) - (p1x - p0x) * (p2z - p0z);
74 float nz = (p1x - p0x) * (p2y - p0y) - (p1y - p0y) * (p2x - p0x);
75 const float length = std::sqrt(nx * nx + ny * ny + nz * nz);
76 if (length > 1.0e-8F) {
77 nx /= length;
78 ny /= length;
79 nz /= length;
80 }
81 const std::uint32_t base = static_cast<std::uint32_t>(output.positions.size() / 3U);
82 output.positions.insert(output.positions.end(), {p0x, p0y, p0z, p1x, p1y, p1z, p2x, p2y, p2z});
83 output.normals.insert(output.normals.end(), {nx, ny, nz, nx, ny, nz, nx, ny, nz});
84 output.texcoords.insert(output.texcoords.end(),
85 {ax / textureWidth, ay / textureHeight, bx / textureWidth,
86 by / textureHeight, cx / textureWidth, cy / textureHeight});
87 output.indices.insert(output.indices.end(), {base, base + 1U, base + 2U});
88}
89
90void buildFlat(const procgen::Heightmap& heightmap, float cellSize, float heightScale,
91 HeightmapArrays& output) {
92 const int width = heightmap.getWidth();
93 const int height = heightmap.getHeight();
94 if (width < 2 || height < 2) return;
95 const float textureWidth = static_cast<float>(width - 1);
96 const float textureHeight = static_cast<float>(height - 1);
97 for (int y = 0; y < height - 1; ++y) {
98 for (int x = 0; x < width - 1; ++x) {
99 const float h00 = heightmap.height(x, y);
100 const float h10 = heightmap.height(x + 1, y);
101 const float h01 = heightmap.height(x, y + 1);
102 const float h11 = heightmap.height(x + 1, y + 1);
103 addFlatTriangle(output, cellSize, heightScale, textureWidth, textureHeight,
104 static_cast<float>(x), static_cast<float>(y), h00,
105 static_cast<float>(x), static_cast<float>(y + 1), h01,
106 static_cast<float>(x + 1), static_cast<float>(y), h10);
107 addFlatTriangle(output, cellSize, heightScale, textureWidth, textureHeight,
108 static_cast<float>(x + 1), static_cast<float>(y), h10,
109 static_cast<float>(x), static_cast<float>(y + 1), h01,
110 static_cast<float>(x + 1), static_cast<float>(y + 1), h11);
111 }
112 }
113}
114
115HeightmapArrays build(const procgen::Heightmap& heightmap, float cellSize, float heightScale,
116 bool smoothNormals) {
117 HeightmapArrays result;
118 if (smoothNormals)
119 buildSmooth(heightmap, cellSize, heightScale, result);
120 else
121 buildFlat(heightmap, cellSize, heightScale, result);
122 return result;
123}
124
125} // namespace
126
128 float heightScale, bool smoothNormals) {
129 auto* graphics = ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
130 if (!graphics || !heightmap)
131 return eve::editing::failed<graphics::Mesh*>(
132 editing::Status::Unsupported, editing::RuleId("procgen.preview.provider-absent"),
133 "Heightmap preview requires Graphics and a source heightmap");
134 HeightmapArrays arrays = build(*heightmap, cellSize, heightScale, smoothNormals);
135 if (arrays.indices.empty())
136 return eve::editing::failed<graphics::Mesh*>(
137 editing::Status::Rejected, editing::RuleId("procgen.preview.empty-heightmap"),
138 "Heightmap preview requires a valid grid and cell size");
139 auto* mesh = graphics->newMeshFromArrays(
140 arrays.positions.data(), arrays.normals.data(), arrays.texcoords.data(),
141 static_cast<int>(arrays.positions.size() / 3U), arrays.indices.data(),
142 static_cast<int>(arrays.indices.size()));
143 if (!mesh)
144 return eve::editing::failed<graphics::Mesh*>(
145 editing::Status::Failed, editing::RuleId("procgen.preview.mesh-create-failed"),
146 "Graphics rejected the heightmap preview mesh");
147 return eve::editing::applied<graphics::Mesh*>(mesh);
148}
149
151 procgen::Heightmap* heightmap, float cellSize,
152 float heightScale, bool smoothNormals) {
153 if (!mesh || !graphics || !heightmap)
154 return eve::editing::failed<void>(
155 editing::Status::Rejected, editing::RuleId("procgen.preview.invalid-update"),
156 "Heightmap preview update requires mesh, Graphics and heightmap");
157 HeightmapArrays arrays = build(*heightmap, cellSize, heightScale, smoothNormals);
158 if (arrays.indices.empty())
159 return eve::editing::failed<void>(
160 editing::Status::Rejected, editing::RuleId("procgen.preview.empty-heightmap"),
161 "Heightmap preview requires a valid grid and cell size");
162 if (!graphics->updateMeshVertices(mesh, arrays.positions.data(), arrays.normals.data(),
163 arrays.texcoords.data(),
164 static_cast<int>(arrays.positions.size() / 3U), nullptr, 0))
165 return eve::editing::failed<void>(
166 editing::Status::Failed, editing::RuleId("procgen.preview.mesh-update-failed"),
167 "Graphics rejected the heightmap preview update");
168 return eve::editing::applied<void>();
169}
170
171} // namespace eve::procgen_graphics_editing
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
std::string output
float cx
Definition CardTypes.cpp:33
float cy
Definition CardTypes.cpp:34
int ax
Definition CaveMesh.cpp:113
int ay
Definition CaveMesh.cpp:113
int bx
Definition CaveMesh.cpp:114
float length
Definition CaveMesh.cpp:94
int by
Definition CaveMesh.cpp:114
float nx
float nz
float ny
std::vector< std::uint32_t > indices
std::vector< float > texcoords
std::vector< float > normals
std::vector< float > positions
std::uint32_t height
std::uint32_t width
Mesh * mesh
Move-only operation result carrying either a value or Status.
Definition Result.h:155
UUID-backed identifier adapter for legacy textual boundaries.
Definition Identity.h:314
virtual bool updateMeshVertices(Mesh *mesh, const float *posXYZ, const float *nrmXYZ, const float *uvST, int vertexCount, const uint32_t *indices, int indexCount)=0
In-place update of a mesh's vertex/index data (CPU -> host-visible VBO). Mirrors bakeMeshMorph: the u...
GPU mesh handle (+ optional CPU morph targets).
Definition Mesh.h:25
In-memory terrain heightmap: a dense float grid (row-major, index = y * width + x) materialized from ...
Definition Heightmap.h:21
double sample(const Heightmap &map, double u, double v)
Sample.
editing::Result< graphics::Mesh * > createHeightmapMesh(procgen::Heightmap *heightmap, float cellSize, float heightScale, bool smoothNormals)
Build a heightmap preview mesh through the linked Graphics module.
editing::Result< void > updateHeightmapMesh(graphics::Mesh *mesh, graphics::Graphics *graphics, procgen::Heightmap *heightmap, float cellSize, float heightScale, bool smoothNormals)
Update preview vertices without replacing the mesh identity.