diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 4a1a9c7fa7..228c34804a 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,3 +7,5 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut + +- Add drag and drop support for IBL files for desktop gltf_viewer. diff --git a/android/filament-utils-android/src/main/cpp/Manipulator.cpp b/android/filament-utils-android/src/main/cpp/Manipulator.cpp index 22d471def2..84ac111e75 100644 --- a/android/filament-utils-android/src/main/cpp/Manipulator.cpp +++ b/android/filament-utils-android/src/main/cpp/Manipulator.cpp @@ -125,6 +125,11 @@ extern "C" JNIEXPORT void Java_com_google_android_filament_utils_Manipulator_nBu builder->groundPlane(a, b, c, d); } +extern "C" JNIEXPORT void Java_com_google_android_filament_utils_Manipulator_nBuilderPanning(JNIEnv*, jclass, jlong nativeBuilder, jboolean enabled) { + Builder* builder = (Builder*) nativeBuilder; + builder->panning(enabled); +} + extern "C" JNIEXPORT long Java_com_google_android_filament_utils_Manipulator_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder, jint mode) { Builder* builder = (Builder*) nativeBuilder; return (jlong) builder->build((Mode) mode); diff --git a/android/filament-utils-android/src/main/java/com/google/android/filament/utils/Manipulator.java b/android/filament-utils-android/src/main/java/com/google/android/filament/utils/Manipulator.java index 2c0ab85a14..548a6e6f8c 100644 --- a/android/filament-utils-android/src/main/java/com/google/android/filament/utils/Manipulator.java +++ b/android/filament-utils-android/src/main/java/com/google/android/filament/utils/Manipulator.java @@ -274,6 +274,17 @@ public class Manipulator { return this; } + /** + * Sets whether panning is enabled in the manipulator. + * + * @return this Builder object for chaining calls + */ + @NonNull + public Builder panning(Boolean enabled) { + nBuilderPanning(mNativeBuilder, enabled); + return this; + } + /** * Creates and returns the Manipulator object. * @@ -483,6 +494,7 @@ public class Manipulator { private static native void nBuilderFlightPanSpeed(long nativeBuilder, float x, float y); private static native void nBuilderFlightMoveDamping(long nativeBuilder, float damping); private static native void nBuilderGroundPlane(long nativeBuilder, float a, float b, float c, float d); + private static native void nBuilderPanning(long nativeBuilder, Boolean enabled); private static native long nBuilderBuild(long nativeBuilder, int mode); private static native void nDestroyManipulator(long nativeManip); diff --git a/filament/docs/SpirvDebugging.md b/filament/docs/SpirvDebugging.md index 42aad3aa9b..047fe3bc2a 100644 --- a/filament/docs/SpirvDebugging.md +++ b/filament/docs/SpirvDebugging.md @@ -64,14 +64,15 @@ First determine the Filament material and variant that causes the problem. What we want is the "raw" GLSL version of the shader, before any optimizations / cross-compilation happens. -The easiest way I've found to do this is by adding a `std::cout` statement inside `MaterialBuilder`, -right after `sg.createFragmentProgram` or `sg.createVertexProgram` is called. For example, +We can use the `--save-raw-variants` debug flag in matc to export each GLSL +shader to a file. For example: ``` -if (v.variant.key == 8u) { std::cout << shader << std::endl; } +matc --save-raw-variants --optimize-size --variant-filter fog,ssr,vsm,stereo \ + -a all -p all -o mymaterial.filamat mymaterial.mat ``` -Then, I invoke `matc` and redirect stdout to a .frag or .vert file. +Files will be named like `mymaterial_0x05.frag` or `mymaterial_0x05.vert`. Note that gltfio material "templates" first go through a build step. After building gltfio, the gltfio Filament materials are output to: diff --git a/libs/camutils/include/camutils/Manipulator.h b/libs/camutils/include/camutils/Manipulator.h index 2cc8a4da03..5ea49eaf5a 100644 --- a/libs/camutils/include/camutils/Manipulator.h +++ b/libs/camutils/include/camutils/Manipulator.h @@ -109,6 +109,7 @@ public: vec4 groundPlane; RayCallback raycastCallback; void* raycastUserdata; + bool panning = true; }; struct Builder { @@ -143,6 +144,8 @@ public: Builder& groundPlane(FLOAT a, FLOAT b, FLOAT c, FLOAT d); //! Plane equation used as a raycast fallback Builder& raycastCallback(RayCallback cb, void* userdata); //! Raycast function for accurate grab-and-pan + Builder& panning(bool enabled); //! Sets whether panning is enabled + /** * Creates a new camera manipulator, either ORBIT, MAP, or FREE_FLIGHT. * diff --git a/libs/camutils/src/Manipulator.cpp b/libs/camutils/src/Manipulator.cpp index d44528cd50..897d75c6d1 100644 --- a/libs/camutils/src/Manipulator.cpp +++ b/libs/camutils/src/Manipulator.cpp @@ -144,6 +144,14 @@ Manipulator::Builder& Manipulator::Builder::raycastCallback(RayCal return *this; } + + +template typename +Manipulator::Builder& Manipulator::Builder::panning(bool enabled) { + details.panning = enabled; + return *this; +} + template Manipulator* Manipulator::Builder::build(Mode mode) { switch (mode) { diff --git a/libs/camutils/src/OrbitManipulator.h b/libs/camutils/src/OrbitManipulator.h index 54e325cc3b..f89b7ada03 100644 --- a/libs/camutils/src/OrbitManipulator.h +++ b/libs/camutils/src/OrbitManipulator.h @@ -69,7 +69,7 @@ public: } void grabBegin(int x, int y, bool strafe) override { - mGrabState = strafe ? PANNING : ORBITING; + mGrabState = strafe && Base::mProps.panning ? PANNING : ORBITING; mGrabPivot = mPivot; mGrabEye = Base::mEye; mGrabTarget = Base::mTarget; diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index c3045b942b..2587adba65 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -134,6 +134,7 @@ protected: TargetApi mTargetApi = (TargetApi) 0; Optimization mOptimization = Optimization::PERFORMANCE; bool mPrintShaders = false; + bool mSaveRawVariants = false; bool mGenerateDebugInfo = false; bool mIncludeEssl1 = true; utils::bitset32 mShaderModels; @@ -586,6 +587,14 @@ public: //! If true, will output the generated GLSL shader code to stdout. MaterialBuilder& printShaders(bool printShaders) noexcept; + /** + * If true, this will write the raw generated GLSL for each variant to a text file in the + * current directory. The file will be named after the material name and the variant name. Its + * extension will be derived from the shader stage. For example, mymaterial_0x0e.frag, + * mymaterial_0x18.vert, etc. + */ + MaterialBuilder& saveRawVariants(bool saveVariants) noexcept; + //! If true, will include debugging information in generated SPIRV. MaterialBuilder& generateDebugInfo(bool generateDebugInfo) noexcept; diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 5fe3dd303f..f30b2df028 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -65,11 +65,11 @@ #include #include #include +#include #include #include - namespace filamat { using namespace utils; @@ -558,6 +558,11 @@ MaterialBuilder& MaterialBuilder::printShaders(bool printShaders) noexcept { return *this; } +MaterialBuilder& MaterialBuilder::saveRawVariants(bool saveRawVariants) noexcept { + mSaveRawVariants = saveRawVariants; + return *this; +} + MaterialBuilder& MaterialBuilder::generateDebugInfo(bool generateDebugInfo) noexcept { mGenerateDebugInfo = generateDebugInfo; return *this; @@ -931,6 +936,30 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vectorgetSkybox()->setLayerMask(0x7, 0x4); - mScene->setSkybox(mIBL->getSkybox()); - mScene->setIndirectLight(mIBL->getIndirectLight()); - } for (auto& view : window->mViews) { if (view.get() != window->mUiView) { @@ -519,31 +514,41 @@ const utils::Path& FilamentApp::getRootAssetsPath() { return root; } -void FilamentApp::loadIBL(const Config& config) { - if (!config.iblDirectory.empty()) { - Path iblPath(config.iblDirectory); +void FilamentApp::loadIBL(std::string_view path) { + Path iblPath(path); + if (!iblPath.exists()) { + std::cerr << "The specified IBL path does not exist: " << iblPath << std::endl; + return; + } - if (!iblPath.exists()) { - std::cerr << "The specified IBL path does not exist: " << iblPath << std::endl; + mIBL = std::make_unique(*mEngine); + + if (!iblPath.isDirectory()) { + if (!mIBL->loadFromEquirect(iblPath)) { + std::cerr << "Could not load the specified IBL: " << iblPath << std::endl; + mIBL.reset(nullptr); return; } - - mIBL = std::make_unique(*mEngine); - - if (!iblPath.isDirectory()) { - if (!mIBL->loadFromEquirect(iblPath)) { - std::cerr << "Could not load the specified IBL: " << iblPath << std::endl; - mIBL.reset(nullptr); - return; - } - } else { - if (!mIBL->loadFromDirectory(iblPath)) { - std::cerr << "Could not load the specified IBL: " << iblPath << std::endl; - mIBL.reset(nullptr); - return; - } + } else { + if (!mIBL->loadFromDirectory(iblPath)) { + std::cerr << "Could not load the specified IBL: " << iblPath << std::endl; + mIBL.reset(nullptr); + return; } } + + if (mIBL != nullptr) { + mIBL->getSkybox()->setLayerMask(0x7, 0x4); + mScene->setSkybox(mIBL->getSkybox()); + mScene->setIndirectLight(mIBL->getIndirectLight()); + } +} + +void FilamentApp::loadIBL(const Config& config) { + if (config.iblDirectory.empty()) { + return; + } + loadIBL(config.iblDirectory); } void FilamentApp::loadDirt(const Config& config) { diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index 340391ec26..d3481c485d 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -58,6 +58,7 @@ #include +#include #include #include #include @@ -508,30 +509,55 @@ static void onClick(App& app, View* view, ImVec2 pos) { }); } -static utils::Path getPathForAsset(std::string_view string) { +static utils::Path getPathForIBLAsset(std::string_view string) { + auto isIBL = [] (utils::Path file) -> bool { + return file.getExtension() == "ktx" || file.getExtension() == "hdr"; + }; + utils::Path filename{ string }; if (!filename.exists()) { std::cerr << "file " << filename << " not found!" << std::endl; return {}; } + if (filename.isDirectory()) { - auto files = filename.listContents(); - for (const auto& file: files) { - if (file.getExtension() == "gltf" || file.getExtension() == "glb") { - filename = file; - break; - } - } - if (filename.isDirectory()) { - std::cerr << "no glTF file found in " << filename << std::endl; + std::vector files = filename.listContents(); + if (std::none_of(files.cbegin(), files.cend(), isIBL)) { return {}; } + } else if (!isIBL(filename)) { + return {}; } + return filename; } +static utils::Path getPathForGLTFAsset(std::string_view string) { + auto isGLTF = [] (utils::Path file) -> bool { + return file.getExtension() == "gltf" || file.getExtension() == "glb"; + }; -static bool checkAsset(const utils::Path& filename) { + utils::Path filename{ string }; + if (!filename.exists()) { + std::cerr << "file " << filename << " not found!" << std::endl; + return {}; + } + + if (filename.isDirectory()) { + std::vector files = filename.listContents(); + auto it = std::find_if(files.cbegin(), files.cend(), isGLTF); + if (it == files.end()) { + return {}; + } + filename = *it; + } else if (!isGLTF(filename)) { + return {}; + } + + return filename; +} + +static bool checkGLTFAsset(const utils::Path& filename) { // Peek at the file size to allow pre-allocation. long const contentSize = static_cast(getFileSize(filename.c_str())); if (contentSize <= 0) { @@ -571,8 +597,9 @@ int main(int argc, char** argv) { utils::Path filename; int const num_args = argc - optionIndex; if (num_args >= 1) { - filename = getPathForAsset(argv[optionIndex]); + filename = getPathForGLTFAsset(argv[optionIndex]); if (filename.isEmpty()) { + std::cerr << "no glTF file found in " << filename << std::endl; return 1; } } @@ -1125,9 +1152,9 @@ int main(int argc, char** argv) { filamentApp.resize(resize); filamentApp.setDropHandler([&](std::string_view path) { - utils::Path const filename = getPathForAsset(path); + utils::Path filename = getPathForGLTFAsset(path); if (!filename.isEmpty()) { - if (checkAsset(filename)) { + if (checkGLTFAsset(filename)) { app.resourceLoader->asyncCancelLoad(); app.resourceLoader->evictResourceData(); app.viewer->removeAsset(); @@ -1136,6 +1163,13 @@ int main(int argc, char** argv) { loadResources(filename); app.viewer->setAsset(app.asset, app.instance); } + return; + } + + filename = getPathForIBLAsset(path); + if (!filename.isEmpty()) { + FilamentApp::get().loadIBL(path); + return; } }); diff --git a/tools/matc/src/matc/CommandlineConfig.cpp b/tools/matc/src/matc/CommandlineConfig.cpp index 64850c436e..6ca63158c6 100644 --- a/tools/matc/src/matc/CommandlineConfig.cpp +++ b/tools/matc/src/matc/CommandlineConfig.cpp @@ -103,6 +103,8 @@ static void usage(char* name) { " Skip validation of number of sampler used\n\n" " --print, -t\n" " Print generated shaders for debugging\n\n" + " --save-raw-variants, -R\n" + " Write the raw generated GLSL for each variant to a text file in the current directory.\n\n" ); const std::string from("MATC"); for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) { @@ -179,7 +181,7 @@ static void parseDefine(std::string defineString, Config::StringReplacementMap& } bool CommandlineConfig::parse() { - static constexpr const char* OPTSTR = "hLxo:f:dm:a:l:p:D:T:P:OSEr:vV:gtwF1"; + static constexpr const char* OPTSTR = "hLxo:f:dm:a:l:p:D:T:P:OSEr:vV:gtwF1R"; static const struct option OPTIONS[] = { { "help", no_argument, nullptr, 'h' }, { "license", no_argument, nullptr, 'L' }, @@ -204,6 +206,7 @@ bool CommandlineConfig::parse() { { "version", no_argument, nullptr, 'v' }, { "raw", no_argument, nullptr, 'w' }, { "no-sampler-validation", no_argument, nullptr, 'F' }, + { "save-raw-variants", no_argument, nullptr, 'R' }, { nullptr, 0, nullptr, 0 } // termination of the option list }; @@ -326,6 +329,8 @@ bool CommandlineConfig::parse() { break; case 'F': mNoSamplerValidation = true; + case 'R': + mSaveRawVariants = true; break; } } diff --git a/tools/matc/src/matc/Config.h b/tools/matc/src/matc/Config.h index 275799e081..d04be8da3d 100644 --- a/tools/matc/src/matc/Config.h +++ b/tools/matc/src/matc/Config.h @@ -111,6 +111,10 @@ public: return mPrintShaders; } + bool saveRawVariants() const noexcept { + return mSaveRawVariants; + } + bool rawShaderMode() const noexcept { return mRawShaderMode; } @@ -149,6 +153,7 @@ protected: bool mPrintShaders = false; bool mRawShaderMode = false; bool mNoSamplerValidation = false; + bool mSaveRawVariants = false; Optimization mOptimizationLevel = Optimization::PERFORMANCE; Metadata mReflectionTarget = Metadata::NONE; Platform mPlatform = Platform::ALL; diff --git a/tools/matc/src/matc/MaterialCompiler.cpp b/tools/matc/src/matc/MaterialCompiler.cpp index c528326aee..e1b22f97e6 100644 --- a/tools/matc/src/matc/MaterialCompiler.cpp +++ b/tools/matc/src/matc/MaterialCompiler.cpp @@ -408,6 +408,7 @@ bool MaterialCompiler::run(const Config& config) { .targetApi(config.getTargetApi()) .optimization(config.getOptimizationLevel()) .printShaders(config.printShaders()) + .saveRawVariants(config.saveRawVariants()) .generateDebugInfo(config.isDebug()) .variantFilter(config.getVariantFilter() | builder.getVariantFilter());