diff --git a/ios/Classes/SwiftPolyvoxFilamentPlugin.swift b/ios/Classes/SwiftPolyvoxFilamentPlugin.swift index e63902af..01e56eea 100644 --- a/ios/Classes/SwiftPolyvoxFilamentPlugin.swift +++ b/ios/Classes/SwiftPolyvoxFilamentPlugin.swift @@ -11,6 +11,7 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture var width: Double = 0 var height: Double = 0 + var createdAt = Date() var targetPixelBuffer: CVPixelBuffer?; // var context: EAGLContext?; @@ -74,6 +75,7 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture do { let c1 = try found!.resourceValues(forKeys: [.creationDateKey]).creationDate let c2 = try fileURL.resourceValues(forKeys: [.creationDateKey]).creationDate + if c1! < c2! { found = fileURL print("\(fileURL) is newer, replacing") @@ -86,11 +88,18 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture } } } - - if found != nil { - print("Using hot reloaded asset : \(found)") - path = found?.path - } else { + + do { + if let cd = try found?.resourceValues(forKeys:[.creationDateKey]).creationDate { + if cd > instance.createdAt { + print("Using hot reloaded asset : \(found)") + path = found!.path + } + } + } catch { + + } + if path == nil { if(uriString.hasPrefix("file://")) { path = String(uriString.dropFirst(7)) } else if(uriString.hasPrefix("asset://")) { @@ -103,7 +112,7 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture } } else { // TODO - } + } } do { print("Opening data from path \(path)") @@ -115,9 +124,8 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture return ResourceBuffer(data:rawPtr, size:UInt32(nsData.count), id:UInt32(resId)) } catch { print("Error opening file: \(error)") - return ResourceBuffer() } - return ResourceBuffer() + return ResourceBuffer() } var freeResource : @convention(c) (UInt32,UnsafeMutableRawPointer) -> () = { rid, resourcesPtr in @@ -349,7 +357,8 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture remove_skybox(self.viewer!) result("OK"); case "loadGlb": - let assetPtr = load_glb(self.viewer, call.arguments as! String) + let args = call.arguments as! Array + let assetPtr = load_glb(self.viewer, args[0] as! String, args[1] as! Bool) result(unsafeBitCast(assetPtr, to:Int64.self)); case "loadGltf": let args = call.arguments as! Array @@ -463,16 +472,21 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture case "rotateEnd": grab_end(self.viewer) result("OK") + case "clearBackgroundImage": + clear_background_image(self.viewer!) + result("OK") + case "setBackgroundColor": + let args = call.arguments as! Array + set_background_color(self.viewer!, Float(args[0] as! Double),Float(args[1] as! Double),Float(args[2] as! Double), Float(args[3] as! Double)) + result("OK") case "setBackgroundImage": - let uri = call.arguments as! String - set_background_image(self.viewer!, uri) - render(self.viewer!, 0) - self.registry.textureFrameAvailable(self.textureId!) - result("OK") + let uri = call.arguments as? String + set_background_image(self.viewer!, uri) + result("OK") case "setBackgroundImagePosition": - let args = call.arguments as! Array - set_background_image_position(self.viewer, Float(args[0] as! Double), Float(args[1] as! Double), args[2] as! Bool) - result("OK"); + let args = call.arguments as! Array + set_background_image_position(self.viewer, Float(args[0] as! Double), Float(args[1] as! Double), args[2] as! Bool) + result("OK"); case "setPosition": let args = call.arguments as! Array let assetPtr = UnsafeMutableRawPointer.init(bitPattern: args[0] as! Int) diff --git a/ios/include/FilamentViewer.hpp b/ios/include/FilamentViewer.hpp index 1583415a..4fdf018f 100644 --- a/ios/include/FilamentViewer.hpp +++ b/ios/include/FilamentViewer.hpp @@ -56,7 +56,7 @@ namespace polyvox { void loadIbl(const char* const iblUri, float intensity); void removeIbl(); - SceneAsset* loadGlb(const char* const uri); + SceneAsset* loadGlb(const char* const uri, bool unlit); SceneAsset* loadGltf(const char* const uri, const char* relativeResourcePath); void removeAsset(SceneAsset* asset); // removes all add assets from the current scene @@ -76,8 +76,9 @@ namespace polyvox { Renderer* getRenderer(); - void setBackgroundColor(const float* color); + void setBackgroundColor(const float r, const float g, const float b, const float a); void setBackgroundImage(const char* resourcePath); + void clearBackgroundImage(); void setBackgroundImagePosition(float x, float y, bool clamp); void setCameraExposure(float aperture, float shutterSpeed, float sensitivity); void setCameraPosition(float x, float y, float z); @@ -125,8 +126,8 @@ namespace polyvox { vector _assets; - AssetLoader* _assetLoader; - SceneAssetLoader* _sceneAssetLoader; + SceneAssetLoader* _ubershaderAssetLoader; + SceneAssetLoader* _unlitAssetLoader; NameComponentManager* _ncm; std::mutex mtx; // mutex to ensure thread safety when removing assets @@ -148,7 +149,9 @@ namespace polyvox { float _cameraFocalLength = 28.0f; float _cameraFocusDistance = 0.0f; - // these flags relate to the textured quad we use for rendering unlit background images + ColorGrading *colorGrading = nullptr; + + // background image properties uint32_t _imageHeight = 0; uint32_t _imageWidth = 0; mat4f _imageScale; @@ -158,12 +161,12 @@ namespace polyvox { IndexBuffer* _imageIb = nullptr; Material* _imageMaterial = nullptr; TextureSampler _imageSampler; - ColorGrading *colorGrading = nullptr; void loadKtx2Texture(string path, ResourceBuffer data); void loadKtxTexture(string path, ResourceBuffer data); void loadPngTexture(string path, ResourceBuffer data); void loadTextureFromPath(string path); - + + void _createManipulator(); uint32_t _lastFrameTimeInNanos; }; diff --git a/ios/include/PolyvoxFilamentApi.h b/ios/include/PolyvoxFilamentApi.h index b90e911c..644166be 100644 --- a/ios/include/PolyvoxFilamentApi.h +++ b/ios/include/PolyvoxFilamentApi.h @@ -26,11 +26,11 @@ typedef struct BoneAnimation BoneAnimation; void* filament_viewer_new(void* context, ResourceBuffer (*loadResource)(const char*), void (*freeResource)(uint32_t)); void filament_viewer_delete(void* viewer); void create_render_target(void* viewer, uint32_t textureId, uint32_t width, uint32_t height); +void clear_background_image(void* viewer); void set_background_image(void* viewer, const char* path); - -// color is rgba -void set_background_color(void* viewer, const float* color); void set_background_image_position(void* viewer, float x, float y, bool clamp); +void set_background_color(void* viewer, const float r, const float g, const float b, const float a); + void load_skybox(void* viewer, const char* skyboxPath); void load_ibl(void* viewer, const char* iblPath, float intensity); void remove_skybox(void* viewer); @@ -38,7 +38,7 @@ void remove_ibl(void* viewer); int32_t add_light(void* viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows); void remove_light(void* viewer, int32_t entityId); void clear_lights(void* viewer); -void* load_glb(void* viewer, const char* assetPath); +void* load_glb(void* viewer, const char* assetPath, bool unlit); void* load_gltf(void* viewer, const char* assetPath, const char* relativePath); bool set_camera(void* viewer, void* asset, const char* nodeName); void render(void* viewer, uint64_t frameTimeInNanos); diff --git a/ios/include/SceneAssetLoader.hpp b/ios/include/SceneAssetLoader.hpp index 2b9d2ca2..bf99af6a 100644 --- a/ios/include/SceneAssetLoader.hpp +++ b/ios/include/SceneAssetLoader.hpp @@ -20,23 +20,30 @@ namespace polyvox { SceneAssetLoader( LoadResource loadResource, FreeResource freeResource, - AssetLoader* assetLoader, + MaterialProvider* materialProvider, + EntityManager* entityManager, ResourceLoader* resourceLoader, NameComponentManager* ncm, Engine* engine, Scene* scene); + ~SceneAssetLoader(); SceneAsset* fromGltf(const char* uri, const char* relativeResourcePath); SceneAsset* fromGlb(const char* uri); void remove(SceneAsset* asset); + void destroyAll(); private: LoadResource _loadResource; FreeResource _freeResource; + MaterialProvider* _materialProvider; + EntityManager* _entityManager; AssetLoader* _assetLoader; ResourceLoader* _resourceLoader; NameComponentManager* _ncm; Engine* _engine; Scene* _scene; + vector _assets; + }; } diff --git a/ios/include/material/UnlitMaterialProvider.hpp b/ios/include/material/UnlitMaterialProvider.hpp index d47e045c..d0477b2c 100644 --- a/ios/include/material/UnlitMaterialProvider.hpp +++ b/ios/include/material/UnlitMaterialProvider.hpp @@ -6,8 +6,11 @@ namespace polyvox { const Material* _m; const Material* _ms[1]; + const Engine* _engine; + public: UnlitMaterialProvider(Engine* engine) { + _engine = engine; _m = Material::Builder() .package( UNLIT_OPAQUE_UNLIT_OPAQUE_DATA, UNLIT_OPAQUE_UNLIT_OPAQUE_SIZE) .build(*engine); @@ -35,11 +38,11 @@ namespace polyvox { } void destroyMaterials() { - + // TODO - do we need to do anything here? } bool needsDummyData(filament::VertexAttribute attrib) const noexcept { - return true; + return false; } }; } diff --git a/ios/lib/libpng16.a b/ios/lib/libpng16.a index ff6f28b9..f6ea7819 100644 --- a/ios/lib/libpng16.a +++ b/ios/lib/libpng16.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4ce6e725e4beb9d7cd494f24b2bd4608de06b5dcc7290d07c8a6f3668cec6ec -size 905232 +oid sha256:6f40a337ca4ae110bbfee332e03ee496b0f3706b6b9d264a44f3c248733f4f23 +size 376488 diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index 9a2124ad..3b08af7a 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -106,14 +106,12 @@ struct Vertex { uint32_t color; }; -// static const Vertex TRIANGLE_VERTICES[3] = { -// {{1, 0}, 0xffff0000u}, -// {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, -// {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, -// }; - -// static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 }; +static constexpr float4 sFullScreenTriangleVertices[3] = { + { -1.0f, -1.0f, 1.0f, 1.0f }, + { 3.0f, -1.0f, 1.0f, 1.0f }, + { -1.0f, 3.0f, 1.0f, 1.0f } }; +static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2}; FilamentViewer::FilamentViewer(void* context, LoadResource loadResource, FreeResource freeResource) @@ -196,34 +194,85 @@ FilamentViewer::FilamentViewer(void* context, LoadResource loadResource, _unlitProvider = new UnlitMaterialProvider(_engine); _ubershaderProvider = gltfio::createUbershaderProvider( _engine, UBERARCHIVE_DEFAULT_DATA, UBERARCHIVE_DEFAULT_SIZE); - Log("Created material provider"); EntityManager &em = EntityManager::get(); _ncm = new NameComponentManager(em); - _assetLoader = AssetLoader::create({_engine, _ubershaderProvider, _ncm, &em}); _resourceLoader = new ResourceLoader({.engine = _engine, .normalizeSkinningWeights = true }); _stbDecoder = createStbProvider(_engine); _resourceLoader->addTextureProvider("image/png", _stbDecoder); _resourceLoader->addTextureProvider("image/jpeg", _stbDecoder); - _sceneAssetLoader = new SceneAssetLoader(_loadResource, + _ubershaderAssetLoader = new SceneAssetLoader(_loadResource, _freeResource, - _assetLoader, + _ubershaderProvider, + &em, _resourceLoader, _ncm, _engine, _scene); + _unlitAssetLoader = new SceneAssetLoader(_loadResource, + _freeResource, + _unlitProvider, + &em, + _resourceLoader, + + _ncm, + _engine, + _scene); + + + _imageTexture = Texture::Builder() + .width(1) + .height(1) + .levels(0x01) + .format(Texture::InternalFormat::RGB16F) + .sampler(Texture::Sampler::SAMPLER_2D) + .build(*_engine); + + _imageMaterial = + Material::Builder() + .package(IMAGE_PACKAGE, IMAGE_IMAGE_SIZE) + .build(*_engine); + _imageMaterial->setDefaultParameter("showImage",0); + _imageMaterial->setDefaultParameter("backgroundColor", RgbType::sRGB, float3(0.f)); + _imageMaterial->setDefaultParameter("image", _imageTexture, _imageSampler); + _imageScale = mat4f { 1.0f , 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; + + _imageMaterial->setDefaultParameter("transform", _imageScale); + + _imageVb = VertexBuffer::Builder() + .vertexCount(3) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, + VertexBuffer::AttributeType::FLOAT4, 0) + .build(*_engine); + + _imageVb->setBufferAt( + *_engine, 0, + {sFullScreenTriangleVertices, sizeof(sFullScreenTriangleVertices)}); + + _imageIb = IndexBuffer::Builder() + .indexCount(3) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*_engine); + + _imageIb->setBuffer(*_engine, {sFullScreenTriangleIndices, + sizeof(sFullScreenTriangleIndices)}); + + Entity imageEntity = em.create(); + RenderableManager::Builder(1) + .boundingBox({{}, {1.0f, 1.0f, 1.0f}}) + .material(0, _imageMaterial->getDefaultInstance()) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, _imageVb, + _imageIb, 0, 3) + .culling(false) + .build(*_engine, imageEntity); + _imageEntity = &imageEntity; + _scene->addEntity(imageEntity); } -static constexpr float4 sFullScreenTriangleVertices[3] = { - { -1.0f, -1.0f, 1.0f, 1.0f }, - { 3.0f, -1.0f, 1.0f, 1.0f }, - { -1.0f, 3.0f, 1.0f, 1.0f } }; - -static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2}; - void FilamentViewer::setFrameInterval(float frameInterval) { Renderer::FrameRateOptions fro; fro.interval = frameInterval; @@ -260,52 +309,6 @@ void FilamentViewer::clearLights() { _lights.clear(); } -void FilamentViewer::createImageRenderable() { - - if (_imageEntity) - return; - - auto &em = EntityManager::get(); - - _imageMaterial = - Material::Builder() - .package(IMAGE_PACKAGE, IMAGE_IMAGE_SIZE) - .build(*_engine); - - _imageVb = VertexBuffer::Builder() - .vertexCount(3) - .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, - VertexBuffer::AttributeType::FLOAT4, 0) - .build(*_engine); - - _imageVb->setBufferAt( - *_engine, 0, - {sFullScreenTriangleVertices, sizeof(sFullScreenTriangleVertices)}); - - _imageIb = IndexBuffer::Builder() - .indexCount(3) - .bufferType(IndexBuffer::IndexType::USHORT) - .build(*_engine); - - _imageIb->setBuffer(*_engine, {sFullScreenTriangleIndices, - sizeof(sFullScreenTriangleIndices)}); - - Entity imageEntity = em.create(); - RenderableManager::Builder(1) - .boundingBox({{}, {1.0f, 1.0f, 1.0f}}) - .material(0, _imageMaterial->getDefaultInstance()) - .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, _imageVb, - _imageIb, 0, 3) - .culling(false) - .build(*_engine, imageEntity); - - _scene->addEntity(imageEntity); - - _imageEntity = &imageEntity; - -} - static bool endsWith(string path, string ending) { return path.compare(path.length() - ending.length(), ending.length(), ending) == 0; } @@ -367,7 +370,7 @@ void FilamentViewer::loadPngTexture(string path, ResourceBuffer rb) { _imageTexture = Texture::Builder() .width(_imageWidth) .height(_imageHeight) - .levels(0xff) + .levels(0x01) .format(channels == 3 ? Texture::InternalFormat::RGB16F : Texture::InternalFormat::RGBA16F) .sampler(Texture::Sampler::SAMPLER_2D) @@ -411,26 +414,32 @@ void FilamentViewer::loadTextureFromPath(string path) { } -void FilamentViewer::setBackgroundColor(const float* color) { +void FilamentViewer::setBackgroundColor(const float r, const float g, const float b, const float a) { _imageMaterial->setDefaultParameter("showImage", 0); - - _imageMaterial->setDefaultParameter("backgroundColor", RgbType::sRGB, float3(color[0], color[1], color[2])); + _imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(r, g, b, a)); + const Viewport& vp = _view->getViewport(); + Log("Image width %d height %d vp width %d height %d", _imageWidth, _imageHeight, vp.width, vp.height); + _imageMaterial->setDefaultParameter("transform", _imageScale); } +void FilamentViewer::clearBackgroundImage() { + _imageMaterial->setDefaultParameter("showImage", 0); + if (_imageTexture) { + Log("Destroying existing texture"); + _engine->destroy(_imageTexture); + Log("Destroyed."); + _imageTexture = nullptr; + } +} + + void FilamentViewer::setBackgroundImage(const char *resourcePath) { string resourcePathString(resourcePath); Log("Setting background image to %s", resourcePath); - createImageRenderable(); - - if (_imageTexture) { - Log("Destroying existing texture"); - _engine->destroy(_imageTexture); - Log("Destroyed."); - _imageTexture = nullptr; - } + clearBackgroundImage(); loadTextureFromPath(resourcePathString); @@ -442,11 +451,8 @@ void FilamentViewer::setBackgroundImage(const char *resourcePath) { _imageMaterial->setDefaultParameter("transform", _imageScale); _imageMaterial->setDefaultParameter("image", _imageTexture, _imageSampler); - _imageMaterial->setDefaultParameter("showImage", 1); - - _imageMaterial->setDefaultParameter("backgroundColor", RgbType::sRGB, - float3(0.f)); + } @@ -529,11 +535,12 @@ void FilamentViewer::setBackgroundImagePosition(float x, float y, bool clamp=fal FilamentViewer::~FilamentViewer() { clearAssets(); - delete _sceneAssetLoader; + delete _ubershaderAssetLoader; + delete _unlitAssetLoader; _resourceLoader->asyncCancelLoad(); _ubershaderProvider->destroyMaterials(); _unlitProvider->destroyMaterials(); - AssetLoader::destroy(&_assetLoader); + for(auto it : _lights) { _engine->destroy(it); } @@ -609,14 +616,20 @@ void FilamentViewer::destroySwapChain() { } } -SceneAsset *FilamentViewer::loadGlb(const char *const uri) { - SceneAsset *asset = _sceneAssetLoader->fromGlb(uri); +SceneAsset *FilamentViewer::loadGlb(const char *const uri, bool unlit) { + SceneAsset *asset; + if(unlit) { + asset = _unlitAssetLoader->fromGlb(uri); + } else { + asset = _ubershaderAssetLoader->fromGlb(uri); + } if (!asset) { Log("Unknown error loading asset."); } else { _assets.push_back(asset); Log("GLB loaded, asset at index %d", _assets.size() - 1); } + return asset; } @@ -624,7 +637,7 @@ SceneAsset *FilamentViewer::loadGltf(const char *const uri, const char *const relativeResourcePath) { Log("Loading GLTF at URI %s with relativeResourcePath %s", uri, relativeResourcePath); - SceneAsset *asset = _sceneAssetLoader->fromGltf(uri, relativeResourcePath); + SceneAsset *asset = _ubershaderAssetLoader->fromGltf(uri, relativeResourcePath); if (!asset) { Log("Unknown error loading asset."); } else { @@ -633,7 +646,6 @@ SceneAsset *FilamentViewer::loadGltf(const char *const uri, return asset; } - void FilamentViewer::clearAssets() { Log("Clearing all assets"); if(_mainCamera) { @@ -644,13 +656,10 @@ void FilamentViewer::clearAssets() { delete _manipulator; _manipulator = nullptr; } + + _ubershaderAssetLoader->destroyAll(); + _unlitAssetLoader->destroyAll(); - int i = 0; - for (auto asset : _assets) { - _sceneAssetLoader->remove(asset); - Log("Cleared asset %d", i); - i++; - } _assets.clear(); Log("Cleared all assets"); } @@ -661,19 +670,8 @@ void FilamentViewer::removeAsset(SceneAsset *asset) { mtx.lock(); // todo - what if we are using a camera from this asset? _view->setCamera(_mainCamera); - _sceneAssetLoader->remove(asset); - - bool erased = false; - for (auto it = _assets.begin(); it != _assets.end();++it) { - if (*it == asset) { - _assets.erase(it); - erased = true; - break; - } - } - if (!erased) { - Log("Error removing asset from scene : not found"); - } + _ubershaderAssetLoader->remove(asset); + _unlitAssetLoader->remove(asset); mtx.unlock(); } diff --git a/ios/src/PolyvoxFilamentApi.cpp b/ios/src/PolyvoxFilamentApi.cpp index 93b1507f..103556c9 100644 --- a/ios/src/PolyvoxFilamentApi.cpp +++ b/ios/src/PolyvoxFilamentApi.cpp @@ -23,8 +23,12 @@ extern "C" { delete((FilamentViewer*)viewer); } - void set_background_color(void* viewer, const float* color) { - ((FilamentViewer*)viewer)->setBackgroundColor(color); + void set_background_color(void* viewer, const float r, const float g, const float b, const float a) { + ((FilamentViewer*)viewer)->setBackgroundColor(r, g, b, a); + } + + void clear_background_image(void* viewer) { + ((FilamentViewer*)viewer)->clearBackgroundImage(); } void set_background_image(void* viewer, const char* path) { @@ -63,8 +67,8 @@ extern "C" { ((FilamentViewer*)viewer)->clearLights(); } - void* load_glb(void* viewer, const char* assetPath) { - return ((FilamentViewer*)viewer)->loadGlb(assetPath); + void* load_glb(void* viewer, const char* assetPath, bool unlit) { + return ((FilamentViewer*)viewer)->loadGlb(assetPath, unlit); } void* load_gltf(void* viewer, const char* assetPath, const char* relativePath) { diff --git a/ios/src/SceneAssetLoader.cpp b/ios/src/SceneAssetLoader.cpp index 4c030a84..9f15e360 100644 --- a/ios/src/SceneAssetLoader.cpp +++ b/ios/src/SceneAssetLoader.cpp @@ -10,14 +10,22 @@ using namespace filament::gltfio; SceneAssetLoader::SceneAssetLoader(LoadResource loadResource, FreeResource freeResource, - AssetLoader *assetLoader, + MaterialProvider* materialProvider, + EntityManager* entityManager, ResourceLoader *resourceLoader, NameComponentManager *ncm, Engine *engine, Scene *scene) - : _loadResource(loadResource), _freeResource(freeResource), - _assetLoader(assetLoader), _resourceLoader(resourceLoader), _ncm(ncm), - _engine(engine), _scene(scene) {} + : _loadResource(loadResource), _freeResource(freeResource), _materialProvider(materialProvider), _entityManager(entityManager), + _resourceLoader(resourceLoader), _ncm(ncm), + _engine(engine), _scene(scene) { + _assetLoader = AssetLoader::create({_engine, materialProvider, _ncm, entityManager}); + } + +SceneAssetLoader::~SceneAssetLoader() { + destroyAll(); + AssetLoader::destroy(&_assetLoader); +} SceneAsset *SceneAssetLoader::fromGltf(const char *uri, const char *relativeResourcePath) { @@ -87,6 +95,7 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) { FilamentAsset *asset = _assetLoader->createAsset( (const uint8_t *)rbuf.data, rbuf.size); + if (!asset) { Log("Unknown error loading GLB asset."); return nullptr; @@ -105,12 +114,18 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) { const Entity *entities = asset->getEntities(); RenderableManager &rm = _engine->getRenderableManager(); + + MaterialKey config; + auto mi_new = _materialProvider->createMaterialInstance(&config, nullptr); // why did I need to explicitly enable culling? for (int i = 0; i < asset->getEntityCount(); i++) { - auto entityInstance = rm.getInstance(entities[i]); - rm.setCulling(entityInstance, true); - } + auto entityInstance = rm.getInstance(entities[i]); + auto mi = rm.getMaterialInstanceAt(entityInstance, 0); + // auto m = mi->getMaterial(); + // auto shading = m->getShading(); + // Log("Shading %d", shading); + } auto lights = asset->getLightEntities(); _scene->addEntities(lights, asset->getLightEntityCount()); @@ -118,6 +133,8 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) { Log("Added %d lights to scene from asset", asset->getLightEntityCount()); FilamentInstance* inst = asset->getInstance(); + + inst->getAnimator()->updateBoneMatrices(); inst->recomputeBoundingBoxes(); @@ -128,10 +145,43 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) { _freeResource(rbuf.id); Log("Successfully loaded GLB."); - return new SceneAsset(asset, _engine, _ncm, _loadResource, _freeResource); + SceneAsset* sceneAsset = new SceneAsset(asset, _engine, _ncm, _loadResource, _freeResource); + _assets.push_back(sceneAsset); + + + + + return sceneAsset; +} + +void SceneAssetLoader::destroyAll() { + for (auto asset : _assets) { + _scene->removeEntities(asset->_asset->getEntities(), + asset->_asset->getEntityCount()); + + _scene->removeEntities(asset->getLightEntities(), + asset->getLightEntityCount()); + + _resourceLoader->evictResourceData(); + _assetLoader->destroyAsset(asset->_asset); + delete asset; + } + _assets.clear(); } void SceneAssetLoader::remove(SceneAsset *asset) { + bool erased = false; + for (auto it = _assets.begin(); it != _assets.end();++it) { + if (*it == asset) { + _assets.erase(it); + erased = true; + break; + } + } + if (!erased) { + Log("Error removing asset from scene : not found"); + return; + } Log("Removing asset and all associated entities/lights."); diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index d570b337..122b5f30 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -1,12 +1,12 @@ import 'dart:async'; import 'dart:typed_data'; import 'dart:ui'; + +import 'package:flutter/services.dart'; + import 'animations/animation_builder.dart'; import 'animations/animations.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; - // this is confusing - "FilamentAsset" actually defines a pointer to a SceneAsset, whereas FilamentLight is an Entity ID. // should make this consistent typedef FilamentAsset = int; @@ -26,11 +26,12 @@ abstract class FilamentController { void setPixelRatio(double ratio); Future resize(int width, int height, {double contentScaleFactor = 1}); Future setBackgroundColor(Color color); + Future clearBackgroundImage(); Future setBackgroundImage(String path); Future setBackgroundImagePosition(double x, double y, {bool clamp = false}); Future loadSkybox(String skyboxPath); Future removeSkybox(); - Future loadIbl(String path); + Future loadIbl(String path, {double intensity = 30000}); Future removeIbl(); // copied from LightManager.h @@ -54,7 +55,7 @@ abstract class FilamentController { bool castShadows); Future removeLight(FilamentLight light); Future clearLights(); - Future loadGlb(String path); + Future loadGlb(String path, {bool unlit = false}); Future loadGltf(String path, String relativeResourcePath); Future zoomBegin(); Future zoomUpdate(double z); @@ -172,6 +173,11 @@ class PolyvoxFilamentController extends FilamentController { _textureIdController.add(_textureId); } + @override + Future clearBackgroundImage() async { + await _channel.invokeMethod("clearBackgroundImage"); + } + @override Future setBackgroundImage(String path) async { await _channel.invokeMethod("setBackgroundImage", path); @@ -179,15 +185,12 @@ class PolyvoxFilamentController extends FilamentController { @override Future setBackgroundColor(Color color) async { - print( - "setting to ${color.red.toDouble() / 255.0} ${color.blue.toDouble() / 255.0} ${color.red.toDouble() / 255.0}"); - await _channel.invokeMethod( - "setBackgroundColor", - Float32List.fromList([ - color.red.toDouble() / 255.0, - color.green.toDouble() / 255.0, - color.blue.toDouble() / 255.0 - ])); + await _channel.invokeMethod("setBackgroundColor", [ + color.red.toDouble() / 255.0, + color.green.toDouble() / 255.0, + color.blue.toDouble() / 255.0, + color.alpha.toDouble() / 255.0 + ]); } @override @@ -253,9 +256,9 @@ class PolyvoxFilamentController extends FilamentController { return _channel.invokeMethod("clearLights"); } - Future loadGlb(String path) async { + Future loadGlb(String path, {bool unlit = false}) async { print("Loading GLB at $path "); - var asset = await _channel.invokeMethod("loadGlb", path); + var asset = await _channel.invokeMethod("loadGlb", [path, unlit]); if (asset == FILAMENT_ASSET_ERROR) { throw Exception("An error occurred loading the asset at $path"); } diff --git a/lib/filament_gesture_detector.dart b/lib/filament_gesture_detector.dart index 8d64eb04..6d556e49 100644 --- a/lib/filament_gesture_detector.dart +++ b/lib/filament_gesture_detector.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -35,6 +36,7 @@ class _FilamentGestureDetectorState extends State { }; bool _rotating = false; + bool _scaling = false; // to avoid duplicating code for pan/rotate (panStart, panUpdate, panEnd, rotateStart, rotateUpdate etc) // we have only a single function for start/update/end. @@ -100,6 +102,8 @@ class _FilamentGestureDetectorState extends State { onScaleStart: !widget.enableControls ? null : (d) async { + _scaling = true; + print("SCALE START"); if (d.pointerCount == 2) { await widget.controller.zoomEnd(); await widget.controller.zoomBegin(); @@ -108,6 +112,7 @@ class _FilamentGestureDetectorState extends State { onScaleEnd: !widget.enableControls ? null : (d) async { + _scaling = false; if (d.pointerCount == 2) { _lastScale = 0; await widget.controller.zoomEnd(); @@ -118,8 +123,9 @@ class _FilamentGestureDetectorState extends State { : (d) async { if (d.pointerCount == 2) { if (_lastScale != 0) { - await widget.controller - .zoomUpdate(100 * (_lastScale - d.scale)); + await widget.controller.zoomUpdate(Platform.isIOS + ? 1000 * (_lastScale - d.scale) + : 100 * (_lastScale - d.scale)); } } _lastScale = d.scale; @@ -128,6 +134,8 @@ class _FilamentGestureDetectorState extends State { onPointerSignal: !widget.enableControls ? null : (pointerSignal) async { + print("ponter signal"); + // scroll-wheel zoom on desktop if (pointerSignal is PointerScrollEvent) { _scrollTimer?.cancel(); @@ -146,6 +154,7 @@ class _FilamentGestureDetectorState extends State { onPointerDown: !widget.enableControls ? null : (d) async { + print("piinterodoiwn"); if (d.buttons == kTertiaryButton || _rotating) { await widget.controller.rotateStart( d.localPosition.dx, d.localPosition.dy); @@ -157,6 +166,7 @@ class _FilamentGestureDetectorState extends State { onPointerMove: !widget.enableControls ? null : (d) async { + print("pointermove"); if (d.buttons == kTertiaryButton || _rotating) { await widget.controller.rotateUpdate( d.localPosition.dx, d.localPosition.dy); @@ -168,6 +178,7 @@ class _FilamentGestureDetectorState extends State { onPointerUp: !widget.enableControls ? null : (d) async { + print("pointerup"); if (d.buttons == kTertiaryButton || _rotating) { await widget.controller.rotateEnd(); } else { diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 39172418..d5c7dd19 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -17,7 +17,7 @@ set(PLUGIN_NAME "polyvox_filament_plugin") link_directories("${CMAKE_CURRENT_SOURCE_DIR}/lib") add_library(FILAMENT_SHADERS SHARED - "${CMAKE_CURRENT_SOURCE_DIR}/../ios/include/material/image_material.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../ios/include/material/image.c" "${CMAKE_CURRENT_SOURCE_DIR}/../ios/include/material/unlit_opaque.c" ) diff --git a/materials/unlit_opaque.mat b/materials/unlit_opaque.mat index ee10a303..1b0722cb 100644 --- a/materials/unlit_opaque.mat +++ b/materials/unlit_opaque.mat @@ -1,15 +1,178 @@ material { - name : BakedColor, - requires : [ - color - ], + name : unlit_opaque, + requires : [ uv0, uv1, color ], shadingModel : unlit, - culling : none + blending : ${BLENDING}, + doubleSided : ${DOUBLESIDED}, + transparency : ${TRANSPARENCY}, + flipUV : false, + specularAmbientOcclusion : simple, + specularAntiAliasing : true, + clearCoatIorChange : false, + reflections : screenspace, + parameters : [ + + { type : float3, name : specularFactor }, + { type : float, name : glossinessFactor }, + + // Base Color + { type : int, name : baseColorIndex }, + { type : float4, name : baseColorFactor }, + { type : sampler2d, name : baseColorMap }, + { type : mat3, name : baseColorUvMatrix, precision: high }, + + // Metallic-Roughness Map + { type : int, name : metallicRoughnessIndex }, + { type : float, name : metallicFactor }, + { type : float, name : roughnessFactor }, + { type : sampler2d, name : metallicRoughnessMap }, + { type : mat3, name : metallicRoughnessUvMatrix, precision: high }, + + // Normal Map + { type : int, name : normalIndex }, + { type : float, name : normalScale }, + { type : sampler2d, name : normalMap }, + { type : mat3, name : normalUvMatrix, precision: high }, + + // Ambient Occlusion + { type : int, name : aoIndex }, + { type : float, name : aoStrength }, + { type : sampler2d, name : occlusionMap }, + { type : mat3, name : occlusionUvMatrix, precision: high }, + + // Emissive Map + { type : int, name : emissiveIndex }, + { type : float3, name : emissiveFactor }, + { type : float, name : emissiveStrength }, + { type : sampler2d, name : emissiveMap }, + { type : mat3, name : emissiveUvMatrix, precision: high }, + + // Clear coat + { type : float, name : clearCoatFactor }, + { type : float, name : clearCoatRoughnessFactor }, + { type : int, name : clearCoatIndex }, + { type : sampler2d, name : clearCoatMap }, + { type : mat3, name : clearCoatUvMatrix, precision: high }, + { type : int, name : clearCoatRoughnessIndex }, + { type : sampler2d, name : clearCoatRoughnessMap }, + { type : mat3, name : clearCoatRoughnessUvMatrix, precision: high }, + { type : int, name : clearCoatNormalIndex }, + { type : sampler2d, name : clearCoatNormalMap }, + { type : mat3, name : clearCoatNormalUvMatrix, precision: high }, + { type : float, name : clearCoatNormalScale }, + + // Reflectance + { type : float, name : reflectance } + + ${CUSTOM_PARAMS} + ], +} + +vertex { + void materialVertex(inout MaterialVertexInputs material) { + ${CUSTOM_VERTEX} + } } fragment { void material(inout MaterialInputs material) { + highp float2 uvs[2]; + uvs[0] = getUV0(); + uvs[1] = getUV1(); + + #if !defined(SHADING_MODEL_UNLIT) + if (materialParams.normalIndex > -1) { + highp float2 uv = uvs[materialParams.normalIndex]; + uv = (vec3(uv, 1.0) * materialParams.normalUvMatrix).xy; + material.normal = texture(materialParams_normalMap, uv).xyz * 2.0 - 1.0; + material.normal.xy *= materialParams.normalScale; + } + #if defined(SHADING_MODEL_LIT) + if (materialParams.clearCoatNormalIndex > -1) { + highp float2 uv = uvs[materialParams.clearCoatNormalIndex]; + uv = (vec3(uv, 1.0) * materialParams.clearCoatNormalUvMatrix).xy; + material.clearCoatNormal = texture(materialParams_clearCoatNormalMap, uv).xyz * 2.0 - 1.0; + material.clearCoatNormal.xy *= materialParams.clearCoatNormalScale; + } + #endif + #endif + prepareMaterial(material); - material.baseColor = getColor(); + material.baseColor = materialParams.baseColorFactor; + + if (materialParams.baseColorIndex > -1) { + highp float2 uv = uvs[materialParams.baseColorIndex]; + uv = (vec3(uv, 1.0) * materialParams.baseColorUvMatrix).xy; + material.baseColor *= texture(materialParams_baseColorMap, uv); + } + + #if defined(BLEND_MODE_TRANSPARENT) + material.baseColor.rgb *= material.baseColor.a; + #endif + + material.baseColor *= getColor(); + + #if !defined(SHADING_MODEL_UNLIT) + + #if defined(SHADING_MODEL_LIT) + material.roughness = materialParams.roughnessFactor; + material.metallic = materialParams.metallicFactor; + + // KHR_materials_clearcoat forbids clear coat from + // being applied in the specular/glossiness model + material.clearCoat = materialParams.clearCoatFactor; + material.clearCoatRoughness = materialParams.clearCoatRoughnessFactor; + + if (materialParams.clearCoatIndex > -1) { + highp float2 uv = uvs[materialParams.clearCoatIndex]; + uv = (vec3(uv, 1.0) * materialParams.clearCoatUvMatrix).xy; + material.clearCoat *= texture(materialParams_clearCoatMap, uv).r; + } + if (materialParams.clearCoatRoughnessIndex > -1) { + highp float2 uv = uvs[materialParams.clearCoatRoughnessIndex]; + uv = (vec3(uv, 1.0) * materialParams.clearCoatRoughnessUvMatrix).xy; + material.clearCoatRoughness *= texture(materialParams_clearCoatRoughnessMap, uv).g; + } + #endif + + material.emissive = vec4(materialParams.emissiveStrength * + materialParams.emissiveFactor.rgb, 0.0); + + #if defined(SHADING_MODEL_SPECULAR_GLOSSINESS) + material.glossiness = materialParams.glossinessFactor; + material.specularColor = materialParams.specularFactor; + #else + material.reflectance = materialParams.reflectance; + #endif + + if (materialParams.metallicRoughnessIndex > -1) { + highp float2 uv = uvs[materialParams.metallicRoughnessIndex]; + uv = (vec3(uv, 1.0) * materialParams.metallicRoughnessUvMatrix).xy; + + #if defined(SHADING_MODEL_SPECULAR_GLOSSINESS) + vec4 sg = texture(materialParams_metallicRoughnessMap, uv); + material.specularColor *= sg.rgb; + material.glossiness *= sg.a; + #else + vec4 mr = texture(materialParams_metallicRoughnessMap, uv); + material.roughness *= mr.g; + material.metallic *= mr.b; + #endif + } + + if (materialParams.aoIndex > -1) { + highp float2 uv = uvs[materialParams.aoIndex]; + uv = (vec3(uv, 1.0) * materialParams.occlusionUvMatrix).xy; + float occlusion = texture(materialParams_occlusionMap, uv).r; + material.ambientOcclusion = 1.0 + materialParams.aoStrength * (occlusion - 1.0); + } + if (materialParams.emissiveIndex > -1) { + highp float2 uv = uvs[materialParams.emissiveIndex]; + uv = (vec3(uv, 1.0) * materialParams.emissiveUvMatrix).xy; + material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb; + } + #endif + + ${CUSTOM_FRAGMENT} } }