载入中...
搜索中...
未找到
SoftBodyModelDefinition.cpp
浏览该文件的文档.
2
4
5#include <cmath>
6#include <initializer_list>
7#include <string>
8
9namespace eve::physics {
10namespace {
11const eve::Value* field(const eve::Value::Object& object, std::string_view name) {
12 const auto found = object.find(std::string(name));
13 return found == object.end() ? nullptr : &found->second;
14}
15
16bool hasExactFields(const eve::Value::Object& object, std::initializer_list<std::string_view> expected) {
17 if (object.size() != expected.size()) return false;
18 for (const auto name : expected)
19 if (!object.contains(std::string(name))) return false;
20 return true;
21}
22
23std::string_view surfaceName(SoftBodySurfaceSampling value) {
24 switch (value) {
25 case SoftBodySurfaceSampling::None: return "none";
26 case SoftBodySurfaceSampling::Vertices: return "vertices";
27 case SoftBodySurfaceSampling::Voxels: return "voxels";
28 }
29 return "";
30}
31
32std::string_view volumeName(SoftBodyVolumeSampling value) {
33 switch (value) {
34 case SoftBodyVolumeSampling::None: return "none";
35 case SoftBodyVolumeSampling::Voxels: return "voxels";
36 }
37 return "";
38}
39
40} // namespace
41
43 if (sourceMesh.empty())
45 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "sourceMesh must not be empty", "sourceMesh"));
46 if (surfaceName(surfaceSampling).empty())
48 eve::DiagnosticCode::InvalidArgument, "unsupported surface sampling mode", "surfaceSampling"));
49 if (volumeName(volumeSampling).empty())
51 "unsupported volume sampling mode", "volumeSampling"));
52 if (surfaceResolution < 2 || surfaceResolution > 128 || volumeResolution < 2 || volumeResolution > 128 ||
53 shapeResolution < 2 || shapeResolution > 128)
55 eve::DiagnosticCode::InvalidArgument, "sampling resolutions must be in [2, 128]", "resolution"));
56 if (!std::isfinite(maxAnisotropy) || maxAnisotropy < 1.f || maxAnisotropy > 5.f)
58 "maxAnisotropy must be in [1, 5]", "maxAnisotropy"));
59 if (!std::isfinite(smoothing) || smoothing < 0.f || smoothing > 1.f)
61 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "smoothing must be in [0, 1]", "smoothing"));
64 eve::DiagnosticCode::InvalidArgument, "at least one sampling mode must be enabled", "sampling"));
66}
67
69 auto valid = validate();
70 if (!valid) return eve::Result<eve::Value>::failure(valid.status());
72 object["schema"] = std::string(SchemaId);
73 object["schemaVersion"] = static_cast<std::int64_t>(SchemaVersion);
74 object["sourceMesh"] = sourceMesh;
75 object["surfaceSampling"] = std::string(surfaceName(surfaceSampling));
76 object["surfaceResolution"] = static_cast<std::int64_t>(surfaceResolution);
77 object["volumeSampling"] = std::string(volumeName(volumeSampling));
78 object["volumeResolution"] = static_cast<std::int64_t>(volumeResolution);
79 object["shapeResolution"] = static_cast<std::int64_t>(shapeResolution);
80 object["maxAnisotropy"] = maxAnisotropy;
81 object["smoothing"] = smoothing;
82 return eve::Result<eve::Value>::success(eve::Value(std::move(object)));
83}
84
86 const auto* object = value.getIf<eve::Value::Object>();
87 if (!object)
89 eve::DiagnosticCode::InvalidArgument, "soft-body model must be an object", "softbodyModel"));
90 const std::initializer_list<std::string_view> names = {
91 "schema", "schemaVersion", "sourceMesh", "surfaceSampling", "surfaceResolution",
92 "volumeSampling", "volumeResolution", "shapeResolution", "maxAnisotropy", "smoothing"};
93 if (!hasExactFields(*object, names))
95 eve::DiagnosticCode::InvalidArgument, "soft-body model fields do not match version 1", "softbodyModel"));
96 const auto* schema = field(*object, "schema");
97 const auto* version = field(*object, "schemaVersion");
98 const auto* mesh = field(*object, "sourceMesh");
99 const auto* surface = field(*object, "surfaceSampling");
100 const auto* volume = field(*object, "volumeSampling");
101 if (!schema || !schema->isString() || schema->asString() != SchemaId)
103 eve::DiagnosticCode::InvalidArgument, "unexpected soft-body model schema", "schema"));
104 if (!version || !version->isInt64() || version->asInt() != SchemaVersion)
106 eve::DiagnosticCode::InvalidArgument, "unsupported soft-body model version", "schemaVersion"));
107 if (!mesh || !mesh->isString() || !surface || !surface->isString() || !volume || !volume->isString())
109 eve::DiagnosticCode::InvalidArgument, "model string field has the wrong type", "softbodyModel"));
110
112 result.sourceMesh = mesh->asString();
113 if (surface->asString() == "none") result.surfaceSampling = SoftBodySurfaceSampling::None;
114 else if (surface->asString() == "vertices") result.surfaceSampling = SoftBodySurfaceSampling::Vertices;
115 else if (surface->asString() == "voxels") result.surfaceSampling = SoftBodySurfaceSampling::Voxels;
116 else
118 eve::DiagnosticCode::InvalidArgument, "unsupported surface sampling mode", "surfaceSampling"));
119 if (volume->asString() == "none") result.volumeSampling = SoftBodyVolumeSampling::None;
120 else if (volume->asString() == "voxels") result.volumeSampling = SoftBodyVolumeSampling::Voxels;
121 else
123 eve::DiagnosticCode::InvalidArgument, "unsupported volume sampling mode", "volumeSampling"));
124
125 auto integer = [&](std::string_view name, int& destination) -> bool {
126 const auto* item = field(*object, name);
127 if (!item || !item->isInt64() || item->asInt() < 0 || item->asInt() > 1000000) return false;
128 destination = static_cast<int>(item->asInt());
129 return true;
130 };
131 auto number = [&](std::string_view name, float& destination) -> bool {
132 const auto* item = field(*object, name);
133 if (!item || !item->isNumeric()) return false;
134 const double parsed = item->isDouble() ? item->asDouble() : static_cast<double>(item->asInt());
135 if (!std::isfinite(parsed)) return false;
136 destination = static_cast<float>(parsed);
137 return true;
138 };
139 if (!integer("surfaceResolution", result.surfaceResolution) ||
140 !integer("volumeResolution", result.volumeResolution) || !integer("shapeResolution", result.shapeResolution) ||
141 !number("maxAnisotropy", result.maxAnisotropy) || !number("smoothing", result.smoothing))
143 eve::DiagnosticCode::InvalidArgument, "model numeric field has the wrong type", "softbodyModel"));
144 auto valid = result.validate();
146 return eve::Result<SoftBodyModelDefinition>::success(std::move(result));
147}
148
152 auto field = [](const char* name, ValueType type, const char* title, std::string defaultJson) {
153 FieldDefinition result;
154 result.name = name;
155 result.type = type;
156 result.required = true;
157 result.title = title;
158 result.defaultJson = std::move(defaultJson);
159 return result;
160 };
161 auto resolution = [&](const char* name, const char* title, int value) {
162 auto result = field(name, ValueType::Integer, title, std::to_string(value));
163 result.minimum = 2;
164 result.maximum = 128;
165 return result;
166 };
168 schema.id = std::string(SchemaId);
169 schema.version = static_cast<int>(SchemaVersion);
170 schema.title = "Soft body model";
171 schema.description = "Mesh source and deterministic sampling settings used to cook a SoftBodyModel.";
172 schema.additionalProperties = false;
173 schema.fields = {field("schema", ValueType::String, "Schema", "\"physics:softbody-model\""),
174 resolution("schemaVersion", "Schema version", 1),
175 field("sourceMesh", ValueType::String, "Source mesh", "\"\""),
176 field("surfaceSampling", ValueType::String, "Surface sampling", "\"vertices\""),
177 resolution("surfaceResolution", "Surface resolution", 16),
178 field("volumeSampling", ValueType::String, "Volume sampling", "\"none\""),
179 resolution("volumeResolution", "Volume resolution", 16),
180 resolution("shapeResolution", "Shape resolution", 48),
181 field("maxAnisotropy", ValueType::Number, "Maximum anisotropy", "3.0"),
182 field("smoothing", ValueType::Number, "Smoothing", "0.25")};
183 schema.fields[1].minimum = schema.fields[1].maximum = 1;
184 schema.fields[8].minimum = 1;
185 schema.fields[8].maximum = 5;
186 schema.fields[9].minimum = 0;
187 schema.fields[9].maximum = 1;
188 return schema;
189}
190
198
199} // namespace eve::physics
double value
double volume
std::string title
std::string name
bool valid
Mesh * mesh
double number
bool found
std::string string
Json object
float size
Definition TreeMesh.cpp:156
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
Type type() const
Return the active value type.
static eve::Result< SchemaRegistrationStatus > registerVersioned(const SchemaDefinition &definition)
Registers a new exact (id, version) entry without replacing it.
static const SchemaDefinition * resolve(const std::string &schemaId, int schemaVersion)
Resolves one exact (schemaId, schemaVersion) pair, or nullptr.
Optional physics backend for vehicle mobility and body attach.
Definition Climbing.h:36
SoftBodySurfaceSampling
SoftBodySurfaceSampling public API.
SoftBodyVolumeSampling
SoftBodyVolumeSampling public API.
const EditorValue * field(const EditorValue &value, const char *name)
ValueType
JSON-compatible value kinds understood by a schema field.
Definition SchemaTypes.h:16
Versioned authoring recipe used to cook a mesh-backed SoftBodyModel.
static eve::Result< void > ensureSchemaRegistered()
Idempotently register version 1 in the process schema registry.
eve::Result< void > validate() const
Validate the complete immutable cooking recipe.
static constexpr std::string_view SchemaId
static eve::schema::SchemaDefinition schemaDefinition()
Return the registry schema for tooling and generic JSON validation.
static eve::Result< SoftBodyModelDefinition > fromValue(const eve::Value &value)
Decode version 1 transactionally and reject unknown fields.
eve::Result< eve::Value > toValue() const
Encode every version-1 field into an owning persistent value.
static constexpr std::uint32_t SchemaVersion
Metadata and validation constraints for one object member.
Definition SchemaTypes.h:77
Versioned runtime schema for a JSON object.
Definition SchemaTypes.h:93
std::vector< FieldDefinition > fields
Definition SchemaTypes.h:99