From 505cb39e1cc1ce163daef2402fb213dbaa6ec4e0 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Tue, 13 Jul 2021 11:24:13 -0700 Subject: [PATCH] Improvements to image_viewer (#4305) Image loading errors are handled more gracefully by showing a background color. Added UI to set the background color. Replaced fragment discards with solid background color. --- samples/image_viewer.cpp | 78 ++++++++++++++++++++++++++++--------- samples/materials/image.mat | 18 +++++++-- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/samples/image_viewer.cpp b/samples/image_viewer.cpp index f776344ce0..cded67676a 100644 --- a/samples/image_viewer.cpp +++ b/samples/image_viewer.cpp @@ -73,8 +73,13 @@ struct App { IndexBuffer* imageIndexBuffer = nullptr; Material* imageMaterial = nullptr; Texture* imageTexture = nullptr; + Texture* defaultTexture = nullptr; + TextureSampler sampler; } scene; + bool showImage = false; + float3 backgroundColor = float3(0.0f); + // zero-initialized so that the first time through is always dirty. ColorGradingSettings lastColorGradingOptions = { 0 }; @@ -195,9 +200,33 @@ static void createImageRenderable(Engine* engine, Scene* scene, App& app) { app.scene.imageVertexBuffer = vertexBuffer; app.scene.imageIndexBuffer = indexBuffer; app.scene.imageMaterial = material; + + Texture* texture = Texture::Builder() + .width(1) + .height(1) + .levels(1) + .format(Texture::InternalFormat::RGBA8) + .sampler(Texture::Sampler::SAMPLER_2D) + .build(*engine); + static uint32_t pixel = 0; + Texture::PixelBufferDescriptor buffer(&pixel, 4, Texture::Format::RGBA, Texture::Type::UBYTE); + texture->setImage(*engine, 0, std::move(buffer)); + + app.scene.defaultTexture = texture; } static void loadImage(App& app, Engine* engine, Path filename) { + if (app.scene.imageTexture) { + engine->destroy(app.scene.imageTexture); + app.scene.imageTexture = nullptr; + } + + if (!filename.exists()) { + std::cerr << "The input image does not exist: " << filename << std::endl; + app.showImage = false; + return; + } + std::ifstream inputStream(filename, std::ios::binary); LinearImage image = ImageDecoder::decode( inputStream, filename, ImageDecoder::ColorSpace::LINEAR); @@ -205,12 +234,14 @@ static void loadImage(App& app, Engine* engine, Path filename) { uint32_t channels = image.getChannels(); if (channels != 3) { std::cerr << "The input image is invalid: " << filename << std::endl; - exit(1); + app.showImage = false; + return; } if (!image.isValid()) { std::cerr << "The input image is invalid: " << filename << std::endl; - exit(1); + app.showImage = false; + return; } inputStream.close(); @@ -252,18 +283,13 @@ static void loadImage(App& app, Engine* engine, Path filename) { texture->setImage(*engine, 0, std::move(buffer)); texture->generateMipmaps(*engine); - TextureSampler sampler; - sampler.setMagFilter(TextureSampler::MagFilter::LINEAR); - sampler.setMinFilter(TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR); - sampler.setWrapModeS(TextureSampler::WrapMode::REPEAT); - sampler.setWrapModeT(TextureSampler::WrapMode::REPEAT); + app.scene.sampler.setMagFilter(TextureSampler::MagFilter::LINEAR); + app.scene.sampler.setMinFilter(TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR); + app.scene.sampler.setWrapModeS(TextureSampler::WrapMode::REPEAT); + app.scene.sampler.setWrapModeT(TextureSampler::WrapMode::REPEAT); - app.scene.imageMaterial->setDefaultParameter("image", texture, sampler); - - if (app.scene.imageTexture) { - engine->destroy(app.scene.imageTexture); - } app.scene.imageTexture = texture; + app.showImage = true; } int main(int argc, char** argv) { @@ -290,9 +316,13 @@ int main(int argc, char** argv) { createImageRenderable(engine, scene, app); - if (filename.exists()) { - loadImage(app, engine, filename); - } + loadImage(app, engine, filename); + + app.viewer->setUiCallback([&app] () { + if (ImGui::CollapsingHeader("Image", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::ColorEdit3("Background color", &app.backgroundColor.r); + } + }); }; auto cleanup = [&app](Engine* engine, View*, Scene*) { @@ -301,6 +331,7 @@ int main(int argc, char** argv) { engine->destroy(app.scene.imageIndexBuffer); engine->destroy(app.scene.imageMaterial); engine->destroy(app.scene.imageTexture); + engine->destroy(app.scene.defaultTexture); engine->destroy(app.colorGrading); delete app.viewer; @@ -334,7 +365,7 @@ int main(int argc, char** argv) { view->setColorGrading(nullptr); } - if (app.scene.imageTexture) { + if (app.showImage) { Texture *texture = app.scene.imageTexture; float srcWidth = texture->getWidth(); float srcHeight = texture->getHeight(); @@ -360,13 +391,22 @@ int main(int argc, char** argv) { } mat3f transform( - 1.0f / sx, 0.0f, 0.0f, - 0.0f, 1.0f / sy, 0.0f, - -tx, -ty, 1.0f + 1.0f / sx, 0.0f, 0.0f, + 0.0f, 1.0f / sy, 0.0f, + -tx, -ty, 1.0f ); app.scene.imageMaterial->setDefaultParameter("transform", transform); + app.scene.imageMaterial->setDefaultParameter( + "image", app.scene.imageTexture, app.scene.sampler); + } else { + app.scene.imageMaterial->setDefaultParameter( + "image", app.scene.defaultTexture, app.scene.sampler); } + + app.scene.imageMaterial->setDefaultParameter("showImage", app.showImage ? 1 : 0); + app.scene.imageMaterial->setDefaultParameter( + "backgroundColor", RgbType::sRGB, app.backgroundColor); }; FilamentApp& filamentApp = FilamentApp::get(); diff --git a/samples/materials/image.mat b/samples/materials/image.mat index 00d2c314a7..0ae9545a50 100644 --- a/samples/materials/image.mat +++ b/samples/materials/image.mat @@ -9,6 +9,14 @@ material { type : mat3, name : transform, precision : high + }, + { + type : float3, + name : backgroundColor + }, + { + type : int, + name : showImage } ], variables : [ @@ -32,9 +40,11 @@ fragment { prepareMaterial(material); highp vec2 uv = (materialParams.transform * vec3(saturate(variable_imageUV.st), 1.0)).st; - if (uv.s > 1.0 || uv.s < 0.0 || uv.t < 0.0 || uv.t > 1.0) discard; - uv.t = 1.0 - uv.t; - - material.baseColor = textureLod(materialParams_image, uv.st, 0.0); + if (materialParams.showImage == 0 || uv.s > 1.0 || uv.s < 0.0 || uv.t < 0.0 || uv.t > 1.0) { + material.baseColor = vec4(materialParams.backgroundColor, 1.0); + } else { + uv.t = 1.0 - uv.t; + material.baseColor = texture(materialParams_image, uv.st); + } } }