载入中...
搜索中...
未找到
SkyscraperMesh.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5#include <cstdint>
6#include <string>
7#include <vector>
8
9namespace eve::procgen {
10namespace {
11
12struct Vec3 {
13 float x = 0.f, y = 0.f, z = 0.f;
14};
15
16Vec3 sub(Vec3 a, Vec3 b) { return {a.x - b.x, a.y - b.y, a.z - b.z}; }
17Vec3 cross(Vec3 a, Vec3 b) {
18 return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
19}
20Vec3 addScaled(Vec3 p, Vec3 n, float s) { return {p.x + n.x * s, p.y + n.y * s, p.z + n.z * s}; }
21
22Vec3 normalize(Vec3 v) {
23 const float len = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
24 if (len <= 1e-8f) return {0.f, 1.f, 0.f};
25 return {v.x / len, v.y / len, v.z / len};
26}
27
28// Bilinear interpolation of a rectangular face from its four corners.
29// p0 bottom-left, p1 bottom-right, p2 top-right, p3 top-left.
30Vec3 lerpFace(Vec3 p0, Vec3 p1, Vec3 p2, Vec3 p3, float u, float v) {
31 const float w = u;
32 Vec3 base = {p0.x + (p1.x - p0.x) * w, p0.y + (p1.y - p0.y) * w, p0.z + (p1.z - p0.z) * w};
33 Vec3 top = {p3.x + (p2.x - p3.x) * w, p3.y + (p2.y - p3.y) * w, p3.z + (p2.z - p3.z) * w};
34 return {base.x + (top.x - base.x) * v, base.y + (top.y - base.y) * v,
35 base.z + (top.z - base.z) * v};
36}
37
38// Emit a quad given four corners and its desired outward normal. Winding is corrected so the
39// geometric normal (cross of the first triangle) agrees with n.
40void addQuad(MeshBuild &out, Vec3 p0, Vec3 p1, Vec3 p2, Vec3 p3, Vec3 n, float u, float v) {
41 const Vec3 winding = cross(sub(p1, p0), sub(p3, p0));
42 const float d = winding.x * n.x + winding.y * n.y + winding.z * n.z;
43 if (d < 0.f) {
44 const Vec3 tmp = p1;
45 p1 = p3;
46 p3 = tmp;
47 }
48 const uint32_t base = uint32_t(out.getVertexCount());
49 out.addVertex(p0.x, p0.y, p0.z, n.x, n.y, n.z, u, v);
50 out.addVertex(p1.x, p1.y, p1.z, n.x, n.y, n.z, u, v);
51 out.addVertex(p2.x, p2.y, p2.z, n.x, n.y, n.z, u, v);
52 out.addVertex(p3.x, p3.y, p3.z, n.x, n.y, n.z, u, v);
53 out.addTriangle(base, base + 1, base + 2);
54 out.addTriangle(base, base + 2, base + 3);
55}
56
57// Add one facade (a rectangular wall) plus a grid of raised window quads.
58// Face corners are in CCW order from outside; n is the outward normal.
59void addFacade(MeshBuild &out, Vec3 p0, Vec3 p1, Vec3 p2, Vec3 p3, Vec3 n, int cols, int rows,
60 float windowDepth) {
61 addQuad(out, p0, p1, p2, p3, n, 0.25f, 0.5f);
62 const float margin = 0.12f;
63 for (int r = 0; r < rows; ++r) {
64 const float v0 = float(r) / float(rows);
65 const float v1 = float(r + 1) / float(rows);
66 const float vi0 = v0 + margin * (v1 - v0);
67 const float vi1 = v1 - margin * (v1 - v0);
68 for (int c = 0; c < cols; ++c) {
69 const float u0 = float(c) / float(cols);
70 const float u1 = float(c + 1) / float(cols);
71 const float ui0 = u0 + margin * (u1 - u0);
72 const float ui1 = u1 - margin * (u1 - u0);
73 const Vec3 w0 = addScaled(lerpFace(p0, p1, p2, p3, ui0, vi0), n, windowDepth);
74 const Vec3 w1 = addScaled(lerpFace(p0, p1, p2, p3, ui1, vi0), n, windowDepth);
75 const Vec3 w2 = addScaled(lerpFace(p0, p1, p2, p3, ui1, vi1), n, windowDepth);
76 const Vec3 w3 = addScaled(lerpFace(p0, p1, p2, p3, ui0, vi1), n, windowDepth);
77 addQuad(out, w0, w1, w2, w3, n, 0.75f, 0.5f);
78 }
79 }
80}
81
82// A solid box (without window grid) centered on cx/cz: four sides + optional top cap.
83void addBox(MeshBuild &out, float cx, float cz, float hw, float hd, float y0, float y1,
84 bool top) {
85 const Vec3 p000 = {cx - hw, y0, cz - hd};
86 const Vec3 p100 = {cx + hw, y0, cz - hd};
87 const Vec3 p110 = {cx + hw, y0, cz + hd};
88 const Vec3 p010 = {cx - hw, y0, cz + hd};
89 const Vec3 p001 = {cx - hw, y1, cz - hd};
90 const Vec3 p101 = {cx + hw, y1, cz - hd};
91 const Vec3 p111 = {cx + hw, y1, cz + hd};
92 const Vec3 p011 = {cx - hw, y1, cz + hd};
93 addQuad(out, p000, p100, p101, p001, {0, 0, 1}, 0.25f, 0.5f); // +Z
94 addQuad(out, p110, p010, p011, p111, {0, 0, -1}, 0.25f, 0.5f); // -Z
95 addQuad(out, p100, p110, p111, p101, {1, 0, 0}, 0.25f, 0.5f); // +X
96 addQuad(out, p010, p000, p001, p011, {-1, 0, 0}, 0.25f, 0.5f); // -X
97 if (top) addQuad(out, p001, p101, p111, p011, {0, 1, 0}, 0.25f, 0.5f);
98}
99
100} // namespace
101
102bool generateSkyscraperMesh(const Params &params, MeshBuild &out, std::string &error) {
103 const int tiers = std::clamp(params.getInt("tiers", 5), 1, 24);
104 const float baseWidth = std::max(0.5f, params.getFloat("baseWidth", 10.f));
105 const float baseDepth = std::max(0.5f, params.getFloat("baseDepth", 10.f));
106 const float tierHeight = std::max(0.5f, params.getFloat("tierHeight", 6.f));
107 const float setback = std::clamp(params.getFloat("setback", 0.08f), 0.f, 0.6f);
108 const int windowCols = std::clamp(params.getInt("windowCols", 6), 1, 24);
109 const int windowRows = std::clamp(params.getInt("windowRows", 4), 1, 24);
110 const float windowDepth = std::max(0.f, params.getFloat("windowDepth", 0.04f));
111 const float spireHeight = std::max(0.f, params.getFloat("spireHeight", 0.f));
112
113 out.clear();
114 const float cx = 0.f, cz = 0.f;
115 float yCursor = 0.f;
116
117 for (int t = 0; t < tiers; ++t) {
118 const float shrink = 1.f - setback * float(t);
119 const float hw = baseWidth * 0.5f * shrink;
120 const float hd = baseDepth * 0.5f * shrink;
121 const float y0 = yCursor;
122 const float y1 = yCursor + tierHeight;
123
124 const Vec3 p000 = {cx - hw, y0, cz - hd};
125 const Vec3 p100 = {cx + hw, y0, cz - hd};
126 const Vec3 p110 = {cx + hw, y0, cz + hd};
127 const Vec3 p010 = {cx - hw, y0, cz + hd};
128 const Vec3 p001 = {cx - hw, y1, cz - hd};
129 const Vec3 p101 = {cx + hw, y1, cz - hd};
130 const Vec3 p111 = {cx + hw, y1, cz + hd};
131 const Vec3 p011 = {cx - hw, y1, cz + hd};
132
133 addFacade(out, p000, p100, p101, p001, {0, 0, 1}, windowCols, windowRows, windowDepth);
134 addFacade(out, p110, p010, p011, p111, {0, 0, -1}, windowCols, windowRows, windowDepth);
135 addFacade(out, p100, p110, p111, p101, {1, 0, 0}, windowCols, windowRows, windowDepth);
136 addFacade(out, p010, p000, p001, p011, {-1, 0, 0}, windowCols, windowRows, windowDepth);
137 yCursor = y1;
138 }
139
140 // Roof cap on the top tier.
141 {
142 const float shrink = 1.f - setback * float(tiers - 1);
143 const float hw = baseWidth * 0.5f * shrink;
144 const float hd = baseDepth * 0.5f * shrink;
145 const float y1 = yCursor;
146 addQuad(out, {cx - hw, y1, cz - hd}, {cx + hw, y1, cz - hd}, {cx + hw, y1, cz + hd},
147 {cx - hw, y1, cz + hd}, {0, 1, 0}, 0.25f, 0.5f);
148 }
149
150 if (spireHeight > 0.f) {
151 const float s = std::min(baseWidth, baseDepth) * 0.045f;
152 addBox(out, cx, cz, s, s, yCursor, yCursor + spireHeight, true);
153 }
154
155 if (out.empty()) {
156 error = "mesh.skyscraper: generated an empty mesh";
157 return false;
158 }
159 out.setMeta("algorithm", "mesh.skyscraper");
160 out.setMeta("tiers", std::to_string(tiers));
161 out.setMeta("windowCols", std::to_string(windowCols));
162 out.setMeta("windowRows", std::to_string(windowRows));
163 out.setMeta("spireHeight", std::to_string(spireHeight));
164 out.setMeta("height", std::to_string(float(tiers) * tierHeight + spireHeight));
165 return true;
166}
167
168} // namespace eve::procgen
float cx
Definition CardTypes.cpp:31
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
float u
Definition Grass.cpp:234
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int w
std::string error
uint32_t a
uint32_t b
uint32_t c
glm::vec4 p[6]
int d
int v
int margin
uint32_t s
Definition Weather.cpp:28
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:14
void setMeta(const std::string &key, const std::string &value)
Definition MeshBuild.cpp:81
Generation parameters. Algorithm-specific keys live in values as strings (no overloads; typed setters...
Definition Params.h:13
float getFloat(const std::string &key, float defaultValue) const
Definition Params.cpp:32
int getInt(const std::string &key, int defaultValue) const
Definition Params.cpp:23
bool generateSkyscraperMesh(const Params &params, MeshBuild &out, std::string &error)
Build a deterministic procedural skyscraper. Registered as the mesh.skyscraper recipe.