Filament加载并渲染glTF模型
1.初始化Filament
void initFilamentEngine(void* nativeWindow) { filament::Engine* m_engine = filament::Engine::create(filament::backend::Backend::METAL); filament::SwapChain* m_swapChain = m_engine->createSwapChain(nativeWindow); filament::View* m_view = m_engine->createView(); }
2.初始化renderer
void initFilaRenderer() { filament::View* filaView = getFilaView(); filament::Engine* filaEngine = getFilaEngine(); filament::Renderer* m_renderer = filaEngine->createRenderer(); m_renderer->setClearOptions({.clearColor={0.0, 0.0, 0.0, 1.0}, .clear = true}); filament::Scene* m_scene = filaEngine->createScene(); filaView->setScene(m_scene); utils::Entity m_camera = utils::EntityManager::get().create(); auto camComponent = filaEngine->createCamera(m_camera); filaView->setCamera(camComponent); filaView->setPostProcessingEnabled(true); filaView->setAntiAliasing(filament::AntiAliasing::NONE); filaView->setMultiSampleAntiAliasingOptions({true, 4, false}); filaView->setAmbientOcclusionOptions({.enabled = false}); filaEngine->getDebugRegistry().setProperty("d.shadowmap.lispsm", false); }
3.上传glTF数据
(1)声明变量
filament::gltfio::MaterialProvider* _matProvider; filament::gltfio::AssetLoader* _assetLoader; filament::gltfio::FilamentAsset* _asset; filament::gltfio::ResourceLoader* _resourceLoader; filament::gltfio::TextureProvider* _textureProvider; filament::gltfio::Animator* _animator; std::vector<utils::Entity> _newCreatedEntites; std::vector<utils::Entity> _entites; std::vector<utils::Entity> _lightEntites; std::vector<filament::math::float2> _lightProperties; mbgl::TimePoint _anmStartTime; std::string _curAnmName; int8_t _curAnmIndex; bool _curAnmLoop; float _curAnmDuration; bool _resourceHasLoaded; static constexpr int kNumAvailable = 128; utils::Entity _renderables[kNumAvailable]; std::mutex _mutex; std::vector<utils::Entity> m_sceneEntites;
(2)上传数据
void upload() { std::lock_guard<std::mutex> lock(_mutex); filament::Engine* engine = getFilaEngine(); if (!_matProvider) { _matProvider = filament::gltfio::createUbershaderProvider(engine, UBERARCHIVE_DEFAULT_DATA, UBERARCHIVE_DEFAULT_SIZE); } if (!_assetLoader) { _assetLoader = filament::gltfio::AssetLoader::create({getFilaEngine(), _matProvider}); } if (_bDirty && _asset && _assetLoader) { _assetLoader->destroyAsset(_asset); _asset = nullptr; _entites.clear(); _lightEntites.clear(); _lightProperties.clear(); } if (!_asset) { if (_modelType == ModelType::GLTF) { _asset = _assetLoader->createAssetFromJson(_data, _dataLen); // glb模型数据和长度 } else { _asset = _assetLoader->createAssetFromBinary(_data, _dataLen); // glb模型数据和长度 } if (!_asset) { assert(false); Log::Info(mbgl::Event::General, "model parse() LoadModel model == null"); return; } if (!_textureProvider) { _textureProvider = filament::gltfio::createStbProvider(backend.getFilaEngine()); } if (!_resourceLoader) { filament::gltfio::ResourceConfiguration configuration = {engine, nullptr, false, false, true}; _resourceLoader = new filament::gltfio::ResourceLoader(configuration); _resourceLoader->addTextureProvider("image/PNG", _textureProvider); _resourceLoader->addTextureProvider("image/png", _textureProvider); _resourceLoader->addTextureProvider("image/jpeg", _textureProvider); _resourceLoader->addTextureProvider("image/JPG", _textureProvider); _resourceLoader->addTextureProvider("image/ktx2", _textureProvider); } _resourceHasLoaded = false; _resourceLoader->asyncBeginLoad(_asset);; _animator = _asset->getAnimator(); size_t lightCount = _asset->getLightEntityCount(); _lightEntites.resize(lightCount); memcpy(&_lightEntites[0], _asset->getLightEntities(), sizeof(utils::Entity) * lightCount); auto& lcm = getFilaEngine()->getLightManager(); for (auto& entity : _lightEntites) { _lightProperties.emplace_back(lcm.getIntensity(lcm.getInstance(entity)), lcm.getFalloff(lcm.getInstance(entity))); } _bDirty = false; } if (_newCreatedEntites.size() + _entites.size() != _asset->getRenderableEntityCount()) { _resourceLoader->asyncUpdateLoad(); if (!_resourceLoader->asyncUploadTangents()) { return; } if (!_resourceHasLoaded) { _asset->releaseSourceData(); if (_data) { free(_data); _data = nullptr; } _resourceHasLoaded = true; } while (size_t numWritten = _asset->popRenderables(_renderables, kNumAvailable)) { auto orgCount = _newCreatedEntites.size(); _newCreatedEntites.resize(orgCount + numWritten); memcpy(&_newCreatedEntites[orgCount], _renderables, sizeof(utils::Entity) * numWritten); } } else if (_textureProvider) { delete _resourceLoader; _resourceLoader = nullptr; delete _textureProvider; _textureProvider = nullptr; } bool bHasAnm = _curAnmName.empty(); if (!bHasAnm && _curAnmIndex == -1) { const size_t numAnimations = _animator->getAnimationCount(); for (size_t i = 0; i < numAnimations; i++) { if (_curAnmName == _animator->getAnimationName(i)) { _curAnmIndex = i; _anmStartTime = mbgl::Clock::now(); _curAnmDuration = _animator->getAnimationDuration(i); break; } } } else if (bHasAnm) { _curAnmIndex = -1; } if (_curAnmIndex != -1) { TimePoint nowTime = mbgl::Clock::now(); double elapseTime = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - _anmStartTime).count() / 1000.0; if (!_curAnmLoop && elapseTime >= _curAnmDuration) { elapseTime = _curAnmDuration; _curAnmName = ""; } _animator->applyAnimation(_curAnmIndex, elapseTime); } _animator->updateBoneMatrices(); }
4.添加Entity
void render() { if (_entites.empty() && _newCreatedEntites.empty() && _lightEntites.empty()) { return; } if (_bTransformDirty) { _bTransformDirty = false; filament::math::mat4 mat = getModelMatrix(modelMat); auto& tcm =getFilaEngine()->getTransformManager(); tcm.setTransform(tcm.getInstance(_asset->getRoot()), mat); size_t lightIndex = 0; auto& lcm = getFilaEngine()->getLightManager(); for (auto& entity : _lightEntites) { auto& prot = _lightProperties[lightIndex++]; lcm.setFalloff(lcm.getInstance(entity), prot.y); lcm.setIntensityCandela(lcm.getInstance(entity), prot.x); } } bool bMatDirty = false; auto depthMat = matrixDepthFor3D(bMatDirty); if (!_newCreatedEntites.empty()) { if (!bMatDirty) { for (auto& entity : _newCreatedEntites) { auto& rcm = parameters.backend.getFilaEngine()->getRenderableManager(); auto reInstance = rcm.getInstance(entity); size_t inCount = rcm.getPrimitiveCount(reInstance); for (size_t i = 0; i != inCount; ++i) { auto pMat = rcm.getMaterialInstanceAt(reInstance, i); pMat->setParameter("cstransform", depthMat); } } } _entites.insert(_entites.end(), _newCreatedEntites.begin(), _newCreatedEntites.end()); _newCreatedEntites.clear(); } if (bMatDirty) { for (auto& entity : _entites) { auto& rcm = parameters.backend.getFilaEngine()->getRenderableManager(); auto reInstance = rcm.getInstance(entity); size_t inCount = rcm.getPrimitiveCount(reInstance); for (size_t i = 0; i != inCount; ++i) { auto pMat = rcm.getMaterialInstanceAt(reInstance, i); pMat->setParameter("cstransform", depthMat); } } } m_sceneEntites.insert(m_sceneEntites.end(), _lightEntites.begin(), _lightEntites.end()); m_sceneEntites.insert(m_sceneEntites.end(), _entites.begin(), _entites.end()); }
const filament::math::mat4f& matrixDepthFor3D(bool& bDirty) { static float s_depthRange = 0.0; static filament::math::mat4f depth3dMat; bDirty = false; if (!IsEqual(depthRangeSize, s_depthRange)) { s_depthRange = depthRangeSize; depth3dMat = matrixForDepthRange(0.0, s_depthRange); bDirty = true; } return depth3dMat; } filament::math::mat4f matrixForDepthRange(float minVal, float maxVal) { float b = minVal; float a = maxVal - b; return filament::math::mat4f( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, a, 0, 0, 0, b, 1 ); }
5.将view传递给渲染器
if (m_renderer->beginFrame(getFilaSwapChain())) { m_renderer->render(getFilaView()); m_renderer->endFrame(); }