载入中...
搜索中...
未找到
ModelRenderer.cpp
浏览该文件的文档.
2
3#include "model3d/ModelData.h"
4
9#include "graphics/Texture.h"
10#include "image/Image.h"
11
12#include <assimp/matrix4x4.h>
13#include <assimp/mesh.h>
14#include <assimp/scene.h>
15
16#include <memory>
17#include <string>
18#include <unordered_map>
19#include <vector>
20
21namespace eve::model3d {
22namespace {
23
28
29Texture *textureFromImageData(IResourceFactory *gfx, image::ImageData *img) {
30 if (!img) return nullptr;
31 try {
32 return gfx->newTexture(img);
33 } catch (...) {
34 return nullptr;
35 }
36}
37
38Texture *loadEmbeddedTexture(IResourceFactory *gfx, ModelData *model, int idx) {
39 image::ImageData *img = model->getEmbeddedTextureImageData(idx);
40 Texture *tex = textureFromImageData(gfx, img);
41 delete img;
42 return tex;
43}
44
45std::string basenameOf(const std::string &path) {
46 const size_t slash = path.find_last_of("/\\");
47 return slash == std::string::npos ? path : path.substr(slash + 1);
48}
49
50Texture *loadExternalTexture(IResourceFactory *gfx, const std::string &path) {
51 auto *fs = filesystem::Filesystem::create();
52 std::unique_ptr<filesystem::FileData> fd;
53 try {
54 fd.reset(fs->read(path));
55 } catch (...) {
56 }
57 if (!fd || fd->getSize() == 0) {
58 const std::string base = basenameOf(path);
59 try {
60 fd.reset(fs->read(base));
61 } catch (...) {
62 }
63 if (!fd || fd->getSize() == 0) {
64 try {
65 fd.reset(fs->read("Textures/" + base));
66 } catch (...) {
67 }
68 }
69 }
70 if (!fd || fd->getSize() == 0) return nullptr;
71 try {
72 image::ImageData *img = image::Image::create()->newImageData(fd.get());
73 Texture *tex = textureFromImageData(gfx, img);
74 delete img;
75 return tex;
76 } catch (...) {
77 return nullptr;
78 }
79}
80
81Texture *loadTextureSlot(IResourceFactory *gfx, ModelData *model, int matIndex, const std::string &type) {
82 if (model->getMaterialTextureSlotCount(matIndex, type) <= 0) return nullptr;
83 const int embedded = model->getMaterialTextureEmbeddedIndex(matIndex, type, 0);
84 if (embedded >= 0) return loadEmbeddedTexture(gfx, model, embedded);
85 const std::string path = model->getMaterialTexturePath(matIndex, type, 0);
86 if (path.empty()) return nullptr;
87 return loadExternalTexture(gfx, path);
88}
89
90struct TextureLook {
91 Texture *albedo = nullptr;
92 Texture *normal = nullptr;
93 Texture *height = nullptr;
94 float tr = 1.f, tg = 1.f, tb = 1.f, ta = 1.f;
95 float metallic = 0.f;
96 float roughness = 0.45f;
97};
98
99TextureLook materialLook(IResourceFactory *gfx, ModelData *model, int matIndex, const ModelRenderOptions &options,
100 std::unordered_map<int, TextureLook> &cache) {
101 auto it = cache.find(matIndex);
102 if (it != cache.end()) return it->second;
103
104 TextureLook look;
105 if (matIndex >= 0) {
106 look.tr = model->getMaterialBaseColorR(matIndex);
107 look.tg = model->getMaterialBaseColorG(matIndex);
108 look.tb = model->getMaterialBaseColorB(matIndex);
109 look.ta = model->getMaterialBaseColorA(matIndex);
110 look.metallic = model->getMaterialMetallicFactor(matIndex);
111 look.roughness = model->getMaterialRoughnessFactor(matIndex);
112 if (options.importAlbedo) {
113 look.albedo = loadTextureSlot(gfx, model, matIndex, "base_color");
114 if (!look.albedo) look.albedo = loadTextureSlot(gfx, model, matIndex, "diffuse");
115 }
116 if (options.importNormalMaps)
117 look.normal = loadTextureSlot(gfx, model, matIndex, "normals");
118 if (options.importHeightMaps)
119 look.height = loadTextureSlot(gfx, model, matIndex, "height");
120 }
121 cache.emplace(matIndex, look);
122 return look;
123}
124
125Renderable3D *makeRenderable(IResourceFactory *gfx, ModelData *model, int meshIndex, const aiMatrix4x4 &world,
126 const ModelRenderOptions &options, std::unordered_map<int, TextureLook> &cache) {
127 const aiScene *scene = model->getScene();
128 if (!scene || meshIndex < 0 || static_cast<unsigned>(meshIndex) >= scene->mNumMeshes)
129 return nullptr;
130 const aiMesh *ai = scene->mMeshes[meshIndex];
131 if (!ai || ai->mNumVertices == 0 || ai->mNumFaces == 0) return nullptr;
132
133 Mesh *mesh = options.bakeWorldTransform ? gfx->newMeshFromAssimp(*ai, world)
134 : gfx->newMeshFromAssimp(*ai);
135 if (!mesh) return nullptr;
136
137 const int matIndex = model->getMaterialIndex(meshIndex);
138 const TextureLook look = materialLook(gfx, model, matIndex, options, cache);
139
140 Renderable3D *ent = Renderable3D::create();
141 ent->meshRenderer()->visible = true;
142 ent->setMesh(mesh);
143 if (look.albedo) ent->setTexture(look.albedo);
144 if (look.normal) ent->setNormalTexture(look.normal);
145 if (look.height) ent->setHeightTexture(look.height);
146 ent->setTint(look.tr, look.tg, look.tb, look.ta);
147 ent->setMetallic(look.metallic);
148 ent->setRoughness(look.roughness);
149 return ent;
150}
151
152void walkNodes(const aiNode *node, const aiMatrix4x4 &parent, IResourceFactory *gfx, ModelData *model,
153 const ModelRenderOptions &options, std::vector<Renderable3D *> &out,
154 std::unordered_map<int, TextureLook> &cache) {
155 if (!node) return;
156 const aiMatrix4x4 world = parent * node->mTransformation;
157 for (unsigned i = 0; i < node->mNumMeshes; ++i) {
158 Renderable3D *ent =
159 makeRenderable(gfx, model, static_cast<int>(node->mMeshes[i]), world, options, cache);
160 if (ent) out.push_back(ent);
161 }
162 for (unsigned c = 0; c < node->mNumChildren; ++c)
163 walkNodes(node->mChildren[c], world, gfx, model, options, out, cache);
164}
165
166bool findMeshTransform(const aiNode *node, const aiMatrix4x4 &parent, unsigned meshIndex,
167 aiMatrix4x4 &out) {
168 if (!node) return false;
169 const aiMatrix4x4 world = parent * node->mTransformation;
170 for (unsigned i = 0; i < node->mNumMeshes; ++i) {
171 if (node->mMeshes[i] == meshIndex) {
172 out = world;
173 return true;
174 }
175 }
176 for (unsigned c = 0; c < node->mNumChildren; ++c)
177 if (findMeshTransform(node->mChildren[c], world, meshIndex, out)) return true;
178 return false;
179}
180
181} // namespace
182
183Renderable3D *buildRenderable(IResourceFactory &gfx, ModelData *model, int meshIndex,
184 const ModelRenderOptions &options) {
185 if (!model) return nullptr;
186 const aiScene *scene = model->getScene();
187 if (!scene || !scene->mRootNode) return nullptr;
188
189 aiMatrix4x4 world;
190 if (!findMeshTransform(scene->mRootNode, aiMatrix4x4(), static_cast<unsigned>(meshIndex),
191 world)) {
192 world = aiMatrix4x4();
193 }
194 std::unordered_map<int, TextureLook> cache;
195 return makeRenderable(&gfx, model, meshIndex, world, options, cache);
196}
197
198std::vector<Renderable3D *> buildRenderables(IResourceFactory &gfx, ModelData *model,
199 const ModelRenderOptions &options) {
200 std::vector<Renderable3D *> out;
201 if (!model) return out;
202 const aiScene *scene = model->getScene();
203 if (!scene || !scene->mRootNode) return out;
204 std::unordered_map<int, TextureLook> cache;
205 walkNodes(scene->mRootNode, aiMatrix4x4(), &gfx, model, options, out, cache);
206 return out;
207}
208
209} // namespace eve::model3d
std::string type
float height
Definition Grass.cpp:235
uint32_t c
float roughness
float tb
float tr
Texture * normal
float tg
Texture * albedo
float ta
float metallic
int idx
Mesh * mesh
glm::mat4 model
int parent
Definition TreeMesh.cpp:175
Texture / mesh / shader / canvas creation and release.
GPU mesh handle (+ optional CPU morph targets).
Definition Mesh.h:18
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:17
CPU-side decoded 3D model (Assimp scene owned via medialoader::ModelScene). Does not upload to GPU — ...
Definition ModelData.h:23
Renderable3D * buildRenderable(IResourceFactory &gfx, ModelData *model, int meshIndex, const ModelRenderOptions &options)
std::vector< Renderable3D * > buildRenderables(IResourceFactory &gfx, ModelData *model, const ModelRenderOptions &options)
NodeDesc node(std::string id, std::vector< NodeDesc > children, std::string name)
Definition NodeDesc.cpp:214