载入中...
搜索中...
未找到
VirtualGeometryRenderer.cpp
浏览该文件的文档.
3
4#include "common/Exception.h"
5#include "data/ByteData.h"
6
7#include <algorithm>
8#include <array>
9#include <cmath>
10#include <cstdint>
11#include <vector>
12
13namespace eve::virtualgeometry {
14namespace {
15
16// Minimal column-major mat4 helpers (GLM is not linked into this module).
17struct Mat4 {
18 float m[16];
19 static Mat4 identity() {
20 Mat4 r{};
21 r.m[0] = r.m[5] = r.m[10] = r.m[15] = 1.f;
22 return r;
23 }
24 static Mat4 mul(const Mat4 &a, const Mat4 &b) {
25 Mat4 r{};
26 for (int c = 0; c < 4; ++c)
27 for (int row = 0; row < 4; ++row) {
28 float sum = 0;
29 for (int k = 0; k < 4; ++k) sum += a.m[k * 4 + row] * b.m[c * 4 + k];
30 r.m[c * 4 + row] = sum;
31 }
32 return r;
33 }
34};
35
36} // namespace
37
39
41
44 bool ok = builder.build(in, builderOptions_, asset_);
45 if (!ok) return false;
46 vgReset(backend_, visibleCapacity_); // size visible/stats before upload
47 vgUpload(backend_, asset_);
48 return true;
49}
50
51bool VirtualGeometryRenderer::build(const float *positions, int vertexCount,
52 const std::uint32_t *indices, int indexCount) {
54 in.vertexCount = vertexCount;
55 in.positions = positions;
56 in.indices = indices;
57 in.indexCount = indexCount;
58 return build(in);
59}
60
61namespace {
62// Build a unit icosphere (triangulated) into CPU buffers.
63void buildIco(std::vector<float> &positions, std::vector<std::uint32_t> &indices, int subdiv) {
64 positions.clear();
65 indices.clear();
66 struct F { int a, b, c; };
67 auto addVtx = [&](float x, float y, float z) {
68 float l = std::sqrt(x * x + y * y + z * z);
69 positions.push_back(x / l);
70 positions.push_back(y / l);
71 positions.push_back(z / l);
72 return static_cast<int>(positions.size() / 3) - 1;
73 };
74 auto tri = [&](int a, int b, int c) {
75 indices.push_back(static_cast<std::uint32_t>(a));
76 indices.push_back(static_cast<std::uint32_t>(b));
77 indices.push_back(static_cast<std::uint32_t>(c));
78 };
79 auto mid = [&](int i0, int i1) {
80 return addVtx(0.5f * (positions[3 * i0] + positions[3 * i1]),
81 0.5f * (positions[3 * i0 + 1] + positions[3 * i1 + 1]),
82 0.5f * (positions[3 * i0 + 2] + positions[3 * i1 + 2]));
83 };
84 const float t = (1.f + std::sqrt(5.f)) * 0.5f;
85 std::vector<std::array<float, 3>> base = {
86 {-1, t, 0}, {1, t, 0}, {-1, -t, 0}, {1, -t, 0}, {0, -1, t}, {0, 1, t},
87 {0, -1, -t}, {0, 1, -t}, {t, 0, -1}, {t, 0, 1}, {-t, 0, -1}, {-t, 0, 1}};
88 int idx[12];
89 for (int i = 0; i < 12; ++i) idx[i] = addVtx(base[i][0], base[i][1], base[i][2]);
90 int faces[20][3] = {{0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11},
91 {1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8},
92 {3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9},
93 {4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1}};
94 std::vector<F> cur;
95 for (auto &f : faces) cur.push_back({idx[f[0]], idx[f[1]], idx[f[2]]});
96 for (int d = 0; d < subdiv; ++d) {
97 std::vector<F> nf;
98 for (auto &x : cur) {
99 int ab = mid(x.a, x.b), ac = mid(x.a, x.c), bc = mid(x.b, x.c);
100 nf.push_back({x.a, ab, ac});
101 nf.push_back({ab, x.b, bc});
102 nf.push_back({ac, bc, x.c});
103 nf.push_back({ab, bc, ac});
104 }
105 cur.swap(nf);
106 }
107 for (auto &x : cur) tri(x.a, x.b, x.c);
108}
109} // namespace
110
112 std::vector<float> pos;
113 std::vector<std::uint32_t> idx;
114 buildIco(pos, idx, std::clamp(subdiv, 1, 6));
115 return build(pos.data(), static_cast<int>(pos.size() / 3), idx.data(),
116 static_cast<int>(idx.size()));
117}
118
119void VirtualGeometryRenderer::setViewport(int width, int height, float fovYDeg, float errorPx) {
120 width_ = std::max(1, width);
121 height_ = std::max(1, height);
122 uniforms_.params[0] = static_cast<float>(width_);
123 uniforms_.params[1] = static_cast<float>(height_);
124 uniforms_.params[2] = static_cast<float>(height_) /
125 (2.f * std::tan(fovYDeg * 3.14159265358979323846f / 360.f));
126 uniforms_.params[3] = errorPx;
127}
128
129void VirtualGeometryRenderer::setCamera(const float view[16], const float proj[16],
130 const float model[16], const float camPos[3]) {
131 // Combined view-projection: clip = P * V * model * pos. The shader uses
132 // vgU.viewProj * (vgU.model * pos), so viewProj = P * V.
133 Mat4 p;
134 for (int i = 0; i < 16; ++i) p.m[i] = proj[i];
135 Mat4 v;
136 for (int i = 0; i < 16; ++i) v.m[i] = view[i];
137 Mat4 vp = Mat4::mul(p, v);
138 for (int i = 0; i < 16; ++i) uniforms_.viewProj[i] = vp.m[i];
139 for (int i = 0; i < 16; ++i) uniforms_.model[i] = model ? model[i] : Mat4::identity().m[i];
140 uniforms_.cameraPos[0] = camPos[0];
141 uniforms_.cameraPos[1] = camPos[1];
142 uniforms_.cameraPos[2] = camPos[2];
143 uniforms_.cameraPos[3] = 0.f;
144 updateUniforms();
145}
146
147void VirtualGeometryRenderer::setCameraSimple(float camX, float camY, float camZ, float nearZ,
148 float farZ) {
149 const float fovY = (uniforms_.params[2] > 0.f)
150 ? 2.f * std::atan(static_cast<float>(height_) / (2.f * uniforms_.params[2]))
151 : 60.f * 3.14159265358979323846f / 180.f;
152 // Identity view (looking down -Z).
153 Mat4 view = Mat4::identity();
154 // Perspective projection (column-major, D3D/Vulkan clip z in [0,1]).
155 Mat4 proj{};
156 const float a = 1.f / std::tan(fovY * 0.5f);
157 const float aspect = static_cast<float>(width_) / static_cast<float>(height_);
158 proj.m[0] = a / aspect;
159 proj.m[5] = a;
160 proj.m[10] = farZ / (nearZ - farZ);
161 proj.m[11] = -1.f;
162 proj.m[14] = (nearZ * farZ) / (nearZ - farZ);
163 const float camPos[3] = {camX, camY, camZ};
164 setCamera(view.m, proj.m, nullptr, camPos);
165}
166
167void VirtualGeometryRenderer::setModelYaw(float yaw) { modelYaw_ = yaw; }
168
169void VirtualGeometryRenderer::updateUniforms() {
170 uniforms_.misc[0] = static_cast<float>(static_cast<int>(asset_.clusters.size()));
171 if (modelYaw_ != 0.f) {
172 // Build a Y-rotation model matrix (column-major) and override.
173 float c = std::cos(modelYaw_), s = std::sin(modelYaw_);
174 Mat4 r = Mat4::identity();
175 r.m[0] = c; r.m[2] = s;
176 r.m[8] = -s; r.m[10] = c;
177 for (int i = 0; i < 16; ++i) uniforms_.model[i] = r.m[i];
178 }
179 // Recompute per-cluster screen-space error constants (errorR * projScale).
180 for (auto &c : asset_.clusters) c.errorRScreen = c.errorR * uniforms_.params[2];
181 vgUploadUniforms(backend_, uniforms_);
182}
183
185 int clusters = static_cast<int>(asset_.clusters.size());
186 if (clusters <= 0 || !backend_.state) return 0;
187 lastVisible_ = vgUpdate(backend_, clusters, visibleCapacity_, width_, height_);
188 return lastVisible_;
189}
190
191bool VirtualGeometryRenderer::resolve(unsigned char *outRgba, int &outW, int &outH) {
192 std::vector<std::uint32_t> pix;
193 if (!vgReadPixels(backend_, pix)) return false;
194 outW = width_;
195 outH = height_;
196 const int n = outW * outH;
197 for (int i = 0; i < n; ++i) {
198 std::uint32_t packed = pix[i];
199 std::uint32_t depth = packed >> 16;
200 std::uint32_t cid = packed & 0xFFFFu;
201 if (cid == 0u && depth == 0xFFFFu) {
202 outRgba[4 * i + 0] = 4;
203 outRgba[4 * i + 1] = 6;
204 outRgba[4 * i + 2] = 12;
205 outRgba[4 * i + 3] = 255;
206 continue;
207 }
208 // Stable per-cluster color hash.
209 std::uint32_t h = cid * 2654435761u;
210 float cr = (h >> 16) & 0xFFu, cg = (h >> 8) & 0xFFu, cb = h & 0xFFu;
211 float mx = std::max({cr, cg, cb, 1.f});
212 float depthF = static_cast<float>(depth) / 65535.f;
213 float shade = 0.35f + 0.65f * (1.f - depthF);
214 outRgba[4 * i + 0] = static_cast<unsigned char>(cr / mx * 255.f * shade);
215 outRgba[4 * i + 1] = static_cast<unsigned char>(cg / mx * 255.f * shade);
216 outRgba[4 * i + 2] = static_cast<unsigned char>(cb / mx * 255.f * shade);
217 outRgba[4 * i + 3] = 255;
218 }
219 return true;
220}
221
223 int w = 1, h = 1;
224 auto *bd = new eve::data::ByteData(static_cast<std::size_t>(width_) * height_ * 4);
225 if (!bd) return nullptr;
226 if (!resolve(static_cast<unsigned char *>(bd->getData()), w, h)) {
227 delete bd;
228 return nullptr;
229 }
230 return bd;
231}
232
234 return static_cast<int>(asset_.clusters.size());
235}
236
240
241int VirtualGeometryRenderer::getLodLevel(int clusterId) const {
242 if (clusterId < 0 || static_cast<std::size_t>(clusterId) >= asset_.clusters.size()) return -1;
243 return static_cast<int>(asset_.clusters[clusterId].lodLevel);
244}
245
247 int m = 0;
248 for (const auto &c : asset_.clusters) m = std::max(m, static_cast<int>(c.lodLevel));
249 return m;
250}
251
252} // namespace eve::virtualgeometry
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
uint32_t i1
Definition Grass.cpp:62
uint32_t i0
Definition Grass.cpp:62
float height
Definition Grass.cpp:235
float u
Definition Grass.cpp:234
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int h
int w
float depth
uint32_t a
uint32_t b
uint32_t c
int width
int idx
float f
glm::vec4 p[6]
glm::mat4 view
glm::mat4 model
glm::mat4 proj
int d
int v
float m[16]
uint32_t s
Definition Weather.cpp:28
In-memory byte buffer implementing eve::Data (ref-counted).
Definition ByteData.h:11
CPU preprocessor that builds a Nanite-style hierarchical cluster DAG from a triangle mesh:
Definition Builder.h:21
bool build(const MeshInput &in, const Options &opt, VirtualGeometryAsset &out)
Returns false on empty/invalid input.
Definition Builder.cpp:337
bool buildIcosphere(int subdiv)
Convenience: procedural unit icosphere, subdiv subdivision levels.
void setViewport(int width, int height, float fovYDeg, float errorPx=1.0f)
int update()
Run cull + raster; returns the number of visible clusters.
void setModelYaw(float yaw)
Spin the virtualized model about Y by yaw radians each frame.
void setCameraSimple(float camX, float camY, float camZ, float nearZ=0.1f, float farZ=100.f)
Script-friendly: identity view (camera looking down -Z) + perspective.
void setCamera(const float view[16], const float proj[16], const float model[16], const float camPos[3])
bool build(const float *positions, int vertexCount, const std::uint32_t *indices, int indexCount)
bool resolve(unsigned char *outRgba, int &outW, int &outH)
eve::data::ByteData * resolveByteData()
Resolve into a heap ByteData (RGBA) for scripting/display.
WidgetDesc row(std::vector< WidgetDesc > children, std::string id)
Horizontal elastic layout row.
Definition Widget.cpp:431
void vgReset(VgBackend &be, int visibleCapacity)
int vgUpdate(VgBackend &be, int clusterCount, int visibleCapacity, int viewW, int viewH)
void vgUploadUniforms(VgBackend &be, const VgUniforms &u)
bool vgReadPixels(VgBackend &be, std::vector< uint32_t > &out)
void vgCreate(VgBackend &be)
void vgDestroy(VgBackend &be)
void vgUpload(VgBackend &be, const VirtualGeometryAsset &asset)