7#include <Poco/JSON/Array.h>
8#include <Poco/JSON/Object.h>
9#include <Poco/JSON/Parser.h>
10#include <Poco/JSON/Stringifier.h>
24constexpr float kPi = 3.14159265358979323846f;
26float degToRad(
float d) {
return d * kPi / 180.f; }
29std::string mcpStringify(
const Poco::Dynamic::Var&
v) {
30 std::ostringstream oss;
31 Poco::JSON::Stringifier::stringify(
v, oss, 0, 0);
35std::string writeTextFile(
const std::string& path,
const std::string& text) {
36 const std::filesystem::path
p(path);
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()));
43 return out.good() ? std::string() :
"failed writing: " + path;
57bool SceneInspect::ensureCamera() {
58 auto* cap = captureIface();
59 return cap && cap->ensureCamera();
63 std::vector<InspectView> out;
64 const float base = fov > 0.f ? fov : 60.f;
68 v.
name =
"along_road";
70 v.eye = center + glm::vec3(0.f, 1.8f, -6.f);
71 v.target = center + glm::vec3(0.f, 1.2f, 0.f);
79 v.eye = center + glm::vec3(0.f, 30.f, 0.f);
81 v.fovYDeg = std::min(base * 1.2f, 100.f);
86 v.
name =
"corner_close";
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);
97 v.eye = center + glm::vec3(0.f, 14.f, -22.f);
99 v.fovYDeg = std::max(base * 0.85f, 35.f);
107 auto* cap = captureIface();
108 if (!cap)
return false;
109 return cap->setCameraPoseYawPitch(
eye.x,
eye.y,
eye.z, rotYawPitch.x, rotYawPitch.y, fov);
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);
119 std::string root = std::filesystem::current_path().string();
121 if (
c ==
'\\')
c =
'/';
122 if (!root.empty() && root.back() ==
'/') root.pop_back();
123 return root +
"/eve_inspect_cache";
127 const std::vector<std::string>& buffers) {
129 auto* cap = captureIface();
131 result.
error =
"Graphics module not available";
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;
144 if (!wantColor) wantColor =
true;
147 cap->setReadbackEnabled(
true);
149 std::string
dir = outDir;
155 if (
c ==
'\\')
c =
'/';
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";
166 if (!cap->savePng(pngPath, &result.
width, &result.
height, &err)) {
172 if (
const std::string werr = writeTextFile(jsonPath, geoJson); !werr.empty()) {
177 const auto pos = geoJson.find(
"\"count\":");
178 if (
pos != std::string::npos) result.
entityCount = std::atoi(geoJson.c_str() +
pos + 9);
182 if (cap->gbufferPng(
"depth", depthPngPath, &berr))
189 if (cap->gbufferPng(
"normal", normalPngPath, &berr))
194 if (wantShadow) result.
unsupported.push_back(
"shadow");
199 const std::string idJson = cap->entityIdMaskJson(&iw, &ih, &
ok);
204 if (cap->entityIdMaskPng(idPngPath, &perr)) result.
idPngPath = idPngPath;
205 if (writeTextFile(idJsonPath, idJson).empty()) result.
idJsonPath = idJsonPath;
212 lastPngPath_ = pngPath;
213 lastJsonPath_ = jsonPath;
218 auto* cap = captureIface();
219 return cap ? cap->cameraPoseJson() :
"{\"error\":\"Graphics module not available\"}";
224 auto* cap = captureIface();
225 if (!cap)
return "{\"error\":\"Graphics module not available\"}";
228 return cap->visibleEntitiesJsonAt(
eye->x,
eye->y,
eye->z, target->x, target->y, target->z, fov, &
ok);
229 return cap->visibleEntitiesJson(fov, &
ok);
Frame capture + camera + visible-entity inspection (graphics).
Scene graph query/mutation surface (provided by the scene module).
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 ¢er, float fov=60.f)
围绕 center 自动生成一组标准化巡检机位:
WidgetDesc text(std::string content, std::string id)
Static text label.
一次原子快照的结果:PNG 渲染帧 + 配套几何 JSON。
std::string normalPngPath
std::vector< std::string > unsupported