From: Richard Huang Date: Thu, 21 Apr 2022 12:52:56 +0000 (+0100) Subject: Ambient occlusion support in DLI model X-Git-Tag: dali_2.1.20~11^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=8dce53eeb9b425c7e7284664a8e6da4cf028b396 Ambient occlusion support in DLI model Change-Id: If4378a8ecffbc37755b711805cc0f241dbd6e592 --- diff --git a/automated-tests/resources/coverageTest.bin b/automated-tests/resources/coverageTest.bin new file mode 100644 index 0000000..1d0e3d6 Binary files /dev/null and b/automated-tests/resources/coverageTest.bin differ diff --git a/automated-tests/resources/coverageTest.dli b/automated-tests/resources/coverageTest.dli new file mode 100644 index 0000000..a380378 --- /dev/null +++ b/automated-tests/resources/coverageTest.dli @@ -0,0 +1,82 @@ +{ + "asset": { "version": "1.0" }, + "scene": 0, + "scenes": [ { "nodes": [ 0 ] } ], + "nodes": [ + { + "name": "root", + "matrix": [ 0.2, 0, 0, 0, 0, -0, 0.2, 0, 0, -0.2, -0, 0, 0, 0, 0, 1 ], + "model": { + "mesh": 0, + "material": 0 + } + } + ], + "meshes": [ + { + "uri": "coverageTest.bin", + "attributes": 31, + "primitive": "TRIANGLES", + "indices": { "byteOffset": 0, "byteLength": 600 }, + "positions": { "byteOffset": 600, "byteLength": 2364 }, + "normals": { "byteOffset": 2964, "byteLength": 2364 }, + "textures": { "byteOffset": 5328, "byteLength": 1576 }, + "tangents": { "byteOffset": 6904, "byteLength": 2364 } + } + ], + "skeletons": [ + ], + "cameras": [ + { + "fov": 60, + "near": 0.1, + "far": 100, + "matrix": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 3.5, 1 ] + } + ], + "materials": [ + { + "name": "material1", + "color": [ 1, 1, 0, 1 ], + "roughness": 0.4, + "metallic": 0, + "occlusionMap": "exercise/Icons/Icon_Idle.png", + "mipmap": true, + "environment" : 1 + }, + { + "name": "", + "color": [ 1, 1, 1, 1 ], + "roughness": 1, + "metallic": 1, + "mipmap": true + } + ], + "lights" : [ { + "matrix" : [ 0.8950600624084473, 0.0914330929517746, 0.4364715814590454, 0.0, 0.3676385283470154, 0.4026888310909271, -0.8382623195648193, 0.0, -0.25240713357925415, 0.9107588529586792, 0.3268163800239563, 0.0, 0.0, 0.0, -1.0, 1.0 ], + "color" : [ 0.8, 0.8, 0.8 ], + "intensity" : 1.0, + "shadowMapSize" : 256, + "orthographicSize" : 4.2760005, + "shadowIntensity" : 1.0 + } ], + "environment" : [ { + "cubeInitialOrientation" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ], + "iblIntensity" : 1.0 + }, { + "cubeSpecular" : "Studio/Radiance.ktx", + "cubeDiffuse" : "Studio/Irradiance.ktx", + "cubeInitialOrientation" : [ 0.6716271638870239, 0.07979151606559753, -0.7365801334381104, 0.0, 0.07979151606559753, 0.9806114435195923, 0.17898204922676086, 0.0, 0.7365801334381104, -0.17898204922676086, 0.6522386074066162, 0.0, 0.0, 0.0, 0.0, 1.0 ], + "iblIntensity" : 0.75 + } ], + "shaders": [ + { + "vertex": "dli_pbr.vsh", + "fragment": "dli_pbr.fsh", + "defines" : [ "OCCLUSION", "DISPLACEMENT" ], + "rendererState": "DEPTH_TEST|DEPTH_WRITE|CULL_BACK|DEPTH_FUNC:LESS_EQUAL", + "uCubeMatrix": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ], + "uMaxLOD": 6 + } + ] +} diff --git a/automated-tests/resources/dli_pbr.fsh b/automated-tests/resources/dli_pbr.fsh index 72a0d31..6a961d2 100644 --- a/automated-tests/resources/dli_pbr.fsh +++ b/automated-tests/resources/dli_pbr.fsh @@ -31,6 +31,10 @@ uniform sampler2D sNormalRoughness; #endif +#ifdef OCCLUSION + uniform sampler2D sAmbientOcclusion; +#endif //OCCLUSION + uniform samplerCube sDiffuse; uniform samplerCube sSpecular; @@ -152,6 +156,11 @@ void main() vec3 finalColor = diffuseColor + specColor; finalColor = sqrt( finalColor ) * uIblIntensity; + +#ifdef OCCLUSION + finalColor *= texture(sAmbientOcclusion, vUV.st).r; +#endif //OCCLUSION + #ifdef THREE_TEX FragColor = vec4( finalColor, alpha ); #else //THREE_TEX diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-DliLoader.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-DliLoader.cpp index d09d2da..b63df36 100644 --- a/automated-tests/src/dali-scene-loader/utc-Dali-DliLoader.cpp +++ b/automated-tests/src/dali-scene-loader/utc-Dali-DliLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,32 +18,30 @@ // Enable debug log for test coverage #define DEBUG_ENABLED 1 +#include +#include +#include "dali-scene-loader/internal/json-util.h" #include "dali-scene-loader/public-api/dli-loader.h" +#include "dali-scene-loader/public-api/load-result.h" #include "dali-scene-loader/public-api/resource-bundle.h" #include "dali-scene-loader/public-api/scene-definition.h" -#include "dali-scene-loader/public-api/load-result.h" -#include "dali-scene-loader/internal/json-util.h" -#include -#include using namespace Dali; using namespace Dali::SceneLoader; namespace { - -void ConfigureBlendShapeShaders(ResourceBundle& resources, const SceneDefinition& scene, Actor root, - std::vector&& requests) +void ConfigureBlendShapeShaders(ResourceBundle& resources, const SceneDefinition& scene, Actor root, std::vector&& requests) { std::vector errors; - auto onError = [&errors](const std::string& msg) { + auto onError = [&errors](const std::string& msg) { errors.push_back(msg); }; - if (!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError)) + if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError)) { ExceptionFlinger flinger(ASSERT_LOCATION); - for (auto& msg : errors) + for(auto& msg : errors) { flinger << msg << '\n'; } @@ -56,33 +54,32 @@ struct Context return TEST_RESOURCE_DIR "/"; }; - ResourceBundle resources; - SceneDefinition scene; - std::vector cameraParameters; - std::vector lights; - std::vector animations; + ResourceBundle resources; + SceneDefinition scene; + std::vector cameraParameters; + std::vector lights; + std::vector animations; std::vector animGroups; - LoadResult output { + LoadResult output{ resources, scene, animations, animGroups, cameraParameters, - lights - }; + lights}; - DliLoader::InputParams input { + DliLoader::InputParams input{ pathProvider(ResourceType::Mesh), nullptr, {}, {}, nullptr, }; - DliLoader::LoadParams loadParams{ input, output }; + DliLoader::LoadParams loadParams{input, output}; std::vector errors; - DliLoader loader; + DliLoader loader; StringCallback onError = [this](const std::string& error) { errors.push_back(error); @@ -97,7 +94,7 @@ struct Context bool StringHasTokens(const char* string, const std::vector& tokens) { - for (auto& token: tokens) + for(auto& token : tokens) { auto result = strstr(string, token); if(nullptr == result) @@ -109,7 +106,7 @@ bool StringHasTokens(const char* string, const std::vector& tokens) return true; } -} +} // namespace int UtcDaliDliLoaderLoadSceneNotFound(void) { @@ -118,7 +115,7 @@ int UtcDaliDliLoaderLoadSceneNotFound(void) DALI_TEST_EQUAL(ctx.loader.LoadScene("does_not_exist.dli", ctx.loadParams), false); auto error = ctx.loader.GetParseError(); - DALI_TEST_CHECK(StringHasTokens(error.c_str(), { "Empty source buffer to parse." })); + DALI_TEST_CHECK(StringHasTokens(error.c_str(), {"Empty source buffer to parse."})); END_TEST; } @@ -131,49 +128,48 @@ int UtcDaliDliLoaderLoadSceneFailParse(void) DALI_TEST_EQUAL(ctx.loader.LoadScene(path, ctx.loadParams), false); auto error = ctx.loader.GetParseError(); - DALI_TEST_CHECK(StringHasTokens(error.c_str(), { "Unexpected character." })); + DALI_TEST_CHECK(StringHasTokens(error.c_str(), {"Unexpected character."})); END_TEST; } int UtcDaliDliLoaderLoadSceneAssertions(void) { - const std::pair pathExceptionPairs[] { - // from RequireChild() - { "scenes-nodes-missing", "Failed to find child node" }, - { "scenes-missing", "Failed to find child node" }, - { "nodes-missing", "Failed to find child node" }, + const std::pair pathExceptionPairs[]{ + // from RequireChild() + {"scenes-nodes-missing", "Failed to find child node"}, + {"scenes-missing", "Failed to find child node"}, + {"nodes-missing", "Failed to find child node"}, // from ParseSceneInternal() - { "scene-out-of-bounds", "out of bounds" }, - { "nodes-invalid-type", "invalid type; array required" }, - { "nodes-array-empty", "must define a node id" }, - { "root-id-invalid", "invalid value for root node index" }, - { "root-id-out-of-bounds", "out of bounds" }, - { "root-node-invalid-type", "invalid JSON type; object required" }, + {"scene-out-of-bounds", "out of bounds"}, + {"nodes-invalid-type", "invalid type; array required"}, + {"nodes-array-empty", "must define a node id"}, + {"root-id-invalid", "invalid value for root node index"}, + {"root-id-out-of-bounds", "out of bounds"}, + {"root-node-invalid-type", "invalid JSON type; object required"}, // from ParseSkeletons() - { "skeleton-node-missing", "Missing required attribute" }, - { "skeleton-root-not-found", "not defined" }, + {"skeleton-node-missing", "Missing required attribute"}, + {"skeleton-root-not-found", "not defined"}, // from ParseShaders() - { "shader-vertex-missing", "Missing vertex / fragment shader" }, - { "shader-fragment-missing", "Missing vertex / fragment shader" }, + {"shader-vertex-missing", "Missing vertex / fragment shader"}, + {"shader-fragment-missing", "Missing vertex / fragment shader"}, // from ParseMeshes() - { "mesh-uri-missing", "Missing required attribute" }, - { "mesh-indices-read-fail", "Failed to read indices" }, - { "mesh-positions-read-fail", "Failed to read positions" }, + {"mesh-uri-missing", "Missing required attribute"}, + {"mesh-indices-read-fail", "Failed to read indices"}, + {"mesh-positions-read-fail", "Failed to read positions"}, // from ParseMaterials() - { "material-environment-out-of-bounds", "out of bounds" }, + {"material-environment-out-of-bounds", "out of bounds"}, // from ParseNodes() - { "node-model-mesh-missing", "Missing mesh" }, - { "node-arc-mesh-missing", "Missing mesh" }, - { "node-animated-image-mesh-missing", "Missing mesh" }, - { "node-renderable-mesh-invalid-type", "Invalid Mesh index type" }, - { "node-renderable-mesh-out-of-bounds", "out of bounds" }, - { "node-child-invalid-type", "invalid index type" }, - { "node-name-already-used", "name already used" }, + {"node-model-mesh-missing", "Missing mesh"}, + {"node-arc-mesh-missing", "Missing mesh"}, + {"node-animated-image-mesh-missing", "Missing mesh"}, + {"node-renderable-mesh-invalid-type", "Invalid Mesh index type"}, + {"node-renderable-mesh-out-of-bounds", "out of bounds"}, + {"node-child-invalid-type", "invalid index type"}, + {"node-name-already-used", "name already used"}, // from ParseAnimations() - { "animation-failed-to-open", "Failed to open animation data" } - }; - for (auto& i: pathExceptionPairs) + {"animation-failed-to-open", "Failed to open animation data"}}; + for(auto& i : pathExceptionPairs) { Context ctx; @@ -214,10 +210,9 @@ int UtcDaliDliLoaderLoadSceneExercise(void) DALI_TEST_EQUAL(ctx.animGroups.size(), 16u); ViewProjection viewProjection; - Transforms xforms { + Transforms xforms{ MatrixStack{}, - viewProjection - }; + viewProjection}; NodeDefinition::CreateParams nodeParams{ resources, xforms, @@ -229,13 +224,13 @@ int UtcDaliDliLoaderLoadSceneExercise(void) Actor root = Actor::New(); SetActorCentered(root); - for (auto iRoot : scene.GetRoots()) + for(auto iRoot : scene.GetRoots()) { auto resourceRefs = resources.CreateRefCounter(); scene.CountResourceRefs(iRoot, choices, resourceRefs); resources.CountEnvironmentReferences(resourceRefs); resources.LoadResources(resourceRefs, ctx.pathProvider); - if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) + if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) { scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor); scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables)); @@ -257,49 +252,47 @@ int UtcDaliDliLoaderLoadSceneMorph(void) Context ctx; std::vector metadata; - uint32_t metadataCount = 0; - ctx.input.mPreNodeCategoryProcessors.push_back({ "metadata", - [&](const Property::Array& array, StringCallback) { - std::string key, value; - for (uint32_t i0 = 0, i1 = array.Count(); i0 < i1; ++i0) - { - auto& data = array.GetElementAt(i0); - DALI_TEST_EQUAL(data.GetType(), Property::MAP); - - auto map = data.GetMap(); - auto key = map->Find("key"); - auto value = map->Find("value"); - DALI_TEST_EQUAL(key->GetType(), Property::STRING); - DALI_TEST_EQUAL(value->GetType(), Property::STRING); - metadata.push_back(key->Get() + ":" + value->Get()); - - ++metadataCount; - } - } - }); + uint32_t metadataCount = 0; + ctx.input.mPreNodeCategoryProcessors.push_back({"metadata", + [&](const Property::Array& array, StringCallback) { + std::string key, value; + for(uint32_t i0 = 0, i1 = array.Count(); i0 < i1; ++i0) + { + auto& data = array.GetElementAt(i0); + DALI_TEST_EQUAL(data.GetType(), Property::MAP); + + auto map = data.GetMap(); + auto key = map->Find("key"); + auto value = map->Find("value"); + DALI_TEST_EQUAL(key->GetType(), Property::STRING); + DALI_TEST_EQUAL(value->GetType(), Property::STRING); + metadata.push_back(key->Get() + ":" + value->Get()); + + ++metadataCount; + } + }}); std::vector behaviors; - uint32_t behaviorCount = 0; - ctx.input.mPostNodeCategoryProcessors.push_back({ "behaviors", - [&](const Property::Array& array, StringCallback) { - for (uint32_t i0 = 0, i1 = array.Count(); i0 < i1; ++i0) - { - auto& data = array.GetElementAt(i0); - DALI_TEST_EQUAL(data.GetType(), Property::MAP); - - auto map = data.GetMap(); - auto event = map->Find("event"); - auto url = map->Find("url"); - DALI_TEST_EQUAL(event->GetType(), Property::STRING); - DALI_TEST_EQUAL(url->GetType(), Property::STRING); - behaviors.push_back(event->Get() + ":" + url->Get()); - - ++behaviorCount; - } - } - }); - - size_t numNodes = 0; + uint32_t behaviorCount = 0; + ctx.input.mPostNodeCategoryProcessors.push_back({"behaviors", + [&](const Property::Array& array, StringCallback) { + for(uint32_t i0 = 0, i1 = array.Count(); i0 < i1; ++i0) + { + auto& data = array.GetElementAt(i0); + DALI_TEST_EQUAL(data.GetType(), Property::MAP); + + auto map = data.GetMap(); + auto event = map->Find("event"); + auto url = map->Find("url"); + DALI_TEST_EQUAL(event->GetType(), Property::STRING); + DALI_TEST_EQUAL(url->GetType(), Property::STRING); + behaviors.push_back(event->Get() + ":" + url->Get()); + + ++behaviorCount; + } + }}); + + size_t numNodes = 0; ctx.input.mNodePropertyProcessor = [&](const NodeDefinition&, const Property::Map&, StringCallback) { ++numNodes; }; @@ -332,10 +325,9 @@ int UtcDaliDliLoaderLoadSceneMorph(void) DALI_TEST_EQUAL(behaviors.size(), 1u); ViewProjection viewProjection; - Transforms xforms { + Transforms xforms{ MatrixStack{}, - viewProjection - }; + viewProjection}; NodeDefinition::CreateParams nodeParams{ resources, xforms, @@ -347,13 +339,13 @@ int UtcDaliDliLoaderLoadSceneMorph(void) Actor root = Actor::New(); SetActorCentered(root); - for (auto iRoot : scene.GetRoots()) + for(auto iRoot : scene.GetRoots()) { auto resourceRefs = resources.CreateRefCounter(); scene.CountResourceRefs(iRoot, choices, resourceRefs); resources.CountEnvironmentReferences(resourceRefs); resources.LoadResources(resourceRefs, ctx.pathProvider); - if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) + if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) { scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor); scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables)); @@ -397,10 +389,9 @@ int UtcDaliDliLoaderLoadSceneArc(void) DALI_TEST_EQUAL(ctx.animGroups.size(), 0u); ViewProjection viewProjection; - Transforms xforms { + Transforms xforms{ MatrixStack{}, - viewProjection - }; + viewProjection}; NodeDefinition::CreateParams nodeParams{ resources, xforms, @@ -412,13 +403,13 @@ int UtcDaliDliLoaderLoadSceneArc(void) Actor root = Actor::New(); SetActorCentered(root); - for (auto iRoot : scene.GetRoots()) + for(auto iRoot : scene.GetRoots()) { auto resourceRefs = resources.CreateRefCounter(); scene.CountResourceRefs(iRoot, choices, resourceRefs); resources.CountEnvironmentReferences(resourceRefs); resources.LoadResources(resourceRefs, ctx.pathProvider); - if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) + if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) { scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor); scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables)); @@ -496,11 +487,10 @@ int UtcDaliDliLoaderLoadSceneExtras(void) DALI_TEST_EQUAL(scene.GetNodeCount(), 1u); ViewProjection viewProjection; - Transforms xforms { + Transforms xforms{ MatrixStack{}, - viewProjection - }; - auto& resources = ctx.resources; + viewProjection}; + auto& resources = ctx.resources; NodeDefinition::CreateParams nodeParams{ resources, xforms, @@ -509,7 +499,7 @@ int UtcDaliDliLoaderLoadSceneExtras(void) Customization::Choices choices; TestApplication app; - Actor actor = scene.CreateNodes(0, choices, nodeParams); + Actor actor = scene.CreateNodes(0, choices, nodeParams); DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("fudgeFactor")).Get(), 9000.1f); DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("fudgeVector")).Get(), Vector2(-.25f, 17.f)); @@ -541,11 +531,10 @@ int UtcDaliDliLoaderLoadSceneConstraints(void) DALI_TEST_EQUAL(scene.GetNodeCount(), 4u); ViewProjection viewProjection; - Transforms xforms { + Transforms xforms{ MatrixStack{}, - viewProjection - }; - auto& resources = ctx.resources; + viewProjection}; + auto& resources = ctx.resources; NodeDefinition::CreateParams nodeParams{ resources, xforms, @@ -555,9 +544,9 @@ int UtcDaliDliLoaderLoadSceneConstraints(void) TestApplication app; - Actor root = scene.CreateNodes(0, choices, nodeParams); - Actor alice = root.FindChildByName("Alice"); - Actor bob = root.FindChildByName("Bob"); + Actor root = scene.CreateNodes(0, choices, nodeParams); + Actor alice = root.FindChildByName("Alice"); + Actor bob = root.FindChildByName("Bob"); Actor charlie = root.FindChildByName("Charlie"); DALI_TEST_EQUAL(nodeParams.mConstrainables.size(), 3u); @@ -639,3 +628,78 @@ int UtcDaliDliLoaderNodeProcessor(void) END_TEST; } + +int UtcDaliDliLoaderLoadCoverageTest(void) +{ + Context ctx; + + auto path = ctx.pathProvider(ResourceType::Mesh) + "coverageTest.dli"; + DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams)); + DALI_TEST_CHECK(ctx.errors.empty()); + + auto& scene = ctx.scene; + auto& roots = scene.GetRoots(); + DALI_TEST_EQUAL(roots.size(), 1u); + DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "root"); + + DALI_TEST_EQUAL(scene.GetNodeCount(), 1u); + + auto& resources = ctx.resources; + DALI_TEST_EQUAL(resources.mMeshes.size(), 1u); + DALI_TEST_EQUAL(resources.mShaders.size(), 1u); + DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 2u); + DALI_TEST_EQUAL(resources.mSkeletons.size(), 0u); + + auto& materials = ctx.resources.mMaterials; + DALI_TEST_EQUAL(2u, materials.size()); + + auto iMaterial = materials.begin(); + auto& md = iMaterial->first; + DALI_TEST_EQUAL(md.mTextureStages.size(), 1u); + + auto iTexture = md.mTextureStages.begin(); + DALI_TEST_CHECK(MaskMatch(iTexture->mSemantic, MaterialDefinition::OCCLUSION)); + DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, "exercise/Icons/Icon_Idle.png"); + ++iTexture; + + DALI_TEST_EQUAL(ctx.cameraParameters.size(), 1u); + DALI_TEST_EQUAL(ctx.lights.size(), 1u); + DALI_TEST_EQUAL(ctx.animations.size(), 0u); + DALI_TEST_EQUAL(ctx.animGroups.size(), 0u); + + ViewProjection viewProjection; + Transforms xforms{ + MatrixStack{}, + viewProjection}; + NodeDefinition::CreateParams nodeParams{ + resources, + xforms, + }; + + Customization::Choices choices; + + TestApplication app; + + Actor root = Actor::New(); + SetActorCentered(root); + for(auto iRoot : scene.GetRoots()) + { + auto resourceRefs = resources.CreateRefCounter(); + scene.CountResourceRefs(iRoot, choices, resourceRefs); + resources.CountEnvironmentReferences(resourceRefs); + resources.LoadResources(resourceRefs, ctx.pathProvider); + if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) + { + scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor); + scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables)); + ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests)); + scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables)); + root.Add(actor); + } + } + + DALI_TEST_EQUAL(root.GetChildCount(), 1u); + DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get(), "root"); + + END_TEST; +} diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp index c1b5481..80ed66d 100644 --- a/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp +++ b/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,20 +18,19 @@ // Enable debug log for test coverage #define DEBUG_ENABLED 1 +#include +#include +#include #include "dali-scene-loader/public-api/gltf2-loader.h" -#include "dali-scene-loader/public-api/shader-definition-factory.h" #include "dali-scene-loader/public-api/node-definition.h" #include "dali-scene-loader/public-api/resource-bundle.h" -#include -#include -#include +#include "dali-scene-loader/public-api/shader-definition-factory.h" using namespace Dali; using namespace Dali::SceneLoader; namespace { - bool EndsWith(const std::string& str, const std::string& suffix) // ends_width() is C++20 { return str.size() >= suffix.size() && str.substr(str.size() - suffix.size()).compare(suffix) == 0; @@ -57,7 +56,7 @@ void ClearMeshesAndMaterials(ResourceBundle& resources) struct Context { - ResourceBundle resources; + ResourceBundle resources; ShaderDefinitionFactory factory; Context() @@ -68,29 +67,29 @@ struct Context struct ShaderParameters { - MeshDefinition& meshDef; + MeshDefinition& meshDef; MaterialDefinition& materialDef; - NodeDefinition& nodeDef; + NodeDefinition& nodeDef; }; struct Permutation { - using ConfigureFn = void(*)(ShaderParameters&); + using ConfigureFn = void (*)(ShaderParameters&); ConfigureFn configureFn; std::set defines; - RendererState::Type rendererStateSet = 0; - RendererState::Type rendererStateClear = 0; + RendererState::Type rendererStateSet = 0; + RendererState::Type rendererStateClear = 0; }; struct PermutationSet { std::vector permutations; - Index shaderIdx; + Index shaderIdx; }; -} +} // namespace int UtcDaliShaderDefinitionFactoryProduceShaderInvalid(void) { @@ -121,173 +120,157 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void) [](ShaderParameters& p) { p.materialDef.mFlags |= MaterialDefinition::TRANSPARENCY; }, - { "THREE_TEX" }, + {"THREE_TEX"}, RendererState::ALPHA_BLEND, RendererState::DEPTH_WRITE, }, - { - [](ShaderParameters& p) { - p.materialDef.mTextureStages.push_back({ MaterialDefinition::ALBEDO, {} }); - }, - { "THREE_TEX" } - }, - { - [](ShaderParameters& p) { - p.materialDef.mTextureStages.push_back({ MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS, {} }); - }, - { "THREE_TEX" } - }, - { - [](ShaderParameters& p) { - p.materialDef.mTextureStages.push_back({ MaterialDefinition::NORMAL, {} }); - }, - { "THREE_TEX" } - }, - { - [](ShaderParameters& p) { - p.materialDef.mFlags |= MaterialDefinition::SUBSURFACE; - }, - { "SSS" } - }, - { - [](ShaderParameters& p) { - p.materialDef.SetAlphaCutoff(.5f); - }, - { "ALPHA_TEST" } - }, - { - [](ShaderParameters& p) { - p.materialDef.SetAlphaCutoff(1.f); - }, - { "ALPHA_TEST" } - }, - { - [](ShaderParameters& p) { - p.materialDef.mFlags |= MaterialDefinition::GLTF_CHANNELS; - }, - { "GLTF_CHANNELS" } - }, - { - [](ShaderParameters& p) { - p.meshDef.mJoints0.mBlob.mOffset = 0; - p.meshDef.mWeights0.mBlob.mOffset = 0; - }, - { "SKINNING" } - }, - { - [](ShaderParameters& p) { - p.meshDef.mFlags |= MeshDefinition::FLIP_UVS_VERTICAL; - }, - { "FLIP_V" } - }, + {[](ShaderParameters& p) { + p.materialDef.mTextureStages.push_back({MaterialDefinition::ALBEDO, {}}); + }, + {"THREE_TEX"}}, + {[](ShaderParameters& p) { + p.materialDef.mTextureStages.push_back({MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS, {}}); + }, + {"THREE_TEX"}}, + {[](ShaderParameters& p) { + p.materialDef.mTextureStages.push_back({MaterialDefinition::NORMAL, {}}); + }, + {"THREE_TEX"}}, + {[](ShaderParameters& p) { + p.materialDef.mFlags |= MaterialDefinition::SUBSURFACE; + }, + {"SSS"}}, + {[](ShaderParameters& p) { + p.materialDef.SetAlphaCutoff(.5f); + }, + {"ALPHA_TEST"}}, + {[](ShaderParameters& p) { + p.materialDef.SetAlphaCutoff(1.f); + }, + {"ALPHA_TEST"}}, + {[](ShaderParameters& p) { + p.materialDef.mFlags |= MaterialDefinition::GLTF_CHANNELS; + }, + {"GLTF_CHANNELS"}}, + {[](ShaderParameters& p) { + p.meshDef.mJoints0.mBlob.mOffset = 0; + p.meshDef.mWeights0.mBlob.mOffset = 0; + }, + {"SKINNING"}}, + {[](ShaderParameters& p) { + p.meshDef.mFlags |= MeshDefinition::FLIP_UVS_VERTICAL; + }, + {"FLIP_V"}}, { [](ShaderParameters& p) { p.meshDef.mBlendShapes.push_back({}); }, }, - { - [](ShaderParameters& p) { - p.meshDef.mBlendShapes.back().deltas.mBlob.mOffset = 0; - }, - { "MORPH_POSITION", "MORPH" } - }, - { - [](ShaderParameters& p) { - p.meshDef.mBlendShapes.back().normals.mBlob.mOffset = 0; - }, - { "MORPH_NORMAL", "MORPH" } - }, - { - [](ShaderParameters& p) { - p.meshDef.mBlendShapes.back().tangents.mBlob.mOffset = 0; - }, - { "MORPH_TANGENT", "MORPH" } - }, - { - [](ShaderParameters& p) { - auto& blendShapes = p.meshDef.mBlendShapes; - DALI_ASSERT_ALWAYS(!blendShapes.empty() && - (blendShapes.back().deltas.mBlob.mOffset != MeshDefinition::INVALID || - blendShapes.back().normals.mBlob.mOffset != MeshDefinition::INVALID || - blendShapes.back().tangents.mBlob.mOffset != MeshDefinition::INVALID)); - p.meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0; - }, - { "MORPH_VERSION_2_0" } - }, + {[](ShaderParameters& p) { + p.meshDef.mBlendShapes.back().deltas.mBlob.mOffset = 0; + }, + {"MORPH_POSITION", "MORPH"}}, + {[](ShaderParameters& p) { + p.meshDef.mBlendShapes.back().normals.mBlob.mOffset = 0; + }, + {"MORPH_NORMAL", "MORPH"}}, + {[](ShaderParameters& p) { + p.meshDef.mBlendShapes.back().tangents.mBlob.mOffset = 0; + }, + {"MORPH_TANGENT", "MORPH"}}, + {[](ShaderParameters& p) { + auto& blendShapes = p.meshDef.mBlendShapes; + DALI_ASSERT_ALWAYS(!blendShapes.empty() && + (blendShapes.back().deltas.mBlob.mOffset != MeshDefinition::INVALID || + blendShapes.back().normals.mBlob.mOffset != MeshDefinition::INVALID || + blendShapes.back().tangents.mBlob.mOffset != MeshDefinition::INVALID)); + p.meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0; + }, + {"MORPH_VERSION_2_0"}}, + + {[](ShaderParameters& p) { + p.materialDef.mFlags |= MaterialDefinition::OCCLUSION; + }, + + {"OCCLUSION"}}, }; - PermutationSet permSets[] { + PermutationSet permSets[]{ // default - { { &permutations[0] }, 0 }, + {{&permutations[0]}, 0}, // alpha - { { &permutations[0], &permutations[1] }, 1 }, + {{&permutations[0], &permutations[1]}, 1}, // three-texture setups - { { &permutations[0], &permutations[2] }, 2 }, - { { &permutations[0], &permutations[3] }, 2 }, - { { &permutations[0], &permutations[4] }, 2 }, - { { &permutations[0], &permutations[2], &permutations[3] }, 2 }, - { { &permutations[0], &permutations[3], &permutations[4] }, 2 }, - { { &permutations[0], &permutations[4], &permutations[2] }, 2 }, - { { &permutations[0], &permutations[2], &permutations[3], &permutations[4] }, 2 }, + {{&permutations[0], &permutations[2]}, 2}, + {{&permutations[0], &permutations[3]}, 2}, + {{&permutations[0], &permutations[4]}, 2}, + {{&permutations[0], &permutations[2], &permutations[3]}, 2}, + {{&permutations[0], &permutations[3], &permutations[4]}, 2}, + {{&permutations[0], &permutations[4], &permutations[2]}, 2}, + {{&permutations[0], &permutations[2], &permutations[3], &permutations[4]}, 2}, // subsurface scattering - { { &permutations[0], &permutations[5] }, 3 }, + {{&permutations[0], &permutations[5]}, 3}, // alpha test - { { &permutations[0], &permutations[6] }, 4 }, - { { &permutations[0], &permutations[7] }, 4 }, + {{&permutations[0], &permutations[6]}, 4}, + {{&permutations[0], &permutations[7]}, 4}, // glTF channels - { { &permutations[0], &permutations[8] }, 5 }, + {{&permutations[0], &permutations[8]}, 5}, // skinning - { { &permutations[0], &permutations[9] }, 6 }, + {{&permutations[0], &permutations[9]}, 6}, // flip uvs - { { &permutations[0], &permutations[10] }, 7 }, + {{&permutations[0], &permutations[10]}, 7}, // morphing - { { &permutations[0], &permutations[11], &permutations[12] }, 8 }, - { { &permutations[0], &permutations[11], &permutations[13] }, 9 }, - { { &permutations[0], &permutations[11], &permutations[14] }, 10 }, - { { &permutations[0], &permutations[11], &permutations[12], &permutations[13] }, 11 }, - { { &permutations[0], &permutations[11], &permutations[13], &permutations[14] }, 12 }, - { { &permutations[0], &permutations[11], &permutations[14], &permutations[12] }, 13 }, - { { &permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14] }, 14 }, - - { { &permutations[0], &permutations[11], &permutations[12], &permutations[15] }, 15 }, - { { &permutations[0], &permutations[11], &permutations[13], &permutations[15] }, 16 }, - { { &permutations[0], &permutations[11], &permutations[14], &permutations[15] }, 17 }, - { { &permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[15] }, 18 }, - { { &permutations[0], &permutations[11], &permutations[13], &permutations[14], &permutations[15] }, 19 }, - { { &permutations[0], &permutations[11], &permutations[14], &permutations[12], &permutations[15] }, 20 }, - { { &permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14], &permutations[15] }, 21 }, + {{&permutations[0], &permutations[11], &permutations[12]}, 8}, + {{&permutations[0], &permutations[11], &permutations[13]}, 9}, + {{&permutations[0], &permutations[11], &permutations[14]}, 10}, + {{&permutations[0], &permutations[11], &permutations[12], &permutations[13]}, 11}, + {{&permutations[0], &permutations[11], &permutations[13], &permutations[14]}, 12}, + {{&permutations[0], &permutations[11], &permutations[14], &permutations[12]}, 13}, + {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14]}, 14}, + + {{&permutations[0], &permutations[11], &permutations[12], &permutations[15]}, 15}, + {{&permutations[0], &permutations[11], &permutations[13], &permutations[15]}, 16}, + {{&permutations[0], &permutations[11], &permutations[14], &permutations[15]}, 17}, + {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[15]}, 18}, + {{&permutations[0], &permutations[11], &permutations[13], &permutations[14], &permutations[15]}, 19}, + {{&permutations[0], &permutations[11], &permutations[14], &permutations[12], &permutations[15]}, 20}, + {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14], &permutations[15]}, 21}, // etc. - { { &permutations[0], &permutations[1], &permutations[2] }, 1 }, - { { &permutations[0], &permutations[1], &permutations[3] }, 1 }, - { { &permutations[0], &permutations[1], &permutations[2], &permutations[3] }, 1 }, + {{&permutations[0], &permutations[1], &permutations[2]}, 1}, + {{&permutations[0], &permutations[1], &permutations[3]}, 1}, + {{&permutations[0], &permutations[1], &permutations[2], &permutations[3]}, 1}, + + // occlusion + {{&permutations[0], &permutations[16]}, 22}, }; - for(auto& ps: permSets) + + for(auto& ps : permSets) { printf("%ld\n", &ps - permSets); - auto modelNode = new ModelNode(); - modelNode->mMeshIdx = 0; + auto modelNode = new ModelNode(); + modelNode->mMeshIdx = 0; modelNode->mMaterialIdx = 0; NodeDefinition nodeDef; nodeDef.mRenderable.reset(modelNode); - auto& meshDef = NewMeshDefinition(ctx.resources); - auto& materialDef = NewMaterialDefinition(ctx.resources); - ShaderParameters sp{ meshDef, materialDef, nodeDef }; + auto& meshDef = NewMeshDefinition(ctx.resources); + auto& materialDef = NewMaterialDefinition(ctx.resources); + ShaderParameters sp{meshDef, materialDef, nodeDef}; std::set defines; - RendererState::Type rendererState = 0; - for (auto p : ps.permutations) + RendererState::Type rendererState = 0; + for(auto p : ps.permutations) { p->configureFn(sp); defines.insert(p->defines.begin(), p->defines.end()); @@ -303,10 +286,10 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void) DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState); uint32_t definesUnmatched = shaderDef.mDefines.size(); - for (auto& d: shaderDef.mDefines) + for(auto& d : shaderDef.mDefines) { auto iFind = defines.find(d); - if (iFind != defines.end()) + if(iFind != defines.end()) { defines.erase(iFind); --definesUnmatched; diff --git a/dali-scene-loader/public-api/dli-loader.cpp b/dali-scene-loader/public-api/dli-loader.cpp index 48a82c3..3031c5e 100644 --- a/dali-scene-loader/public-api/dli-loader.cpp +++ b/dali-scene-loader/public-api/dli-loader.cpp @@ -1014,6 +1014,14 @@ void DliLoader::Impl::ParseMaterials(const TreeNode* materials, ConvertColorCode materialDef.mFlags |= semantic; } + if(ReadString(node.GetChild("occlusionMap"), texturePath)) + { + ToUnixFileSeparators(texturePath); + const auto semantic = MaterialDefinition::OCCLUSION; + materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}}); + materialDef.mFlags |= semantic; + } + if(ReadColorCodeOrColor(&node, materialDef.mColor, convertColorCode) && materialDef.mColor.a < 1.0f) { diff --git a/dali-scene-loader/public-api/material-definition.cpp b/dali-scene-loader/public-api/material-definition.cpp index c0e816c..3c7a391 100644 --- a/dali-scene-loader/public-api/material-definition.cpp +++ b/dali-scene-loader/public-api/material-definition.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -217,6 +217,12 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const ++iTexture; } + if(checkStage(OCCLUSION)) + { + raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); + ++iTexture; + } + return raw; } diff --git a/dali-scene-loader/public-api/shader-definition-factory.cpp b/dali-scene-loader/public-api/shader-definition-factory.cpp index 843fbcf..bd6b168 100644 --- a/dali-scene-loader/public-api/shader-definition-factory.cpp +++ b/dali-scene-loader/public-api/shader-definition-factory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -96,6 +96,11 @@ uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& mater hash.Add("SSS"); } + if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION)) + { + hash.Add("OCCL" /*USION*/); + } + if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS)) { hash.Add("GLTF" /*_CHANNELS*/); @@ -217,6 +222,11 @@ Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef) shaderDef.mDefines.push_back("SSS"); } + if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::OCCLUSION)) + { + shaderDef.mDefines.push_back("OCCLUSION"); + } + if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::GLTF_CHANNELS)) { shaderDef.mDefines.push_back("GLTF_CHANNELS");