载入中...
搜索中...
未找到
Model3D.cpp
浏览该文件的文档.
1#include "model3d/Model3D.h"
4
5#include "common/Data.h"
6#include "common/Exception.h"
7#include "common/Resource.h"
10#include "graphics/Graphics.h"
11#include "image/ImageData.h"
12
13#include "medialoader/Exception.h"
14#include "medialoader/model/ModelLoader.h"
15
16#include "model3d/ModelLoader.h"
17
18#include <simplesquirrel/simplesquirrel.hpp>
19
20#include <cctype>
21#include <functional>
22
23namespace eve {
24namespace model3d {
25
27
28Model3D::Model3D() = default;
29Model3D::~Model3D() = default;
30
31namespace {
32
33std::string lowerExt(std::string ext) {
34 for (char &c : ext)
35 c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
36 return ext;
37}
38
39std::string ensureDotExt(std::string ext) {
40 ext = lowerExt(std::move(ext));
41 if (ext.empty())
42 return {};
43 if (ext[0] != '.')
44 ext.insert(ext.begin(), '.');
45 return ext;
46}
47
48medialoader::LoadOptions toMedialoader(const ModelLoadOptions &opt) {
49 medialoader::LoadOptions m;
50 m.triangulate = opt.triangulate;
51 m.generateNormalsIfMissing = opt.generateNormalsIfMissing;
52 m.joinIdenticalVertices = opt.joinIdenticalVertices;
53 m.flipUVs = opt.flipUVs;
54 m.improveCacheLocality = opt.improveCacheLocality;
55 return m;
56}
57
58medialoader::ModelScene loadOrThrow(medialoader::ModelLoader &loader, const void *data, size_t size,
59 const char *hint, const medialoader::LoadOptions &opt) {
60 try {
61 return loader.loadFromMemory(data, size, hint, opt);
62 } catch (const medialoader::Exception &e) {
63 throw eve::Exception("%s", e.what());
64 }
65}
66
67} // namespace
68
69ModelData *Model3D::newModelData(Data *data, std::string hintExt) {
70 return newModelData(data, std::move(hintExt), ModelLoadOptions{});
71}
72
73ModelData *Model3D::newModelData(Data *data, std::string hintExt,
74 const ModelLoadOptions &options) {
75 if (data == nullptr || data->getData() == nullptr || data->getSize() == 0)
76 throw eve::Exception("Cannot decode empty model data");
77
78 std::string hint = ensureDotExt(std::move(hintExt));
79 if (hint.empty()) {
80 if (auto *fd = dynamic_cast<filesystem::FileData *>(data))
81 hint = ensureDotExt(fd->getExtension());
82 }
83
84 // Prefer VFS for sidecar resolution when FileData carries a filename.
85 filesystem::Filesystem *fs = ModuleManager::getInstance<filesystem::Filesystem>("Filesystem");
86 if (!fs)
87 fs = filesystem::Filesystem::create();
88
89 EveFileSystem eveFs(fs);
90 medialoader::ModelLoader loader(&eveFs);
91
92 auto scene = loadOrThrow(loader, data->getData(), data->getSize(), hint.c_str(),
93 toMedialoader(options));
94 if (scene.empty())
95 throw eve::Exception("Could not decode model data");
96
97 std::string uri;
98 if (auto *fd = dynamic_cast<filesystem::FileData *>(data))
99 uri = "file://" + fd->getFilename();
100
101 return new ModelData(std::move(scene), std::move(uri));
102}
103
105 return newModelDataFromFile(std::move(path), ModelLoadOptions{});
106}
107
108ModelData *Model3D::newModelDataFromFile(std::string path, const ModelLoadOptions &options) {
109 if (path.empty())
110 throw eve::Exception("Model3D::newModelDataFromFile: empty path");
111
112 // Route through the unified resource cache: options are part of the key,
113 // so identical (path, options) requests share one decoded Assimp scene.
114 const std::string key = modelCacheKey(path, options);
116 if (!resource)
117 throw eve::Exception("Could not load model: %s", path.c_str());
118 return static_cast<ModelData *>(resource);
119}
120
122 int meshIndex) {
123 if (!gfx)
124 throw eve::Exception("Model3D::createRenderable: null Graphics");
125 if (!model)
126 throw eve::Exception("Model3D::createRenderable: null ModelData");
127 return buildRenderable(*gfx, model, meshIndex);
128}
129
130void Model3D::expose(ssq::Table &table) {
131 auto cls = table.addClass(name, Model3D::create, false);
132 expose(cls);
133
134 auto md = table.addClass<ModelData>(
135 "ModelData", std::function<ModelData *()>([]() -> ModelData * { return nullptr; }), true);
136 md.addFunc("empty", &ModelData::empty);
137 md.addFunc("getMeshCount", &ModelData::getMeshCount);
138 md.addFunc("getMaterialCount", &ModelData::getMaterialCount);
139 md.addFunc("getVertexCount", &ModelData::getVertexCount);
140 md.addFunc("getFaceCount", &ModelData::getFaceCount);
141 md.addFunc("hasNormals", &ModelData::hasNormals);
142 md.addFunc("hasTexCoords", &ModelData::hasTexCoords);
143 md.addFunc("getMaterialIndex", &ModelData::getMaterialIndex);
144 md.addFunc("getMaterialName", &ModelData::getMaterialName);
145 md.addFunc("getMaterialBaseColorR", &ModelData::getMaterialBaseColorR);
146 md.addFunc("getMaterialBaseColorG", &ModelData::getMaterialBaseColorG);
147 md.addFunc("getMaterialBaseColorB", &ModelData::getMaterialBaseColorB);
148 md.addFunc("getMaterialBaseColorA", &ModelData::getMaterialBaseColorA);
149 md.addFunc("getMaterialMetallicFactor", &ModelData::getMaterialMetallicFactor);
150 md.addFunc("getMaterialRoughnessFactor", &ModelData::getMaterialRoughnessFactor);
151 md.addFunc("getMaterialOpacity", &ModelData::getMaterialOpacity);
152 md.addFunc("getMaterialTwoSided", &ModelData::getMaterialTwoSided);
153 md.addFunc("getMaterialTextureSlotCount", &ModelData::getMaterialTextureSlotCount);
154 md.addFunc("getMaterialTexturePath", &ModelData::getMaterialTexturePath);
155 md.addFunc("getMaterialTextureEmbeddedIndex", &ModelData::getMaterialTextureEmbeddedIndex);
156 md.addFunc("getEmbeddedTextureCount", &ModelData::getEmbeddedTextureCount);
157 md.addFunc("getEmbeddedTextureName", &ModelData::getEmbeddedTextureName);
158 md.addFunc("getEmbeddedTextureWidth", &ModelData::getEmbeddedTextureWidth);
159 md.addFunc("getEmbeddedTextureHeight", &ModelData::getEmbeddedTextureHeight);
160 md.addFunc("getEmbeddedTextureImageData", &ModelData::getEmbeddedTextureImageData);
161 md.addFunc("getMorphTargetCount", &ModelData::getMorphTargetCount);
162 md.addFunc("getMorphTargetName", &ModelData::getMorphTargetName);
163 md.addFunc("hasBones", &ModelData::hasBones);
164 md.addFunc("getBoneCount", &ModelData::getBoneCount);
165 md.addFunc("getBoneName", &ModelData::getBoneName);
166 md.addFunc("getInverseBindMatrixElement", &ModelData::getInverseBindMatrixElement);
167 md.addFunc("getBoneWeightCount", &ModelData::getBoneWeightCount);
168 md.addFunc("getBoneWeightVertex", &ModelData::getBoneWeightVertex);
169 md.addFunc("getBoneWeightValue", &ModelData::getBoneWeightValue);
170 md.addFunc("getAnimationCount", &ModelData::getAnimationCount);
171 md.addFunc("getAnimationName", &ModelData::getAnimationName);
172}
173
174void Model3D::expose(ssq::Class &cls) {
175 cls.addFunc("getName", &Model3D::getName);
176 cls.addFunc("newModelData", static_cast<ModelData *(Model3D::*)(Data *, std::string)>(
178 cls.addFunc("newModelDataFromFile",
179 static_cast<ModelData *(Model3D::*)(std::string)>(&Model3D::newModelDataFromFile));
180 cls.addFunc("createRenderable", &Model3D::createRenderable);
181}
182
183} // namespace model3d
184} // namespace eve
HSQOBJECT cls
Definition ECS.cpp:21
uint32_t c
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:24
glm::mat4 model
Light2D::Data * data
const char * name
Definition RockMesh.cpp:21
float m[16]
virtual std::string getName() const =0
Resource * get(std::string key)
Get the cached resource for key; on a miss, load it through the registered IAssetReloader providers a...
Definition Resource.cpp:56
static ResourceManager & getInstance()
Definition Resource.cpp:8
Resource is a game object that is managed by the ResourceManager. It can be loaded from a file or gen...
Definition Resource.h:35
Data buffer paired with a filename (used for type identification).
Definition FileData.h:12
medialoader::FileSystem adapter over eve::filesystem (physfs / VFS).
Resource module for decoding 3D models via medialoader (Assimp). Produces ModelData; GPU upload is gr...
Definition Model3D.h:41
ModelData * newModelData(Data *data, std::string hintExt="")
Decode model from in-memory bytes.
Definition Model3D.cpp:69
graphics::Renderable3D * createRenderable(graphics::Graphics *gfx, ModelData *model, int meshIndex)
Definition Model3D.cpp:121
ModelData * newModelDataFromFile(std::string path)
Decode model from a VFS path (physfs). Uses EveFileSystem so sidecar files (.mtl, textures) resolve t...
Definition Model3D.cpp:104
CPU-side decoded 3D model (Assimp scene owned via medialoader::ModelScene). Does not upload to GPU — ...
Definition ModelData.h:23
int getEmbeddedTextureCount() const
float getMaterialBaseColorR(int matIndex) const
Base color: glTF BASE_COLOR, falling back to OBJ/legacy DIFFUSE.
float getMaterialMetallicFactor(int matIndex) const
PBR factors; defaults 0 (metallic) / 0.45 (roughness) when absent.
float getMaterialBaseColorB(int matIndex) const
float getMaterialBaseColorG(int matIndex) const
int getFaceCount(int meshIndex) const
bool hasNormals(int meshIndex) const
int getEmbeddedTextureHeight(int idx) const
0 means a compressed blob (use getEmbeddedTextureImageData to decode).
int getBoneCount(int meshIndex) const
int getBoneWeightCount(int meshIndex, int boneIndex) const
float getMaterialOpacity(int matIndex) const
std::string getMaterialTexturePath(int matIndex, const std::string &type, int slot=0) const
External file path, or "*N" for an embedded texture. Empty when absent.
int getMaterialTextureSlotCount(int matIndex, const std::string &type) const
Texture type names (Squirrel strings): "base_color", "diffuse", "normals", "height",...
float getInverseBindMatrixElement(int meshIndex, int boneIndex, int elementIndex) const
Inverse-bind (offset) matrix element, column-major, elementIndex in [0,15].
std::string getMaterialName(int matIndex) const
int getEmbeddedTextureWidth(int idx) const
bool getMaterialTwoSided(int matIndex) const
int getAnimationCount() const
Scene-level animation clips (aiAnimation).
float getMaterialBaseColorA(int matIndex) const
float getBoneWeightValue(int meshIndex, int boneIndex, int weightIndex) const
std::string getMorphTargetName(int meshIndex, int morphIndex) const
std::string getAnimationName(int animIndex) const
bool hasTexCoords(int meshIndex) const
int getBoneWeightVertex(int meshIndex, int boneIndex, int weightIndex) const
image::ImageData * getEmbeddedTextureImageData(int idx) const
int getMaterialCount() const
Definition ModelData.cpp:92
int getMaterialIndex(int meshIndex) const
Assimp material slot referenced by a mesh; -1 when invalid.
int getMaterialTextureEmbeddedIndex(int matIndex, const std::string &type, int slot=0) const
Scene texture index for embedded "*N" references; -1 for external files.
float getMaterialRoughnessFactor(int matIndex) const
bool hasBones(int meshIndex) const
Assimp skeletal skin data (aiBone / vertex weights) on a mesh.
std::string getBoneName(int meshIndex, int boneIndex) const
int getVertexCount(int meshIndex) const
Definition ModelData.cpp:97
std::string getEmbeddedTextureName(int idx) const
int getMorphTargetCount(int meshIndex) const
Assimp morph / blend-shape targets on a mesh (aiAnimMesh).
std::string modelCacheKey(const std::string &path, const ModelLoadOptions &options)
Build a deterministic ResourceManager cache key for path + options.
Renderable3D * buildRenderable(IResourceFactory &gfx, ModelData *model, int meshIndex, const ModelRenderOptions &options)
Definition Build.cpp:11
Toggles for the Assimp post-processing steps applied by medialoader on decode. All default to on (mat...
Definition Model3D.h:28