From 17d1ad77255f40100a80535a61683b9cd869d773 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Fri, 30 Dec 2022 16:50:52 -0800 Subject: [PATCH] [Impeller Scene] Import materials, load embedded textures (#38577) --- impeller/aiks/aiks_unittests.cc | 14 +- impeller/fixtures/BUILD.gn | 5 +- impeller/fixtures/flutter_logo.glb | Bin 18656 -> 0 bytes ..._logo_baked.png => flutter_logo_baked.glb} | Bin 269210 -> 288244 bytes impeller/playground/playground.cc | 62 +++++---- impeller/playground/playground.h | 17 ++- impeller/scene/BUILD.gn | 1 + impeller/scene/importer/BUILD.gn | 17 ++- impeller/scene/importer/conversions.cc | 8 ++ impeller/scene/importer/conversions.h | 3 + impeller/scene/importer/importer_gltf.cc | 131 ++++++++++++++---- impeller/scene/importer/importer_unittests.cc | 3 +- impeller/scene/importer/scene.fbs | 28 +++- impeller/scene/material.cc | 126 ++++++++++++++--- impeller/scene/material.h | 40 ++++-- impeller/scene/node.cc | 114 ++++++++++++++- impeller/scene/node.h | 7 +- impeller/scene/scene_unittests.cc | 16 +-- 18 files changed, 463 insertions(+), 129 deletions(-) delete mode 100644 impeller/fixtures/flutter_logo.glb rename impeller/fixtures/{flutter_logo_baked.png => flutter_logo_baked.glb} (93%) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index d64965857610b..3a501cc532151 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -1708,25 +1708,13 @@ TEST_P(AiksTest, SaveLayerFiltersScaleWithTransform) { TEST_P(AiksTest, SceneColorSource) { // Load up the scene. auto mapping = - flutter::testing::OpenFixtureAsMapping("flutter_logo.glb.ipscene"); + flutter::testing::OpenFixtureAsMapping("flutter_logo_baked.glb.ipscene"); ASSERT_NE(mapping, nullptr); std::shared_ptr gltf_scene = scene::Node::MakeFromFlatbuffer( *mapping, *GetContext()->GetResourceAllocator()); ASSERT_NE(gltf_scene, nullptr); - // Assign a material (temporary stopgap). - std::shared_ptr material = scene::Material::MakeUnlit(); - auto color_baked = CreateTextureForFixture("flutter_logo_baked.png"); - ASSERT_NE(color_baked, nullptr); - material->SetColorTexture(std::move(color_baked)); - material->SetVertexColorWeight(0); - - ASSERT_EQ(gltf_scene->GetChildren().size(), 1u); - ASSERT_EQ(gltf_scene->GetChildren()[0]->GetMesh().GetPrimitives().size(), 1u); - gltf_scene->GetChildren()[0]->GetMesh().GetPrimitives()[0].material = - std::move(material); - auto callback = [&](AiksContext& renderer, RenderTarget& render_target) { Paint paint; diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index 7c8fe01a79e2f..f91c66ef7f11b 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -35,7 +35,7 @@ impeller_shaders("shader_fixtures") { scenec("scene_fixtures") { geometry = [ - "flutter_logo.glb", + "flutter_logo_baked.glb", "two_triangles.glb", ] type = "gltf" @@ -61,8 +61,7 @@ test_fixtures("file_fixtures") { "blue_noise.png", "boston.jpg", "embarcadero.jpg", - "flutter_logo.glb", - "flutter_logo_baked.png", + "flutter_logo_baked.glb", "kalimba.jpg", "multiple_stages.hlsl", "resources_limit.vert", diff --git a/impeller/fixtures/flutter_logo.glb b/impeller/fixtures/flutter_logo.glb deleted file mode 100644 index 8a320e662e9633cbc776b03a7542f4cff664da00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18656 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 AHm7qIN*r zq4p3{PZR<)1ckwF^+LfwgHaFI$p{n*G!*rQsQaUVKnJ41u)BlM0H6aThTTTxK+Dlh$e_EZ3}_jQ zRiFpx5zt5I31nXtssvhz9zxDNhWVl3K{za`VY`PK^}jD{v)(6kkNGrY1BY#q*04BG!RgvQ3rXi3HUo;4UHC% z%es(nm%M^OUPI| zXdNIcTZ4!8(Ci@tBO%keLkowWevpOX(7HiJb%)H1hBgK=t`}r&EVLnzMbVIH@z5qf zmW_feOoKKSyu?FxMM4_{*_sNO7X_^^JQ;>U=5~VC8GeR?htALfU zlOE85;3*V`5`ZS4uJDrpp1VQ|1W$g*AE-an#9*KVD1k_4L2fPqx&-n!7xH!?(1noS zt07PMEL{nCx)ySH5zs}Dqcb5NOMsR@p3eum8R%xPFM^yc09pWfx)t&{4`?1prhtz^ zpoM5E{1k%LRA|}YWg40ebUNg7G0+^KIbfdwv;PeAXOx8|L%l2px)`2$GvHY|3FsuK zwK+g10-XqPY=^u)0rUja!EVTB1yBXlz+uScD?qP6z8{AiJ_Ga&NKQlk-T`_Ca{MCX z?RB8nL2?aht9dILY7AXDE! zdj_Mmkd+^xeSx1k$WcB|Kf>sJ$oyJpkdzu#P!$>)_aIZRg0zvwRcJS$k~AS}Z^Gy` zm|;6qbOp2rP(7s(-9u>iV6{)7Y7Rl8P{GwOqY~O-nBg>3>qltcpkmI#>c2vJkK7>l zZGqY%59A5Y-j+aH!n;WdIc@;d0J*}C0aSx4G#ONjGm-$6zJ86l2cUAGa;S$E;M*CfGuUk1(t+E$WefZr>5qTee<1i{+mARK{+{s1zij?*aSgTq E19OsUdH?_b diff --git a/impeller/fixtures/flutter_logo_baked.png b/impeller/fixtures/flutter_logo_baked.glb similarity index 93% rename from impeller/fixtures/flutter_logo_baked.png rename to impeller/fixtures/flutter_logo_baked.glb index fe8477286e8fc7e8f48cc65cbaa5e39b0cf33f9f..f786be69b36e859054ccab65c4028e4302927aa0 100644 GIT binary patch delta 19202 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 C4=j2B delta 22 dcmexzT5#5OfhMmuFUB@6rZz9;ZC)(1qycRX2rU2r diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index f33d4697a1c3a..08800d55bb1b0 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -329,16 +329,20 @@ bool Playground::OpenPlaygroundHere(SinglePassCallback pass_callback) { }); } -std::optional Playground::LoadFixtureImageRGBA( - const char* fixture_name) const { - if (!renderer_ || fixture_name == nullptr) { - return std::nullopt; - } - - auto compressed_image = - CompressedImage::Create(OpenAssetAsMapping(fixture_name)); +std::shared_ptr Playground::LoadFixtureImageCompressed( + std::shared_ptr mapping) const { + auto compressed_image = CompressedImage::Create(std::move(mapping)); if (!compressed_image) { VALIDATION_LOG << "Could not create compressed image."; + return nullptr; + } + + return compressed_image; +} + +std::optional Playground::DecodeImageRGBA( + const std::shared_ptr& compressed) const { + if (compressed == nullptr) { return std::nullopt; } // The decoded image is immediately converted into RGBA as that format is @@ -346,9 +350,9 @@ std::optional Playground::LoadFixtureImageRGBA( // bit pixel strides, this is overkill. Since this is a test fixture we // aren't necessarily trying to eke out memory savings here and instead // favor simplicity. - auto image = compressed_image->Decode().ConvertToRGBA(); + auto image = compressed->Decode().ConvertToRGBA(); if (!image.IsValid()) { - VALIDATION_LOG << "Could not find fixture named " << fixture_name; + VALIDATION_LOG << "Could not decode image."; return std::nullopt; } @@ -356,42 +360,52 @@ std::optional Playground::LoadFixtureImageRGBA( } std::shared_ptr Playground::CreateTextureForFixture( - const char* fixture_name, + DecompressedImage& decompressed_image, bool enable_mipmapping) const { - auto image = LoadFixtureImageRGBA(fixture_name); - if (!image.has_value()) { - return nullptr; - } - auto texture_descriptor = TextureDescriptor{}; texture_descriptor.storage_mode = StorageMode::kHostVisible; texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt; - texture_descriptor.size = image->GetSize(); + texture_descriptor.size = decompressed_image.GetSize(); texture_descriptor.mip_count = - enable_mipmapping ? image->GetSize().MipCount() : 1u; + enable_mipmapping ? decompressed_image.GetSize().MipCount() : 1u; auto texture = renderer_->GetContext()->GetResourceAllocator()->CreateTexture( texture_descriptor); if (!texture) { - VALIDATION_LOG << "Could not allocate texture for fixture " << fixture_name; + VALIDATION_LOG << "Could not allocate texture for fixture."; return nullptr; } - texture->SetLabel(fixture_name); - auto uploaded = texture->SetContents(image->GetAllocation()); + auto uploaded = texture->SetContents(decompressed_image.GetAllocation()); if (!uploaded) { - VALIDATION_LOG << "Could not upload texture to device memory for fixture " - << fixture_name; + VALIDATION_LOG << "Could not upload texture to device memory for fixture."; return nullptr; } return texture; } +std::shared_ptr Playground::CreateTextureForFixture( + std::shared_ptr mapping, + bool enable_mipmapping) const { + auto image = DecodeImageRGBA(LoadFixtureImageCompressed(std::move(mapping))); + if (!image.has_value()) { + return nullptr; + } + return CreateTextureForFixture(image.value()); +} + +std::shared_ptr Playground::CreateTextureForFixture( + const char* fixture_name, + bool enable_mipmapping) const { + return CreateTextureForFixture(OpenAssetAsMapping(fixture_name)); +} + std::shared_ptr Playground::CreateTextureCubeForFixture( std::array fixture_names) const { std::array images; for (size_t i = 0; i < fixture_names.size(); i++) { - auto image = LoadFixtureImageRGBA(fixture_names[i]); + auto image = DecodeImageRGBA( + LoadFixtureImageCompressed(OpenAssetAsMapping(fixture_names[i]))); if (!image.has_value()) { return nullptr; } diff --git a/impeller/playground/playground.h b/impeller/playground/playground.h index 1bc94570d055c..ac44f19450a6d 100644 --- a/impeller/playground/playground.h +++ b/impeller/playground/playground.h @@ -11,6 +11,8 @@ #include "flutter/fml/time/time_delta.h" #include "impeller/geometry/point.h" +#include "impeller/image/compressed_image.h" +#include "impeller/image/decompressed_image.h" #include "impeller/renderer/renderer.h" #include "impeller/renderer/texture.h" #include "impeller/runtime_stage/runtime_stage.h" @@ -61,8 +63,19 @@ class Playground { bool OpenPlaygroundHere(SinglePassCallback pass_callback); - std::optional LoadFixtureImageRGBA( - const char* fixture_name) const; + std::shared_ptr LoadFixtureImageCompressed( + std::shared_ptr mapping) const; + + std::optional DecodeImageRGBA( + const std::shared_ptr& compressed) const; + + std::shared_ptr CreateTextureForFixture( + DecompressedImage& decompressed_image, + bool enable_mipmapping = false) const; + + std::shared_ptr CreateTextureForFixture( + std::shared_ptr mapping, + bool enable_mipmapping = false) const; std::shared_ptr CreateTextureForFixture( const char* fixture_name, diff --git a/impeller/scene/BUILD.gn b/impeller/scene/BUILD.gn index 4dbbc755d57a2..978885867b496 100644 --- a/impeller/scene/BUILD.gn +++ b/impeller/scene/BUILD.gn @@ -27,6 +27,7 @@ impeller_component("scene") { public_deps = [ "../renderer", + "importer:conversions", "importer:importer_flatbuffers", "shaders", ] diff --git a/impeller/scene/importer/BUILD.gn b/impeller/scene/importer/BUILD.gn index 87b9946cb636e..9a017a61ce992 100644 --- a/impeller/scene/importer/BUILD.gn +++ b/impeller/scene/importer/BUILD.gn @@ -17,14 +17,26 @@ flatbuffers("importer_flatbuffers") { public_deps = [ "//third_party/flatbuffers" ] } +impeller_component("conversions") { + sources = [ + "conversions.cc", + "conversions.h", + ] + + public_deps = [ + ":importer_flatbuffers", + "../../base", + "../../geometry", + "//flutter/fml", + ] +} + impeller_component("importer_lib") { # Current versions of libcxx have deprecated some of the UTF-16 string # conversion APIs. defines = [ "_LIBCPP_DISABLE_DEPRECATION_WARNINGS" ] sources = [ - "conversions.cc", - "conversions.h", "importer.h", "importer_gltf.cc", "switches.cc", @@ -35,6 +47,7 @@ impeller_component("importer_lib") { ] public_deps = [ + ":conversions", ":importer_flatbuffers", "../../base", "../../compiler:utilities", diff --git a/impeller/scene/importer/conversions.cc b/impeller/scene/importer/conversions.cc index 7031ed3ba7ccd..bd74f04ebb04e 100644 --- a/impeller/scene/importer/conversions.cc +++ b/impeller/scene/importer/conversions.cc @@ -75,6 +75,14 @@ fb::Color ToFBColor(const Color c) { return fb::Color(c.red, c.green, c.blue, c.alpha); } +std::unique_ptr ToFBColor(const std::vector& c) { + auto* color = new fb::Color(c.size() > 0 ? c[0] : 1, // + c.size() > 1 ? c[1] : 1, // + c.size() > 2 ? c[2] : 1, // + c.size() > 3 ? c[3] : 1); + return std::unique_ptr(color); +} + } // namespace importer } // namespace scene } // namespace impeller diff --git a/impeller/scene/importer/conversions.h b/impeller/scene/importer/conversions.h index 9388e7ed4b79d..b5fe119674d57 100644 --- a/impeller/scene/importer/conversions.h +++ b/impeller/scene/importer/conversions.h @@ -6,6 +6,7 @@ #include #include +#include #include "impeller/geometry/matrix.h" #include "impeller/scene/importer/scene_flatbuffers.h" @@ -44,6 +45,8 @@ fb::Vec4 ToFBVec4(const Vector4 v); fb::Color ToFBColor(const Color c); +std::unique_ptr ToFBColor(const std::vector& c); + } // namespace importer } // namespace scene } // namespace impeller diff --git a/impeller/scene/importer/importer_gltf.cc b/impeller/scene/importer/importer_gltf.cc index 87fe6b73767e8..83c33c0a06e2b 100644 --- a/impeller/scene/importer/importer_gltf.cc +++ b/impeller/scene/importer/importer_gltf.cc @@ -40,6 +40,25 @@ static bool MeshPrimitiveIsSkinned(const tinygltf::Primitive& primitive) { primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end(); } +static void ProcessMaterial(const tinygltf::Model& gltf, + const tinygltf::Material& in_material, + fb::MaterialT& out_material) { + out_material.type = fb::MaterialType::kUnlit; + out_material.base_color_factor = + ToFBColor(in_material.pbrMetallicRoughness.baseColorFactor); + bool base_color_texture_valid = + in_material.pbrMetallicRoughness.baseColorTexture.texCoord == 0 && + in_material.pbrMetallicRoughness.baseColorTexture.index >= 0 && + in_material.pbrMetallicRoughness.baseColorTexture.index < + static_cast(gltf.textures.size()); + out_material.base_color_texture = + base_color_texture_valid + // This is safe because every GLTF input texture is mapped to a + // `Scene->texture`. + ? in_material.pbrMetallicRoughness.baseColorTexture.index + : -1; +} + static bool ProcessMeshPrimitive(const tinygltf::Model& gltf, const tinygltf::Primitive& primitive, fb::MeshPrimitiveT& mesh_primitive) { @@ -119,35 +138,52 @@ static bool ProcessMeshPrimitive(const tinygltf::Model& gltf, /// Indices. /// - if (!WithinRange(primitive.indices, gltf.accessors.size())) { - std::cerr << "Mesh primitive has no index buffer. Skipping." << std::endl; - return false; - } - - auto index_accessor = gltf.accessors[primitive.indices]; - auto index_view = gltf.bufferViews[index_accessor.bufferView]; + { + if (!WithinRange(primitive.indices, gltf.accessors.size())) { + std::cerr << "Mesh primitive has no index buffer. Skipping." << std::endl; + return false; + } - auto indices = std::make_unique(); + auto index_accessor = gltf.accessors[primitive.indices]; + auto index_view = gltf.bufferViews[index_accessor.bufferView]; + + auto indices = std::make_unique(); + + switch (index_accessor.componentType) { + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + indices->type = fb::IndexType::k16Bit; + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: + indices->type = fb::IndexType::k32Bit; + break; + default: + std::cerr << "Mesh primitive has unsupported index type " + << index_accessor.componentType << ". Skipping."; + return false; + } + indices->count = index_accessor.count; + indices->data.resize(index_view.byteLength); + const auto* index_buffer = + &gltf.buffers[index_view.buffer].data[index_view.byteOffset]; + std::memcpy(indices->data.data(), index_buffer, indices->data.size()); - switch (index_accessor.componentType) { - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: - indices->type = fb::IndexType::k16Bit; - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: - indices->type = fb::IndexType::k32Bit; - break; - default: - std::cerr << "Mesh primitive has unsupported index type " - << index_accessor.componentType << ". Skipping."; - return false; + mesh_primitive.indices = std::move(indices); } - indices->count = index_accessor.count; - indices->data.resize(index_view.byteLength); - const auto* index_buffer = - &gltf.buffers[index_view.buffer].data[index_view.byteOffset]; - std::memcpy(indices->data.data(), index_buffer, indices->data.size()); - mesh_primitive.indices = std::move(indices); + //--------------------------------------------------------------------------- + /// Material. + /// + + { + auto material = std::make_unique(); + if (primitive.material >= 0 && + primitive.material < static_cast(gltf.materials.size())) { + ProcessMaterial(gltf, gltf.materials[primitive.material], *material); + } else { + material->type = fb::MaterialType::kUnlit; + } + mesh_primitive.material = std::move(material); + } return true; } @@ -208,6 +244,45 @@ static void ProcessNode(const tinygltf::Model& gltf, } } +static void ProcessTexture(const tinygltf::Model& gltf, + const tinygltf::Texture& in_texture, + fb::TextureT& out_texture) { + if (in_texture.source < 0 || + in_texture.source >= static_cast(gltf.images.size())) { + return; + } + auto& image = gltf.images[in_texture.source]; + + auto embedded = std::make_unique(); + embedded->bytes = image.image; + size_t bytes_per_component = 0; + switch (image.pixel_type) { + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: + embedded->component_type = fb::ComponentType::k8Bit; + bytes_per_component = 1; + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + embedded->component_type = fb::ComponentType::k16Bit; + bytes_per_component = 2; + break; + default: + std::cerr << "Texture component type " << image.pixel_type + << " not supported." << std::endl; + return; + } + if (image.image.size() != + bytes_per_component * image.component * image.width * image.height) { + std::cerr << "Decompressed texture had unexpected buffer size. Skipping." + << std::endl; + return; + } + embedded->component_count = image.component; + embedded->width = image.width; + embedded->height = image.height; + out_texture.embedded_image = std::move(embedded); + out_texture.uri = image.uri; +} + bool ParseGLTF(const fml::Mapping& source_mapping, fb::SceneT& out_scene) { tinygltf::Model gltf; @@ -232,6 +307,12 @@ bool ParseGLTF(const fml::Mapping& source_mapping, fb::SceneT& out_scene) { const tinygltf::Scene& scene = gltf.scenes[gltf.defaultScene]; out_scene.children = scene.nodes; + for (size_t texture_i = 0; texture_i < gltf.textures.size(); texture_i++) { + auto texture = std::make_unique(); + ProcessTexture(gltf, gltf.textures[texture_i], *texture); + out_scene.textures.push_back(std::move(texture)); + } + for (size_t node_i = 0; node_i < gltf.nodes.size(); node_i++) { auto node = std::make_unique(); ProcessNode(gltf, gltf.nodes[node_i], *node); diff --git a/impeller/scene/importer/importer_unittests.cc b/impeller/scene/importer/importer_unittests.cc index 1dd20b56169cc..77ffca8e43cb4 100644 --- a/impeller/scene/importer/importer_unittests.cc +++ b/impeller/scene/importer/importer_unittests.cc @@ -15,7 +15,8 @@ namespace importer { namespace testing { TEST(ImporterTest, CanParseUnskinnedGLTF) { - auto mapping = flutter::testing::OpenFixtureAsMapping("flutter_logo.glb"); + auto mapping = + flutter::testing::OpenFixtureAsMapping("flutter_logo_baked.glb"); fb::SceneT scene; ASSERT_TRUE(ParseGLTF(*mapping, scene)); diff --git a/impeller/scene/importer/scene.fbs b/impeller/scene/importer/scene.fbs index 90552307d3290..de2d1b11b5a08 100644 --- a/impeller/scene/importer/scene.fbs +++ b/impeller/scene/importer/scene.fbs @@ -15,14 +15,28 @@ struct Color { a: float; } -/// A compressed texture for Flutter to decode. The `bytes` field takes -/// precedent over the `uri` field. +enum ComponentType:byte { + k8Bit, + k16Bit, +} + +table EmbeddedImage { + bytes: [ubyte]; + component_count: ubyte = 0; + component_type: ComponentType; + width: uint; + height: uint; +} + +/// The `bytes` field takes precedent over the `uri` field. +/// If both the `uri` and `bytes` fields are empty, a fully opaque white +/// placeholder will be used. table Texture { - /// A Flutter asset URI for an image file to import and decode. + /// A Flutter asset URI for a compressed image file to import and decode. uri: string; - /// Compressed image bytes for Flutter to decode. If this field is not empty, - /// it takes precedent over the `uri` field for sourcing the texture. - bytes: [ubyte]; + /// Decompressed image bytes for uploading to the GPU. If this field is not + /// empty, it takes precedent over the `uri` field for sourcing the texture. + embedded_image: EmbeddedImage; } enum MaterialType:byte { @@ -34,7 +48,7 @@ enum MaterialType:byte { /// by the factor of the component. /// Texture fields are indices into the `Scene`->`textures` array. All textures /// are optional -- a texture index value of -1 indicates no texture. -table Material { +table Material { // When the `MaterialType` is `kUnlit`, only the `base_color` fields are used. type: MaterialType; diff --git a/impeller/scene/material.cc b/impeller/scene/material.cc index 9ea9655a74ae2..9e141d29ec9e2 100644 --- a/impeller/scene/material.cc +++ b/impeller/scene/material.cc @@ -3,9 +3,12 @@ // found in the LICENSE file. #include "impeller/scene/material.h" +#include "impeller/base/validation.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/sampler_descriptor.h" #include "impeller/renderer/sampler_library.h" +#include "impeller/scene/importer/conversions.h" +#include "impeller/scene/importer/scene_flatbuffers.h" #include "impeller/scene/pipeline_key.h" #include "impeller/scene/scene_context.h" #include "impeller/scene/shaders/unlit.frag.h" @@ -21,12 +24,27 @@ namespace scene { Material::~Material() = default; +std::unique_ptr Material::MakeFromFlatbuffer( + const fb::Material& material, + const std::vector>& textures) { + switch (material.type()) { + case fb::MaterialType::kUnlit: + return UnlitMaterial::MakeFromFlatbuffer(material, textures); + case fb::MaterialType::kPhysicallyBased: + return PhysicallyBasedMaterial::MakeFromFlatbuffer(material, textures); + } +} + std::unique_ptr Material::MakeUnlit() { return std::make_unique(); } -std::unique_ptr Material::MakeStandard() { - return std::make_unique(); +std::unique_ptr Material::MakePhysicallyBased() { + return std::make_unique(); +} + +void Material::SetVertexColorWeight(Scalar weight) { + vertex_color_weight_ = weight; } void Material::SetBlendConfig(BlendConfig blend_config) { @@ -50,6 +68,29 @@ SceneContextOptions Material::GetContextOptions(const RenderPass& pass) const { /// UnlitMaterial /// +std::unique_ptr UnlitMaterial::MakeFromFlatbuffer( + const fb::Material& material, + const std::vector>& textures) { + if (material.type() != fb::MaterialType::kUnlit) { + VALIDATION_LOG << "Cannot unpack unlit material because the ipscene " + "material type is not unlit."; + return nullptr; + } + + auto result = Material::MakeUnlit(); + + result->SetColor(material.base_color_factor() + ? importer::ToColor(*material.base_color_factor()) + : Color::White()); + if (material.base_color_texture() >= 0 && + material.base_color_texture() < static_cast(textures.size())) { + result->SetColorTexture(textures[material.base_color_texture()]); + result->SetVertexColorWeight(0); + } + + return result; +} + UnlitMaterial::~UnlitMaterial() = default; void UnlitMaterial::SetColor(Color color) { @@ -60,10 +101,6 @@ void UnlitMaterial::SetColorTexture(std::shared_ptr color_texture) { color_texture_ = std::move(color_texture); } -void UnlitMaterial::SetVertexColorWeight(Scalar weight) { - vertex_color_weight_ = weight; -} - // |Material| MaterialType UnlitMaterial::GetMaterialType() const { return MaterialType::kUnlit; @@ -96,51 +133,96 @@ void UnlitMaterial::BindToCommand(const SceneContext& scene_context, /// StandardMaterial /// -StandardMaterial::~StandardMaterial() = default; - -void StandardMaterial::SetAlbedo(Color albedo) { +std::unique_ptr +PhysicallyBasedMaterial::MakeFromFlatbuffer( + const fb::Material& material, + const std::vector>& textures) { + if (material.type() != fb::MaterialType::kPhysicallyBased) { + VALIDATION_LOG << "Cannot unpack unlit material because the ipscene " + "material type is not unlit."; + return nullptr; + } + + auto result = Material::MakePhysicallyBased(); + + result->SetAlbedo(material.base_color_factor() + ? importer::ToColor(*material.base_color_factor()) + : Color::White()); + result->SetRoughness(material.roughness_factor()); + result->SetMetallic(material.metallic_factor()); + + if (material.base_color_texture() >= 0 && + material.base_color_texture() < static_cast(textures.size())) { + result->SetAlbedoTexture(textures[material.base_color_texture()]); + result->SetVertexColorWeight(0); + } + if (material.metallic_roughness_texture() >= 0 && + material.metallic_roughness_texture() < + static_cast(textures.size())) { + result->SetMetallicRoughnessTexture( + textures[material.metallic_roughness_texture()]); + } + if (material.normal_texture() >= 0 && + material.normal_texture() < static_cast(textures.size())) { + result->SetNormalTexture(textures[material.normal_texture()]); + } + if (material.occlusion_texture() >= 0 && + material.occlusion_texture() < static_cast(textures.size())) { + result->SetOcclusionTexture(textures[material.occlusion_texture()]); + } + + return result; +} + +PhysicallyBasedMaterial::~PhysicallyBasedMaterial() = default; + +void PhysicallyBasedMaterial::SetAlbedo(Color albedo) { albedo_ = albedo; } -void StandardMaterial::SetRoughness(Scalar roughness) { +void PhysicallyBasedMaterial::SetRoughness(Scalar roughness) { roughness_ = roughness; } -void StandardMaterial::SetMetallic(Scalar metallic) { +void PhysicallyBasedMaterial::SetMetallic(Scalar metallic) { metallic_ = metallic; } -void StandardMaterial::SetAlbedoTexture( +void PhysicallyBasedMaterial::SetAlbedoTexture( std::shared_ptr albedo_texture) { albedo_texture_ = std::move(albedo_texture); } -void StandardMaterial::SetNormalTexture( +void PhysicallyBasedMaterial::SetMetallicRoughnessTexture( + std::shared_ptr metallic_roughness_texture) { + metallic_roughness_texture_ = std::move(metallic_roughness_texture); +} + +void PhysicallyBasedMaterial::SetNormalTexture( std::shared_ptr normal_texture) { normal_texture_ = std::move(normal_texture); } -void StandardMaterial::SetOcclusionRoughnessMetallicTexture( - std::shared_ptr occlusion_roughness_metallic_texture) { - occlusion_roughness_metallic_texture_ = - std::move(occlusion_roughness_metallic_texture); +void PhysicallyBasedMaterial::SetOcclusionTexture( + std::shared_ptr occlusion_texture) { + occlusion_texture_ = std::move(occlusion_texture); } -void StandardMaterial::SetEnvironmentMap( +void PhysicallyBasedMaterial::SetEnvironmentMap( std::shared_ptr environment_map) { environment_map_ = std::move(environment_map); } // |Material| -MaterialType StandardMaterial::GetMaterialType() const { +MaterialType PhysicallyBasedMaterial::GetMaterialType() const { // TODO(bdero): Replace this once a PBR shader has landed. return MaterialType::kUnlit; } // |Material| -void StandardMaterial::BindToCommand(const SceneContext& scene_context, - HostBuffer& buffer, - Command& command) const {} +void PhysicallyBasedMaterial::BindToCommand(const SceneContext& scene_context, + HostBuffer& buffer, + Command& command) const {} } // namespace scene } // namespace impeller diff --git a/impeller/scene/material.h b/impeller/scene/material.h index d289a6e8bbd4d..a9221a05f480c 100644 --- a/impeller/scene/material.h +++ b/impeller/scene/material.h @@ -10,6 +10,7 @@ #include "impeller/renderer/formats.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/texture.h" +#include "impeller/scene/importer/scene_flatbuffers.h" #include "impeller/scene/pipeline_key.h" namespace impeller { @@ -20,12 +21,10 @@ struct SceneContextOptions; class Geometry; class UnlitMaterial; -class StandardMaterial; +class PhysicallyBasedMaterial; class Material { public: - virtual ~Material(); - struct BlendConfig { BlendOperation color_op = BlendOperation::kAdd; BlendFactor source_color_factor = BlendFactor::kOne; @@ -40,9 +39,16 @@ class Material { CompareFunction compare = CompareFunction::kAlways; }; + static std::unique_ptr MakeFromFlatbuffer( + const fb::Material& material, + const std::vector>& textures); + static std::unique_ptr MakeUnlit(); - static std::unique_ptr MakeStandard(); + static std::unique_ptr MakePhysicallyBased(); + virtual ~Material(); + + void SetVertexColorWeight(Scalar weight); void SetBlendConfig(BlendConfig blend_config); void SetStencilConfig(StencilConfig stencil_config); @@ -57,6 +63,7 @@ class Material { Command& command) const = 0; protected: + Scalar vertex_color_weight_ = 1; BlendConfig blend_config_; StencilConfig stencil_config_; bool is_translucent_ = false; @@ -64,14 +71,16 @@ class Material { class UnlitMaterial final : public Material { public: + static std::unique_ptr MakeFromFlatbuffer( + const fb::Material& material, + const std::vector>& textures); + ~UnlitMaterial(); void SetColor(Color color); void SetColorTexture(std::shared_ptr color_texture); - void SetVertexColorWeight(Scalar weight); - // |Material| MaterialType GetMaterialType() const override; @@ -83,21 +92,25 @@ class UnlitMaterial final : public Material { private: Color color_ = Color::White(); std::shared_ptr color_texture_; - Scalar vertex_color_weight_ = 1; }; -class StandardMaterial final : public Material { +class PhysicallyBasedMaterial final : public Material { public: - ~StandardMaterial(); + static std::unique_ptr MakeFromFlatbuffer( + const fb::Material& material, + const std::vector>& textures); + + ~PhysicallyBasedMaterial(); void SetAlbedo(Color albedo); void SetRoughness(Scalar roughness); void SetMetallic(Scalar metallic); void SetAlbedoTexture(std::shared_ptr albedo_texture); + void SetMetallicRoughnessTexture( + std::shared_ptr metallic_roughness_texture); void SetNormalTexture(std::shared_ptr normal_texture); - void SetOcclusionRoughnessMetallicTexture( - std::shared_ptr occlusion_roughness_metallic_texture); + void SetOcclusionTexture(std::shared_ptr occlusion_texture); void SetEnvironmentMap(std::shared_ptr environment_map); @@ -111,12 +124,13 @@ class StandardMaterial final : public Material { private: Color albedo_ = Color::White(); - Scalar roughness_ = 0.5; Scalar metallic_ = 0.5; + Scalar roughness_ = 0.5; std::shared_ptr albedo_texture_; + std::shared_ptr metallic_roughness_texture_; std::shared_ptr normal_texture_; - std::shared_ptr occlusion_roughness_metallic_texture_; + std::shared_ptr occlusion_texture_; std::shared_ptr environment_map_; }; diff --git a/impeller/scene/node.cc b/impeller/scene/node.cc index c2d1521419741..cabdb197c27f7 100644 --- a/impeller/scene/node.cc +++ b/impeller/scene/node.cc @@ -6,8 +6,10 @@ #include +#include "flutter/fml/logging.h" #include "impeller/base/validation.h" #include "impeller/geometry/matrix.h" +#include "impeller/scene/importer/conversions.h" #include "impeller/scene/importer/scene_flatbuffers.h" #include "impeller/scene/mesh.h" #include "impeller/scene/node.h" @@ -16,20 +18,107 @@ namespace impeller { namespace scene { -std::shared_ptr Node::MakeFromFlatbuffer(fml::Mapping& mapping, - Allocator& allocator) { - flatbuffers::Verifier verifier(mapping.GetMapping(), mapping.GetSize()); +std::shared_ptr Node::MakeFromFlatbuffer( + const fml::Mapping& ipscene_mapping, + Allocator& allocator) { + flatbuffers::Verifier verifier(ipscene_mapping.GetMapping(), + ipscene_mapping.GetSize()); if (!fb::VerifySceneBuffer(verifier)) { VALIDATION_LOG << "Failed to unpack scene: Scene flatbuffer is invalid."; return nullptr; } - return Node::MakeFromFlatbuffer(*fb::GetScene(mapping.GetMapping()), + return Node::MakeFromFlatbuffer(*fb::GetScene(ipscene_mapping.GetMapping()), allocator); } +static std::shared_ptr UnpackTextureFromFlatbuffer( + const fb::Texture* iptexture, + Allocator& allocator) { + if (iptexture == nullptr || iptexture->embedded_image() == nullptr || + iptexture->embedded_image()->bytes() == nullptr) { + return nullptr; + } + + auto embedded = iptexture->embedded_image(); + + uint8_t bytes_per_component = 0; + switch (embedded->component_type()) { + case fb::ComponentType::k8Bit: + bytes_per_component = 1; + break; + case fb::ComponentType::k16Bit: + // bytes_per_component = 2; + FML_LOG(WARNING) << "16 bit textures not yet supported."; + return nullptr; + } + + DecompressedImage::Format format; + switch (embedded->component_count()) { + case 1: + format = DecompressedImage::Format::kGrey; + break; + case 3: + format = DecompressedImage::Format::kRGB; + break; + case 4: + format = DecompressedImage::Format::kRGBA; + break; + default: + FML_LOG(WARNING) << "Textures with " << embedded->component_count() + << " components are not supported." << std::endl; + return nullptr; + } + if (embedded->bytes()->size() != bytes_per_component * + embedded->component_count() * + embedded->width() * embedded->height()) { + FML_LOG(WARNING) << "Embedded texture has an unexpected size. Skipping." + << std::endl; + return nullptr; + } + + auto image_mapping = std::make_shared( + embedded->bytes()->Data(), embedded->bytes()->size()); + auto decompressed_image = + DecompressedImage(ISize(embedded->width(), embedded->height()), format, + image_mapping) + .ConvertToRGBA(); + + auto texture_descriptor = TextureDescriptor{}; + texture_descriptor.storage_mode = StorageMode::kHostVisible; + texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt; + texture_descriptor.size = decompressed_image.GetSize(); + // TODO(bdero): Generate mipmaps for embedded textures. + texture_descriptor.mip_count = 1u; + + auto texture = allocator.CreateTexture(texture_descriptor); + if (!texture) { + FML_LOG(ERROR) << "Could not allocate texture."; + return nullptr; + } + + auto uploaded = texture->SetContents(decompressed_image.GetAllocation()); + if (!uploaded) { + FML_LOG(ERROR) << "Could not upload texture to device memory."; + return nullptr; + } + + return texture; +} + std::shared_ptr Node::MakeFromFlatbuffer(const fb::Scene& scene, Allocator& allocator) { + // Unpack textures. + std::vector> textures; + if (scene.textures()) { + for (const auto iptexture : *scene.textures()) { + // The elements of the unpacked texture array must correspond exactly with + // the ipscene texture array. So if a texture is empty or invalid, a + // nullptr is inserted as a placeholder. + textures.push_back(UnpackTextureFromFlatbuffer(iptexture, allocator)); + } + } + auto result = std::make_shared(); if (!scene.nodes() || !scene.children()) { return result; // The scene is empty. @@ -55,7 +144,7 @@ std::shared_ptr Node::MakeFromFlatbuffer(const fb::Scene& scene, // Unpack each node. for (size_t node_i = 0; node_i < scene.nodes()->size(); node_i++) { scene_nodes[node_i]->UnpackFromFlatbuffer(*scene.nodes()->Get(node_i), - scene_nodes, allocator); + scene_nodes, textures, allocator); } return result; @@ -64,16 +153,29 @@ std::shared_ptr Node::MakeFromFlatbuffer(const fb::Scene& scene, void Node::UnpackFromFlatbuffer( const fb::Node& source_node, const std::vector>& scene_nodes, + const std::vector>& textures, Allocator& allocator) { + /// Transform. + + SetLocalTransform(importer::ToMatrix(*source_node.transform())); + + /// Meshes. + if (source_node.mesh_primitives()) { Mesh mesh; for (const auto* primitives : *source_node.mesh_primitives()) { auto geometry = Geometry::MakeFromFlatbuffer(*primitives, allocator); - mesh.AddPrimitive({geometry, Material::MakeUnlit()}); + auto material = + primitives->material() + ? Material::MakeFromFlatbuffer(*primitives->material(), textures) + : Material::MakeUnlit(); + mesh.AddPrimitive({std::move(geometry), std::move(material)}); } SetMesh(std::move(mesh)); } + /// Child nodes. + if (!source_node.children()) { return; } diff --git a/impeller/scene/node.h b/impeller/scene/node.h index 307411de6d053..a64fa9b8d9d84 100644 --- a/impeller/scene/node.h +++ b/impeller/scene/node.h @@ -11,6 +11,7 @@ #include "impeller/geometry/matrix.h" #include "impeller/renderer/render_target.h" +#include "impeller/renderer/texture.h" #include "impeller/scene/camera.h" #include "impeller/scene/mesh.h" #include "impeller/scene/scene_encoder.h" @@ -20,8 +21,9 @@ namespace scene { class Node final { public: - static std::shared_ptr MakeFromFlatbuffer(fml::Mapping& mapping, - Allocator& allocator); + static std::shared_ptr MakeFromFlatbuffer( + const fml::Mapping& ipscene_mapping, + Allocator& allocator); static std::shared_ptr MakeFromFlatbuffer(const fb::Scene& scene, Allocator& allocator); @@ -52,6 +54,7 @@ class Node final { void UnpackFromFlatbuffer( const fb::Node& node, const std::vector>& scene_nodes, + const std::vector>& textures, Allocator& allocator); bool is_root_ = false; diff --git a/impeller/scene/scene_unittests.cc b/impeller/scene/scene_unittests.cc index a9ce2138c19c6..0cbd458fb9f54 100644 --- a/impeller/scene/scene_unittests.cc +++ b/impeller/scene/scene_unittests.cc @@ -4,13 +4,16 @@ #include #include +#include +#include "flutter/fml/mapping.h" #include "flutter/testing/testing.h" #include "impeller/geometry/color.h" #include "impeller/geometry/constants.h" #include "impeller/geometry/matrix.h" #include "impeller/geometry/quaternion.h" #include "impeller/geometry/vector.h" +#include "impeller/image/decompressed_image.h" #include "impeller/playground/playground.h" #include "impeller/playground/playground_test.h" #include "impeller/renderer/formats.h" @@ -72,22 +75,17 @@ TEST_P(SceneTest, FlutterLogo) { auto allocator = GetContext()->GetResourceAllocator(); auto mapping = - flutter::testing::OpenFixtureAsMapping("flutter_logo.glb.ipscene"); + flutter::testing::OpenFixtureAsMapping("flutter_logo_baked.glb.ipscene"); ASSERT_NE(mapping, nullptr); + flatbuffers::Verifier verifier(mapping->GetMapping(), mapping->GetSize()); + ASSERT_TRUE(fb::VerifySceneBuffer(verifier)); + std::shared_ptr gltf_scene = Node::MakeFromFlatbuffer(*mapping, *allocator); ASSERT_NE(gltf_scene, nullptr); - - std::shared_ptr material = Material::MakeUnlit(); - auto color_baked = CreateTextureForFixture("flutter_logo_baked.png"); - material->SetColorTexture(color_baked); - material->SetVertexColorWeight(0); - ASSERT_EQ(gltf_scene->GetChildren().size(), 1u); ASSERT_EQ(gltf_scene->GetChildren()[0]->GetMesh().GetPrimitives().size(), 1u); - gltf_scene->GetChildren()[0]->GetMesh().GetPrimitives()[0].material = - material; auto scene_context = std::make_shared(GetContext()); auto scene = Scene(scene_context);