载入中...
搜索中...
未找到
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
24std::string writeTextFile(const std::string& path, const std::string& text) {
25 const std::filesystem::path p(path);
26 std::error_code ec;
27 std::filesystem::create_directories(p.parent_path(), ec);
28 std::ofstream out(p, std::ios::binary);
29 if (!out.good()) return "cannot open output file: " + path;
30 out.write(text.data(), static_cast<std::streamsize>(text.size()));
31 out.flush();
32 return out.good() ? std::string() : "failed writing: " + path;
33}
34
35} // namespace
36
38 static SceneInspect inst;
39 return inst;
40}
41
42eve::IRenderCapture* SceneInspect::captureIface() { return eve::cap::query<eve::IRenderCapture>(); }
43
44eve::ISceneQuery* SceneInspect::scene() { return eve::cap::query<eve::ISceneQuery>(); }
45
46bool SceneInspect::ensureCamera() {
47 auto* cap = captureIface();
48 return cap && cap->ensureCamera();
49}
50
51std::vector<InspectView> SceneInspect::generateViews(const glm::vec3& center, float fov) {
52 std::vector<InspectView> out;
53 const float base = fov > 0.f ? fov : 60.f;
54
55 {
57 v.name = "along_road";
58 v.kind = "沿路平视";
59 v.eye = center + glm::vec3(0.f, 1.8f, -6.f);
60 v.target = center + glm::vec3(0.f, 1.2f, 0.f);
61 v.fovYDeg = base;
62 out.push_back(v);
63 }
64 {
66 v.name = "bird_eye";
67 v.kind = "高空俯拍";
68 v.eye = center + glm::vec3(0.f, 30.f, 0.f);
69 v.target = center;
70 v.fovYDeg = std::min(base * 1.2f, 100.f);
71 out.push_back(v);
72 }
73 {
75 v.name = "corner_close";
76 v.kind = "拐角特写";
77 v.eye = center + glm::vec3(2.4f, 1.2f, 2.4f);
78 v.target = center + glm::vec3(0.f, 0.8f, 0.f);
79 v.fovYDeg = std::max(base * 0.8f, 25.f);
80 out.push_back(v);
81 }
82 {
84 v.name = "vista";
85 v.kind = "远景视角";
86 v.eye = center + glm::vec3(0.f, 14.f, -22.f);
87 v.target = center;
88 v.fovYDeg = std::max(base * 0.85f, 35.f);
89 out.push_back(v);
90 }
91 return out;
92}
93
94bool SceneInspect::setCameraPose(const glm::vec3& eye, const glm::vec3& rotYawPitch,
95 float fov) {
96 auto* cap = captureIface();
97 if (!cap) return false;
98 return cap->setCameraPoseYawPitch(eye.x, eye.y, eye.z, rotYawPitch.x, rotYawPitch.y, fov);
99}
100
102 auto* cap = captureIface();
103 if (!cap) return false;
104 return cap->setCameraPose(v.eye.x, v.eye.y, v.eye.z, v.target.x, v.target.y, v.target.z, v.fovYDeg);
105}
106
107std::string SceneInspect::defaultCacheDir() const {
108 std::string root = std::filesystem::current_path().string();
109 for (char& c : root)
110 if (c == '\\') c = '/';
111 if (!root.empty() && root.back() == '/') root.pop_back();
112 return root + "/eve_inspect_cache";
113}
114
115InspectCapture SceneInspect::capture(const std::string& outDir, const std::string& tag,
116 const std::vector<std::string>& buffers) {
117 InspectCapture result;
118 auto* cap = captureIface();
119 if (!cap) {
120 result.error = "Graphics module not available";
121 return result;
122 }
123
124 bool wantColor = buffers.empty();
125 bool wantDepth = false, wantNormal = false, wantId = false, wantShadow = false;
126 for (const auto& b : buffers) {
127 if (b == "color") wantColor = true;
128 else if (b == "depth") wantDepth = true;
129 else if (b == "normal") wantNormal = true;
130 else if (b == "id") wantId = true;
131 else if (b == "shadow") wantShadow = true;
132 }
133 if (!wantColor) wantColor = true;
134
135 ensureCamera();
136 cap->setReadbackEnabled(true);
137
138 std::string dir = outDir;
139 if (dir.empty()) {
140 dir = cacheDir();
141 if (dir.empty()) dir = defaultCacheDir();
142 }
143 for (char& c : dir)
144 if (c == '\\') c = '/';
145
146 const std::string safeTag = tag.empty() ? "frame" : tag;
147 const std::string pngPath = dir + "/" + safeTag + ".png";
148 const std::string jsonPath = dir + "/" + safeTag + ".json";
149 const std::string depthPngPath = dir + "/" + safeTag + "_depth.png";
150 const std::string normalPngPath = dir + "/" + safeTag + "_normal.png";
151 const std::string idPngPath = dir + "/" + safeTag + "_id.png";
152 const std::string idJsonPath = dir + "/" + safeTag + "_id.json";
153
154 std::string err;
155 if (!cap->savePng(pngPath, &result.width, &result.height, &err)) {
156 result.error = err;
157 return result;
158 }
159
160 const std::string geoJson = visibleEntitiesJson();
161 if (const std::string werr = writeTextFile(jsonPath, geoJson); !werr.empty()) {
162 result.error = werr;
163 return result;
164 }
165 result.entityCount = 0;
166 const auto pos = geoJson.find("\"count\":");
167 if (pos != std::string::npos) result.entityCount = std::atoi(geoJson.c_str() + pos + 9);
168
169 if (wantDepth) {
170 std::string berr;
171 if (cap->gbufferPng("depth", depthPngPath, &berr))
172 result.depthPngPath = depthPngPath;
173 else
174 result.unsupported.push_back("depth");
175 }
176 if (wantNormal) {
177 std::string berr;
178 if (cap->gbufferPng("normal", normalPngPath, &berr))
179 result.normalPngPath = normalPngPath;
180 else
181 result.unsupported.push_back("normal");
182 }
183 if (wantShadow) result.unsupported.push_back("shadow");
184
185 if (wantId) {
186 int iw = 0, ih = 0;
187 bool ok = false;
188 const std::string idJson = cap->entityIdMaskJson(&iw, &ih, &ok);
189 if (!ok) {
190 result.unsupported.push_back("id");
191 } else {
192 std::string perr;
193 if (cap->entityIdMaskPng(idPngPath, &perr)) result.idPngPath = idPngPath;
194 if (writeTextFile(idJsonPath, idJson).empty()) result.idJsonPath = idJsonPath;
195 }
196 }
197
198 result.ok = true;
199 result.pngPath = pngPath;
200 result.jsonPath = jsonPath;
201 lastPngPath_ = pngPath;
202 lastJsonPath_ = jsonPath;
203 return result;
204}
205
207 auto* cap = captureIface();
208 return cap ? cap->cameraPoseJson() : "{\"error\":\"Graphics module not available\"}";
209}
210
211std::string SceneInspect::visibleEntitiesJson(const glm::vec3* eye, const glm::vec3* target,
212 float fov) {
213 auto* cap = captureIface();
214 if (!cap) return "{\"error\":\"Graphics module not available\"}";
215 bool ok = false;
216 if (eye && target)
217 return cap->visibleEntitiesJsonAt(eye->x, eye->y, eye->z, target->x, target->y, target->z, fov, &ok);
218 return cap->visibleEntitiesJson(fov, &ok);
219}
220
221} // namespace eve::dev
LogicalId target
int root
Definition AnimSmr.cpp:119
glm::vec4 p[6]
float v
std::int32_t c
std::string text
MeleePoint3 b
Definition MeleeHit.cpp:41
const std::string * tag
std::string path
Definition PlayHost.cpp:110
glm::vec3 eye
V3 dir
Definition TreeMesh.cpp:150
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 自动生成一组标准化巡检机位:
一次原子快照的结果:PNG 渲染帧 + 配套几何 JSON。
std::vector< std::string > unsupported
场景巡检工具集(MCP 底层数据底座)。