载入中...
搜索中...
未找到
SceneInspect.cpp
浏览该文件的文档.
2
3#include "common/Capability.h"
5#include "common/SceneQuery.h"
6
7#include <Poco/JSON/Array.h>
8#include <Poco/JSON/Object.h>
9#include <Poco/JSON/Parser.h>
10#include <Poco/JSON/Stringifier.h>
11
12#include <algorithm>
13#include <cmath>
14#include <cstdio>
15#include <filesystem>
16#include <fstream>
17#include <sstream>
18#include <string>
19#include <vector>
20
21namespace eve::dev {
22namespace {
23
24constexpr float kPi = 3.14159265358979323846f;
25
26float degToRad(float d) { return d * kPi / 180.f; }
27
29std::string mcpStringify(const Poco::Dynamic::Var& v) {
30 std::ostringstream oss;
31 Poco::JSON::Stringifier::stringify(v, oss, 0, 0);
32 return oss.str();
33}
34
35std::string writeTextFile(const std::string& path, const std::string& text) {
36 const std::filesystem::path p(path);
37 std::error_code ec;
38 std::filesystem::create_directories(p.parent_path(), ec);
39 std::ofstream out(p, std::ios::binary);
40 if (!out.good()) return "cannot open output file: " + path;
41 out.write(text.data(), static_cast<std::streamsize>(text.size()));
42 out.flush();
43 return out.good() ? std::string() : "failed writing: " + path;
44}
45
46} // namespace
47
49 static SceneInspect inst;
50 return inst;
51}
52
53eve::IRenderCapture* SceneInspect::captureIface() { return eve::cap::query<eve::IRenderCapture>(); }
54
55eve::ISceneQuery* SceneInspect::scene() { return eve::cap::query<eve::ISceneQuery>(); }
56
57bool SceneInspect::ensureCamera() {
58 auto* cap = captureIface();
59 return cap && cap->ensureCamera();
60}
61
62std::vector<InspectView> SceneInspect::generateViews(const glm::vec3& center, float fov) {
63 std::vector<InspectView> out;
64 const float base = fov > 0.f ? fov : 60.f;
65
66 {
68 v.name = "along_road";
69 v.kind = "沿路平视";
70 v.eye = center + glm::vec3(0.f, 1.8f, -6.f);
71 v.target = center + glm::vec3(0.f, 1.2f, 0.f);
72 v.fovYDeg = base;
73 out.push_back(v);
74 }
75 {
77 v.name = "bird_eye";
78 v.kind = "高空俯拍";
79 v.eye = center + glm::vec3(0.f, 30.f, 0.f);
80 v.target = center;
81 v.fovYDeg = std::min(base * 1.2f, 100.f);
82 out.push_back(v);
83 }
84 {
86 v.name = "corner_close";
87 v.kind = "拐角特写";
88 v.eye = center + glm::vec3(2.4f, 1.2f, 2.4f);
89 v.target = center + glm::vec3(0.f, 0.8f, 0.f);
90 v.fovYDeg = std::max(base * 0.8f, 25.f);
91 out.push_back(v);
92 }
93 {
95 v.name = "vista";
96 v.kind = "远景视角";
97 v.eye = center + glm::vec3(0.f, 14.f, -22.f);
98 v.target = center;
99 v.fovYDeg = std::max(base * 0.85f, 35.f);
100 out.push_back(v);
101 }
102 return out;
103}
104
105bool SceneInspect::setCameraPose(const glm::vec3& eye, const glm::vec3& rotYawPitch,
106 float fov) {
107 auto* cap = captureIface();
108 if (!cap) return false;
109 return cap->setCameraPoseYawPitch(eye.x, eye.y, eye.z, rotYawPitch.x, rotYawPitch.y, fov);
110}
111
113 auto* cap = captureIface();
114 if (!cap) return false;
115 return cap->setCameraPose(v.eye.x, v.eye.y, v.eye.z, v.target.x, v.target.y, v.target.z, v.fovYDeg);
116}
117
118std::string SceneInspect::defaultCacheDir() const {
119 std::string root = std::filesystem::current_path().string();
120 for (char& c : root)
121 if (c == '\\') c = '/';
122 if (!root.empty() && root.back() == '/') root.pop_back();
123 return root + "/eve_inspect_cache";
124}
125
126InspectCapture SceneInspect::capture(const std::string& outDir, const std::string& tag,
127 const std::vector<std::string>& buffers) {
128 InspectCapture result;
129 auto* cap = captureIface();
130 if (!cap) {
131 result.error = "Graphics module not available";
132 return result;
133 }
134
135 bool wantColor = buffers.empty();
136 bool wantDepth = false, wantNormal = false, wantId = false, wantShadow = false;
137 for (const auto& b : buffers) {
138 if (b == "color") wantColor = true;
139 else if (b == "depth") wantDepth = true;
140 else if (b == "normal") wantNormal = true;
141 else if (b == "id") wantId = true;
142 else if (b == "shadow") wantShadow = true;
143 }
144 if (!wantColor) wantColor = true;
145
146 ensureCamera();
147 cap->setReadbackEnabled(true);
148
149 std::string dir = outDir;
150 if (dir.empty()) {
151 dir = cacheDir();
152 if (dir.empty()) dir = defaultCacheDir();
153 }
154 for (char& c : dir)
155 if (c == '\\') c = '/';
156
157 const std::string safeTag = tag.empty() ? "frame" : tag;
158 const std::string pngPath = dir + "/" + safeTag + ".png";
159 const std::string jsonPath = dir + "/" + safeTag + ".json";
160 const std::string depthPngPath = dir + "/" + safeTag + "_depth.png";
161 const std::string normalPngPath = dir + "/" + safeTag + "_normal.png";
162 const std::string idPngPath = dir + "/" + safeTag + "_id.png";
163 const std::string idJsonPath = dir + "/" + safeTag + "_id.json";
164
165 std::string err;
166 if (!cap->savePng(pngPath, &result.width, &result.height, &err)) {
167 result.error = err;
168 return result;
169 }
170
171 const std::string geoJson = visibleEntitiesJson();
172 if (const std::string werr = writeTextFile(jsonPath, geoJson); !werr.empty()) {
173 result.error = werr;
174 return result;
175 }
176 result.entityCount = 0;
177 const auto pos = geoJson.find("\"count\":");
178 if (pos != std::string::npos) result.entityCount = std::atoi(geoJson.c_str() + pos + 9);
179
180 if (wantDepth) {
181 std::string berr;
182 if (cap->gbufferPng("depth", depthPngPath, &berr))
183 result.depthPngPath = depthPngPath;
184 else
185 result.unsupported.push_back("depth");
186 }
187 if (wantNormal) {
188 std::string berr;
189 if (cap->gbufferPng("normal", normalPngPath, &berr))
190 result.normalPngPath = normalPngPath;
191 else
192 result.unsupported.push_back("normal");
193 }
194 if (wantShadow) result.unsupported.push_back("shadow");
195
196 if (wantId) {
197 int iw = 0, ih = 0;
198 bool ok = false;
199 const std::string idJson = cap->entityIdMaskJson(&iw, &ih, &ok);
200 if (!ok) {
201 result.unsupported.push_back("id");
202 } else {
203 std::string perr;
204 if (cap->entityIdMaskPng(idPngPath, &perr)) result.idPngPath = idPngPath;
205 if (writeTextFile(idJsonPath, idJson).empty()) result.idJsonPath = idJsonPath;
206 }
207 }
208
209 result.ok = true;
210 result.pngPath = pngPath;
211 result.jsonPath = jsonPath;
212 lastPngPath_ = pngPath;
213 lastJsonPath_ = jsonPath;
214 return result;
215}
216
218 auto* cap = captureIface();
219 return cap ? cap->cameraPoseJson() : "{\"error\":\"Graphics module not available\"}";
220}
221
222std::string SceneInspect::visibleEntitiesJson(const glm::vec3* eye, const glm::vec3* target,
223 float fov) {
224 auto* cap = captureIface();
225 if (!cap) return "{\"error\":\"Graphics module not available\"}";
226 bool ok = false;
227 if (eye && target)
228 return cap->visibleEntitiesJsonAt(eye->x, eye->y, eye->z, target->x, target->y, target->z, fov, &ok);
229 return cap->visibleEntitiesJson(fov, &ok);
230}
231
232} // namespace eve::dev
uint32_t b
uint32_t c
glm::vec3 eye
glm::vec4 p[6]
int d
int v
V3 dir
Definition TreeMesh.cpp:121
Frame capture + camera + visible-entity inspection (graphics).
Scene graph query/mutation surface (provided by the scene module).
Definition SceneQuery.h:30
std::string currentPoseJson()
当前激活相机位姿 JSON(eye/target/fov/viewport)。
const std::string & cacheDir() const
std::string defaultCacheDir() const
默认缓存目录:<gameRoot>/eve_inspect_cache。
std::string visibleEntitiesJson(const glm::vec3 *eye=nullptr, const glm::vec3 *target=nullptr, float fov=0.f)
生成当前视锥内可见实体的结构化 JSON: { camera, viewport, entities:[ { id, asset, world_aabb:{min,...
InspectCapture capture(const std::string &outDir={}, const std::string &tag="frame", const std::vector< std::string > &buffers={})
锁定当前相机 → 捕获渲染帧 PNG → 立刻导出配套可见实体几何 JSON。 两者共享同一相机位姿,杜绝图片与实体数据错位。 outDir 为空时使用缓存目录。返回文件路径与图像尺寸。 buffers...
bool setCameraView(const InspectView &v)
static SceneInspect & instance()
bool setCameraPose(const glm::vec3 &eye, const glm::vec3 &rotYawPitch, float fov=0.f)
以 pos + 欧拉角 rot 设置相机位姿。 rot = [yawDeg, pitchDeg](与 firstperson 约定一致,Y-up)。 fov <= 0 时保持当前 FOV。
static std::vector< InspectView > generateViews(const glm::vec3 &center, float fov=60.f)
围绕 center 自动生成一组标准化巡检机位:
I * query()
Definition Capability.h:77
WidgetDesc text(std::string content, std::string id)
Static text label.
Definition Widget.cpp:235
一次原子快照的结果:PNG 渲染帧 + 配套几何 JSON。
std::vector< std::string > unsupported
场景巡检工具集(MCP 底层数据底座)。