载入中...
搜索中...
未找到
VirtualGeometryRuntime.cpp
浏览该文件的文档.
2
5
6#include <algorithm>
7#include <cmath>
8#include <cstring>
9#include <utility>
10
12namespace {
13void hashBytes(std::uint64_t& hash, const void* data, std::size_t size) {
14 const auto* bytes = static_cast<const unsigned char*>(data);
15 for (std::size_t i = 0; i < size; ++i) {
16 hash ^= bytes[i];
17 hash *= 1099511628211ull;
18 }
19}
20std::uint64_t checksum(const virtualgeometry::VirtualGeometryAsset& a) {
21 std::uint64_t hash = 1469598103934665603ull;
22 hashBytes(hash, a.positions.data(), a.positions.size() * sizeof(float));
23 hashBytes(hash, a.triangles.data(), a.triangles.size() * sizeof(std::uint32_t));
24 hashBytes(hash, a.clusters.data(), a.clusters.size() * sizeof(virtualgeometry::VgCluster));
25 return hash;
26}
27} // namespace
31 const VirtualGeometryDocumentTarget& document, const IVirtualGeometryMeshResolver& resolver) {
32 const auto diagnostics = document.validate();
33 for (const auto& d : diagnostics)
34 if (d.severity() == DiagnosticSeverity::Error)
36 Status(EditorStatus::Rejected, diagnostics));
37 if (document.value().sourceAsset.empty())
38 return eve::editing::failed<VirtualGeometryBuildArtifact>(EditorStatus::Rejected,
39 RuleId("editor.virtualgeometry.source"),
40 "VirtualGeometry build requires a source asset");
41 auto resolved = resolver.resolve(document.value().sourceAsset);
42 if (!resolved.ok())
43 return Result<VirtualGeometryBuildArtifact>::failure(resolved.status());
44 auto& mesh = resolved.value();
45 const bool normalsInvalid = !mesh.normals.empty() && mesh.normals.size() != mesh.positions.size();
46 if (mesh.positions.empty() || mesh.positions.size() % 3 != 0 || mesh.indices.empty() ||
47 mesh.indices.size() % 3 != 0 || mesh.positions.size() / 3 > 50000000 || mesh.indices.size() > 150000000 ||
48 normalsInvalid)
49 return eve::editing::failed<VirtualGeometryBuildArtifact>(EditorStatus::Rejected,
50 RuleId("editor.virtualgeometry.mesh"),
51 "VirtualGeometry mesh shape or budget is invalid");
52 const std::size_t vertices = mesh.positions.size() / 3;
53 for (float value : mesh.positions)
54 if (!std::isfinite(value))
55 return eve::editing::failed<VirtualGeometryBuildArtifact>(EditorStatus::Rejected,
56 RuleId("editor.virtualgeometry.position"),
57 "VirtualGeometry positions must be finite");
58 for (std::uint32_t index : mesh.indices)
59 if (index >= vertices)
60 return eve::editing::failed<VirtualGeometryBuildArtifact>(EditorStatus::Rejected,
61 RuleId("editor.virtualgeometry.index"),
62 "VirtualGeometry index is out of range");
63 auto candidate = std::make_unique<virtualgeometry::VirtualGeometryAsset>();
66 input.vertexCount = static_cast<int>(vertices);
67 input.positions = mesh.positions.data();
68 input.normals = mesh.normals.empty() ? nullptr : mesh.normals.data();
69 input.indices = mesh.indices.data();
70 input.indexCount = static_cast<int>(mesh.indices.size());
71 if (!builder.build(input, document.value().builder, *candidate))
72 return eve::editing::failed<VirtualGeometryBuildArtifact>(
73 EditorStatus::Failed, RuleId("editor.virtualgeometry.build"),
74 "VirtualGeometry builder rejected the candidate mesh");
76 artifact.sourceRevision = document.revision();
77 artifact.vertices = candidate->vertexCount;
78 artifact.sourceTriangles = mesh.indices.size() / 3;
79 artifact.storedTriangles = candidate->triangles.size() / 3;
80 artifact.clusters = static_cast<int>(candidate->clusters.size());
81 artifact.checksum = checksum(*candidate);
82 for (const auto& cluster : candidate->clusters) {
83 artifact.maxLod = std::max(artifact.maxLod, static_cast<int>(cluster.lodLevel));
84 if (cluster.parent == 0xFFFFFFFFu) ++artifact.roots;
85 if (cluster.childCount > 4 || cluster.triStart + cluster.triCount > candidate->triangles.size() / 3)
86 return eve::editing::failed<VirtualGeometryBuildArtifact>(
87 EditorStatus::Failed, RuleId("editor.virtualgeometry.dag"),
88 "VirtualGeometry builder produced an invalid cluster range");
89 for (std::uint32_t i = 0; i < cluster.childCount; ++i)
90 if (cluster.children[i] >= candidate->clusters.size())
91 return eve::editing::failed<VirtualGeometryBuildArtifact>(
92 EditorStatus::Failed, RuleId("editor.virtualgeometry.dag"),
93 "VirtualGeometry builder produced an invalid child reference");
94 }
95 const auto& v = document.value();
96 constexpr float pi = 3.14159265358979323846f;
97 const float projection = static_cast<float>(v.previewHeight) / (2.f * std::tan(v.previewFov * pi / 180.f * .5f));
98 for (int sample = 0; sample < v.distanceSamples; ++sample) {
99 const float alpha = static_cast<float>(sample) / (v.distanceSamples - 1);
100 const float distance = v.nearDistance * std::pow(v.farDistance / v.nearDistance, alpha);
101 std::vector<std::uint32_t> selected;
102 virtualgeometry::selectClusters(*candidate, distance, projection, v.errorPixels, selected);
105 point.clusters = static_cast<int>(selected.size());
106 for (auto id : selected) point.triangles += candidate->clusters[id].triCount;
107 virtualgeometry::lodHistogram(*candidate, selected, point.levelHistogram);
108 artifact.lodCurve.push_back(std::move(point));
109 }
110 asset_ = std::move(candidate);
111 revision_ = document.revision();
112 return eve::editing::applied<VirtualGeometryBuildArtifact>(std::move(artifact), diagnostics);
113}
114} // namespace eve::virtualgeometry_editing
double value
std::array< std::uint8_t, 32 > hash
Definition Evpack.cpp:172
EvpackChunkInput input
Definition Evpack.cpp:170
float v
std::uint64_t bytes
MeleePoint3 a
Definition MeleeHit.cpp:40
float distance
std::vector< Point > vertices
float d
Mesh * mesh
float size
Definition TreeMesh.cpp:156
uint32_t index
glm::vec3 point
Move-only operation result carrying either a value or Status.
Definition Result.h:155
const T & value() const &
Borrow the value from a const lvalue after checking success.
Definition Result.h:308
Structured status and zero or more diagnostics for an operation.
Definition Status.h:68
std::uint64_t revision() const override
Return the current revision.
CPU preprocessor that builds a Nanite-style hierarchical cluster DAG from a triangle mesh:
Definition Builder.h:23
bool build(const MeshInput &in, const Options &opt, VirtualGeometryAsset &out)
Returns false on empty/invalid input.
Definition Builder.cpp:337
Asset resolver boundary for VirtualGeometry preprocessing.
virtual Result< VirtualGeometryMeshData > resolve(const std::string &assetId) const =0
Return an owned triangulated mesh for one asset generation.
Result< VirtualGeometryBuildArtifact > build(const VirtualGeometryDocumentTarget &document, const IVirtualGeometryMeshResolver &resolver)
Resolve, validate and build fully before replacing the active asset.
~VirtualGeometryBuildRuntime()
Virtual geometry build runtime.
VirtualGeometryBuildRuntime()
Virtual geometry build runtime.
const VirtualGeometryImportValue & value() const
Value.
std::vector< EditorDiagnostic > validate() const
Validate builder invariants, CPU budgets and preview sweep.
void lodHistogram(const VirtualGeometryAsset &asset, const std::vector< std::uint32_t > &selected, std::vector< int > &perLevelCount)
Per-LOD-level counts of the selected clusters (size = maxLod+1).
int selectClusters(const VirtualGeometryAsset &asset, float dist, float projScale, float errorPx, std::vector< std::uint32_t > &outSelected)
CPU reference implementation of the GPU cluster-DAG LOD selection (mirrors shaders/vg_cull....
CPU-side processed cluster (before packing into VgGpuCluster).
Fully processed virtual-geometry asset (CPU representation). Produced by Builder from a Mesh; uploade...
Immutable quality/cost report for a built virtual-geometry generation.
virtualgeometry::VirtualGeometryBuilder::Options builder
One sample in the logarithmic camera-distance LOD cost curve.