From 0916db4ae20611f2c6d8738882089eaa3e7a5d2d Mon Sep 17 00:00:00 2001 From: seungho Date: Mon, 25 Apr 2022 23:38:15 +0900 Subject: [PATCH] Modify default shader according to the gltf pbr spec - Add uColorFactor. In glTF, color factor can be used as a color when there isn't color texture, but it is also used to be multiplied with base color that is sampled from color texture. In previous implementation, when there isn't color texture, color factor is converted as single pixel texture. If the texture is from color factor, we shouldn't multiply color factor again. But, we couldn't notify whether the texture is from image file or color factor. - Add vertex color - Add uMetallicFactor, uRoughnessFactor - Use #ifdef instead of single value texture. - Use pre-computed brdf texture. - Modify alpha mode Change-Id: I048b793a4481b65da5ce07d0d3e263ae74b2ab59 Signed-off-by: seungho --- automated-tests/resources/AnimatedCube.gltf | 3 - .../src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp | 49 +++- .../utc-Dali-ShaderDefinitionFactory.cpp | 11 +- .../shaders/default-physically-based-shader.frag | 315 ++++++++++++--------- .../shaders/default-physically-based-shader.vert | 41 ++- .../public-api/environment-definition.cpp | 35 ++- .../public-api/environment-definition.h | 7 +- dali-scene-loader/public-api/gltf2-loader.cpp | 44 ++- .../public-api/material-definition.cpp | 34 ++- dali-scene-loader/public-api/material-definition.h | 20 +- dali-scene-loader/public-api/mesh-definition.cpp | 31 +- dali-scene-loader/public-api/mesh-definition.h | 2 + dali-scene-loader/public-api/node-definition.cpp | 22 +- .../public-api/shader-definition-factory.cpp | 27 +- 14 files changed, 420 insertions(+), 221 deletions(-) diff --git a/automated-tests/resources/AnimatedCube.gltf b/automated-tests/resources/AnimatedCube.gltf index 2f78e20..995d3b1 100644 --- a/automated-tests/resources/AnimatedCube.gltf +++ b/automated-tests/resources/AnimatedCube.gltf @@ -202,9 +202,6 @@ "baseColorTexture" : { "index" : 0 }, - "metallicRoughnessTexture" : { - "index" : 1 - }, "baseColorFactor": [ 1.000, 0.766, 0.336, 1.0 ], "metallicFactor": 1.0, "roughnessFactor": 0.0 diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp index b4dceb9..4a40524 100644 --- a/automated-tests/src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp +++ b/automated-tests/src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp @@ -161,28 +161,30 @@ int UtcDaliGltfLoaderSuccess1(void) DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size()); DALI_TEST_EQUAL(6u, ctx.scene.GetNodeCount()); - DALI_TEST_EQUAL(0u, ctx.resources.mEnvironmentMaps.size()); + // Default envmap is used + DALI_TEST_EQUAL(1u, ctx.resources.mEnvironmentMaps.size()); auto& materials = ctx.resources.mMaterials; DALI_TEST_EQUAL(2u, materials.size()); const MaterialDefinition materialGroundTruth[]{ - {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | - MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | - MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | MaterialDefinition::GLTF_CHANNELS | + {MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | + MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT), 0, - Vector4(1.f, .766f, .336f, 1.f), - Vector3(0.2, 0.1, 0.0), + Color::WHITE, 1.f, 0.f, + Vector4(1.000, 0.766, 0.336, 1.0), + 1.f, 1.f, + Vector3(0.2, 0.1, 0.0), + true, + false, + true, { {MaterialDefinition::ALBEDO, {"AnimatedCube_BaseColor.png", SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, - {MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS, - {"AnimatedCube_MetallicRoughness.png", - SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT)}}, {MaterialDefinition::NORMAL, {"AnimatedCube_BaseColor.png", SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}}, @@ -197,11 +199,16 @@ int UtcDaliGltfLoaderSuccess1(void) MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS, 0, - Vector4(1.f, .766f, .336f, 1.f), - Vector3(0.2, 0.1, 0.0), + Color::WHITE, 1.f, 0.f, + Vector4(1.000, 0.766, 0.336, 1.0), 1.f, + 1.f, + Vector3(0.2, 0.1, 0.0), + true, + true, + true, { {MaterialDefinition::ALBEDO, {"AnimatedCube_BaseColor.png", @@ -231,6 +238,13 @@ int UtcDaliGltfLoaderSuccess1(void) DALI_TEST_EQUAL(md.mColor, m.mColor); DALI_TEST_EQUAL(md.mMetallic, m.mMetallic); DALI_TEST_EQUAL(md.mRoughness, m.mRoughness); + DALI_TEST_EQUAL(md.mBaseColorFactor, m.mBaseColorFactor); + DALI_TEST_EQUAL(md.mNormalScale, m.mNormalScale); + DALI_TEST_EQUAL(md.mOcclusionStrength, m.mOcclusionStrength); + DALI_TEST_EQUAL(md.mEmissiveFactor, m.mEmissiveFactor); + DALI_TEST_EQUAL(md.mNeedAlbedoTexture, m.mNeedAlbedoTexture); + DALI_TEST_EQUAL(md.mNeedMetallicRoughnessTexture, m.mNeedMetallicRoughnessTexture); + DALI_TEST_EQUAL(md.mNeedNormalTexture, m.mNeedNormalTexture); DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size()); auto iTexture = md.mTextureStages.begin(); @@ -260,6 +274,7 @@ int UtcDaliGltfLoaderSuccess1(void) Accessor{Blob{0, 0}, {}}, Accessor{Blob{0, 0}, {}}, Accessor{Blob{0, 0}, {}}, + Accessor{Blob{0, 0}, {}}, }, { 0, @@ -270,6 +285,7 @@ int UtcDaliGltfLoaderSuccess1(void) Accessor{Blob{0, 0}, {}}, Accessor{Blob{0, 0}, {}}, Accessor{Blob{0, 0}, {}}, + Accessor{Blob{0, 0}, {}}, }, }; @@ -286,6 +302,7 @@ int UtcDaliGltfLoaderSuccess1(void) &MeshDefinition::mPositions, &MeshDefinition::mNormals, &MeshDefinition::mTexCoords, + &MeshDefinition::mColors, &MeshDefinition::mTangents, &MeshDefinition::mJoints0, &MeshDefinition::mWeights0}) @@ -333,6 +350,7 @@ int UtcDaliGltfLoaderSuccessShort(void) "MorphPrimitivesTest", "MRendererTest", "SimpleSparseAccessor", + "AnimatedCube", }) { Context ctx; @@ -405,7 +423,6 @@ int UtcDaliGltfLoaderMRendererTest(void) ShaderDefinitionFactory sdf; sdf.SetResources(ctx.resources); auto& resources = ctx.resources; - resources.mEnvironmentMaps.push_back({}); LoadGltfScene(TEST_RESOURCE_DIR "/MRendererTest.gltf", sdf, ctx.loadResult); @@ -448,8 +465,12 @@ int UtcDaliGltfLoaderMRendererTest(void) } DALI_TEST_EQUAL(root.GetChildCount(), 1u); - DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get(), "RootNode"); - DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::SCALE).Get(), Vector3(1.0f, 1.0f, 1.0f)); + Actor child = root.GetChildAt(0); + + DALI_TEST_EQUAL(child.GetProperty(Actor::Property::NAME).Get(), "RootNode"); + DALI_TEST_EQUAL(child.GetProperty(Actor::Property::SCALE).Get(), Vector3(1.0f, 1.0f, 1.0f)); + DALI_TEST_EQUAL(child.GetRendererCount(), 1u); + DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 4u); 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 3fd8fbb..534189e 100644 --- a/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp +++ b/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp @@ -108,7 +108,7 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void) Permutation permutations[]{ { [](ShaderParameters& p) {}, - {}, + {"THREE_TEX"}, RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK, }, { @@ -250,8 +250,6 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void) for(auto& ps : permSets) { - printf("%ld\n", &ps - permSets); - auto modelNode = new ModelNode(); modelNode->mMeshIdx = 0; modelNode->mMaterialIdx = 0; @@ -279,9 +277,9 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void) DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState); uint32_t definesUnmatched = shaderDef.mDefines.size(); - for(auto& d : shaderDef.mDefines) + for(auto& define : shaderDef.mDefines) { - auto iFind = defines.find(d); + auto iFind = defines.find(define); if(iFind != defines.end()) { defines.erase(iFind); @@ -289,7 +287,6 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void) } else { - printf("mismatched: %s\n", d.c_str()); break; } } @@ -297,8 +294,6 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void) DALI_TEST_CHECK(defines.empty()); DALI_TEST_EQUAL(0, definesUnmatched); - printf("defines OK\n"); - auto uMaxLOD = shaderDef.mUniforms["uMaxLOD"]; DALI_TEST_EQUAL(uMaxLOD.GetType(), Property::FLOAT); diff --git a/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.frag b/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.frag index 2581ad6..8f927f5 100644 --- a/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.frag +++ b/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.frag @@ -1,14 +1,30 @@ +// Original Code +// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/glTF-WebGL-PBR/shaders/pbr-frag.glsl +// Commit dc84b5e374fb3d23153d2248a338ef88173f9eb6 +// +// This fragment shader defines a reference implementation for Physically Based Shading of +// a microfacet surface material defined by a glTF model.For the DamagedHelmet.gltf and its Assets +// +// References: +// [1] Real Shading in Unreal Engine 4 +// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf +// [2] Physically Based Shading at Disney +// http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf +// [3] README.md - Environment Maps +// https://github.com/KhronosGroup/glTF-Sample-Viewer/#environment-maps +// [4] \"An Inexpensive BRDF Model for Physically based Rendering\" by Christophe Schlick +// https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf + #version 300 es #ifdef HIGHP - precision highp float; +precision highp float; #else - precision mediump float; +precision mediump float; #endif #ifdef THREE_TEX #ifdef GLTF_CHANNELS -// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#pbrmetallicroughnessmetallicroughnesstexture #define METALLIC b #define ROUGHNESS g #else //GLTF_CHANNELS @@ -17,167 +33,192 @@ #endif //GLTF_CHANNELS #endif //THREE_TEX -#ifdef THREE_TEX - uniform sampler2D sAlbedoAlpha; - uniform sampler2D sMetalRoughness; - uniform sampler2D sNormal; - -#ifdef ALPHA_TEST - uniform float uAlphaThreshold; -#endif //ALPHA_TEST +uniform lowp vec4 uColorFactor; +uniform lowp float uMetallicFactor; +uniform lowp float uRoughnessFactor; -#else - uniform sampler2D sAlbedoMetal; - uniform sampler2D sNormalRoughness; +#ifdef THREE_TEX +#ifdef BASECOLOR_TEX +uniform sampler2D sAlbedoAlpha; +#endif // BASECOLOR_TEX +#ifdef METALLIC_ROUGHNESS_TEX +uniform sampler2D sMetalRoughness; +#endif // METALLIC_ROUGHNESS_TEX +#ifdef NORMAL_TEX +uniform sampler2D sNormal; +uniform float uNormalScale; +#endif // NORMAL_TEX +#else // THREE_TEX +uniform sampler2D sAlbedoMetal; +uniform sampler2D sNormalRoughness; #endif #ifdef OCCLUSION - uniform sampler2D sOcclusion; - uniform float uOcclusionStrength; +uniform sampler2D sOcclusion; +uniform float uOcclusionStrength; #endif #ifdef EMISSIVE - uniform sampler2D sEmissive; - uniform vec3 uEmissiveFactor; +uniform sampler2D sEmissive; +uniform vec3 uEmissiveFactor; #endif -uniform samplerCube sDiffuse; -uniform samplerCube sSpecular; - -// Number of mip map levels in the texture -uniform float uMaxLOD; - -// Transformation matrix of the cubemap texture -uniform mat4 uCubeMatrix; - -uniform vec4 uColor; -uniform float uMetallicFactor; -uniform float uRoughnessFactor; - -//IBL Light intensity +//// For IBL +uniform samplerCube sDiffuseEnvSampler; +uniform samplerCube sSpecularEnvSampler; +uniform sampler2D sbrdfLUT; uniform float uIblIntensity; +// For Alpha Mode. +uniform lowp float uOpaque; +uniform lowp float uMask; +uniform lowp float uAlphaThreshold; + // TODO: Multiple texture coordinate will be supported. -in vec2 vUV; -in vec3 vNormal; -in vec3 vTangent; -in vec3 vViewVec; +in lowp vec2 vUV; +in lowp mat3 vTBN; +in lowp vec4 vColor; +in highp vec3 vPositionToCamera; out vec4 FragColor; -// Functions for BRDF calculation come from -// https://www.unrealengine.com/blog/physically-based-shading-on-mobile -// Based on the paper by Dimitar Lazarov -// http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf -vec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV ) +struct PBRInfo { - const vec4 c0 = vec4( -1.0, -0.0275, -0.572, 0.022 ); - const vec4 c1 = vec4( 1.0, 0.0425, 1.04, -0.04 ); - vec4 r = Roughness * c0 + c1; - float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y; - vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw; - - return SpecularColor * AB.x + AB.y; + mediump float NdotL; // cos angle between normal and light direction + mediump float NdotV; // cos angle between normal and view direction + mediump float NdotH; // cos angle between normal and half vector + mediump float VdotH; // cos angle between view direction and half vector + mediump vec3 reflectance0; // full reflectance color (normal incidence angle) + mediump vec3 reflectance90; // reflectance color at grazing angle + lowp float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) +}; + +const float M_PI = 3.141592653589793; +const float c_MinRoughness = 0.04; + +vec3 specularReflection(PBRInfo pbrInputs) +{ + return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); } -void main() +float geometricOcclusion(PBRInfo pbrInputs) { - // We get information from the maps (albedo, normal map, roughness, metalness - // I access the maps in the order they will be used -#ifdef THREE_TEX - vec4 albedoAlpha = texture(sAlbedoAlpha, vUV.st); - float alpha = albedoAlpha.a; -#ifdef ALPHA_TEST - if (alpha <= uAlphaThreshold) - { - discard; - } -#endif //ALPHA_TEST - vec3 albedoColor = albedoAlpha.rgb * uColor.rgb; - - vec4 metalRoughness = texture(sMetalRoughness, vUV.st); - float metallic = metalRoughness.METALLIC * uMetallicFactor; - float roughness = metalRoughness.ROUGHNESS * uRoughnessFactor; - - vec3 normalMap = texture(sNormal, vUV.st).rgb; -#else //THREE_TEX - vec4 albedoMetal = texture(sAlbedoMetal, vUV.st); - vec3 albedoColor = albedoMetal.rgb * uColor.rgb; - float metallic = albedoMetal.a * uMetallicFactor; - - vec4 normalRoughness = texture(sNormalRoughness, vUV.st); - vec3 normalMap = normalRoughness.rgb; - float roughness = normalRoughness.a * uRoughnessFactor; -#endif - //Normalize vectors - vec3 normal = normalize(vNormal); - vec3 tangent = normalize(vTangent); - - // NOTE: normal and tangent have to be orthogonal for the result of the cross() - // product to be a unit vector. We might find that we need to normalize(). - vec3 bitangent = cross(normal, tangent); - - vec3 viewVec = normalize(vViewVec); - - // Create Inverse Local to world matrix - mat3 vInvTBN = mat3(tangent, bitangent, normal); - - // Get normal map info in world space - normalMap = normalize(normalMap - 0.5); - vec3 newNormal = vInvTBN * normalMap.rgb; + mediump float NdotL = pbrInputs.NdotL; + mediump float NdotV = pbrInputs.NdotV; + lowp float r = pbrInputs.alphaRoughness; - // Calculate normal dot view vector - float NoV = max(dot(newNormal, -viewVec), 0.0); - - // Reflect vector - vec3 reflectionVec = reflect(viewVec, newNormal); - - //transform it now to environment coordinates (used when the environment rotates) - vec3 reflecCube = (uCubeMatrix * vec4( reflectionVec, 0.0 ) ).xyz; - reflecCube = normalize( reflecCube ); - - //transform it now to environment coordinates - vec3 normalCube = ( uCubeMatrix * vec4( newNormal, 0.0 ) ).xyz; - normalCube = normalize( normalCube ); - - // Get irradiance from diffuse cubemap - vec3 irradiance = texture( sDiffuse, normalCube ).rgb; - - // Access reflection color using roughness value - float finalLod = mix( 0.0, uMaxLOD - 2.0, roughness); - vec3 reflectionColor = textureLod(sSpecular, reflecCube, finalLod).rgb; - - // We are supposed to be using DielectricColor (0.04) of a plastic (almost everything) - // http://blog.selfshadow.com/publications/s2014-shading-course/hoffman/s2014_pbs_physics_math_slides.pdf - // however that seems to prevent achieving very dark tones (i.e. get dark gray blacks). - vec3 DiffuseColor = albedoColor - albedoColor * metallic; // 1 mad - vec3 SpecularColor = mix( vec3(0.04), albedoColor, metallic); // 2 mad - - // Calculate specular color using Magic Function (takes original roughness and normal dot view). - vec3 specColor = reflectionColor.rgb * EnvBRDFApprox(SpecularColor, roughness, NoV ); + lowp float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); + lowp float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); + return attenuationL * attenuationV; +} - // Multiply the result by albedo texture and do energy conservation - vec3 diffuseColor = irradiance * DiffuseColor; +float microfacetDistribution(PBRInfo pbrInputs) +{ + mediump float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; + lowp float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; + return roughnessSq / (M_PI * f * f); +} - // Final color is the sum of the diffuse and specular term - vec3 finalColor = diffuseColor + specColor; +vec3 linear(vec3 color) +{ + return pow(color, vec3(2.2)); +} - finalColor = sqrt( finalColor ) * uIblIntensity; +void main() +{ + // Metallic and Roughness material properties are packed together + // In glTF, these factors can be specified by fixed scalar values + // or from a metallic-roughness map + // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. + // This layout intentionally reserves the 'r' channel for (optional) occlusion map data + lowp float metallic = uMetallicFactor; + lowp float perceptualRoughness = uRoughnessFactor; + // If there isn't normal texture, use surface normal + mediump vec3 n = normalize(vTBN[2].xyz); +#ifdef THREE_TEX + // The albedo may be defined from a base texture or a flat color +#ifdef BASECOLOR_TEX + lowp vec4 baseColor = texture(sAlbedoAlpha, vUV); + baseColor = vec4(linear(baseColor.rgb), baseColor.w) * uColorFactor; +#else // BASECOLOR_TEX + lowp vec4 baseColor = vColor * uColorFactor; +#endif // BASECOLOR_TEX + +#ifdef METALLIC_ROUGHNESS_TEX + lowp vec4 metrou = texture(sMetalRoughness, vUV); + metallic = metrou.METALLIC * metallic; + perceptualRoughness = metrou.ROUGHNESS * perceptualRoughness; +#endif // METALLIC_ROUGHNESS_TEX + +#ifdef NORMAL_TEX + n = texture(sNormal, vUV).rgb; + n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0))); +#endif // NORMAL_TEX +#else // THREE_TEX + vec4 albedoMetal = texture(sAlbedoMetal, vUV); + lowp vec4 baseColor = vec4(linear(albedoMetal.rgb), 1.0) * vColor * uColorFactor; + + metallic = albedoMetal.METALLIC * metallic; + + vec4 normalRoughness = texture(sNormalRoughness, vUV); + perceptualRoughness = normalRoughness.ROUGHNESS * perceptualRoughness; + + n = normalRoughness.rgb; + n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0))); +#endif // THREE_TEX + + // The value of uOpaque and uMask can be 0.0 or 1.0. + // If uOpaque is 1.0, alpha value of final color is 1.0; + // If uOpaque is 0.0 and uMask is 1.0, alpha value of final color is 0.0 when input alpha is lower than uAlphaThreshold or + // 1.0 when input alpha is larger than uAlphaThreshold. + // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphamode + baseColor.a = mix(baseColor.a, 1.0, uOpaque); + baseColor.a = min(mix(baseColor.a, floor(baseColor.a - uAlphaThreshold + 1.0), uMask), 1.0); + + metallic = clamp(metallic, 0.0, 1.0); + // Roughness is authored as perceptual roughness; as is convention, + // convert to material roughness by squaring the perceptual roughness [2]. + perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); + lowp float alphaRoughness = perceptualRoughness * perceptualRoughness; + + lowp vec3 f0 = vec3(0.04); + lowp vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0); + diffuseColor *= (1.0 - metallic); + lowp vec3 specularColor = mix(f0, baseColor.rgb, metallic); + + // Compute reflectance. + lowp float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); + + // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect. + // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%. + lowp float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0); + lowp vec3 specularEnvironmentR0 = specularColor.rgb; + lowp vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90; + + mediump vec3 v = normalize(vPositionToCamera); // Vector from surface point to camera + mediump float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0); + mediump vec3 reflection = -normalize(reflect(v, n)); + + lowp vec3 color = vec3(0.0); + lowp vec3 diffuseLight = linear(texture(sDiffuseEnvSampler, n).rgb); + lowp vec3 specularLight = linear(texture(sSpecularEnvSampler, reflection).rgb); + // retrieve a scale and bias to F0. See [1], Figure 3 + lowp vec3 brdf = linear(texture(sbrdfLUT, vec2(NdotV, 1.0 - perceptualRoughness)).rgb); + + lowp vec3 diffuse = diffuseLight * diffuseColor; + lowp vec3 specular = specularLight * (specularColor * brdf.x + brdf.y); + color += (diffuse + specular) * uIblIntensity; #ifdef OCCLUSION - float ao = texture(sOcclusion, vUV.st).r; - finalColor = mix( finalColor, finalColor * ao, uOcclusionStrength ); -#endif + lowp float ao = texture(sOcclusion, vUV).r; + color = mix(color, color * ao, uOcclusionStrength); +#endif // OCCLUSION #ifdef EMISSIVE - vec3 emissive = texture( sEmissive, vUV.st ).rgb * uEmissiveFactor; - finalColor += emissive; -#endif + lowp vec3 emissive = linear(texture(sEmissive, vUV).rgb) * uEmissiveFactor; + color += emissive; +#endif // EMISSIVE -#ifdef THREE_TEX - FragColor = vec4( finalColor, alpha ); -#else //THREE_TEX - FragColor = vec4( finalColor, 1.0 ); -#endif //THREE_TEX + FragColor = vec4(pow(color, vec3(1.0 / 2.2)), baseColor.a); } diff --git a/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.vert b/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.vert index e9381c5..a4451e5 100644 --- a/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.vert +++ b/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.vert @@ -1,3 +1,7 @@ +// Original Code +// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/glTF-WebGL-PBR/shaders/pbr-vert.glsl +// Commit dc84b5e374fb3d23153d2248a338ef88173f9eb6 + #version 300 es #ifdef HIGHP @@ -9,23 +13,29 @@ in vec3 aPosition; in vec2 aTexCoord; in vec3 aNormal; + +#ifdef VEC4_TANGENT +in vec4 aTangent; +#else in vec3 aTangent; +#endif + +in vec4 aVertexColor; #ifdef MORPH uniform sampler2D sBlendShapeGeometry; #endif out vec2 vUV; -out vec3 vNormal; -out vec3 vTangent; -out vec3 vViewVec; +out lowp mat3 vTBN; +out lowp vec4 vColor; +out highp vec3 vPositionToCamera; -uniform highp mat4 uMvpMatrix; uniform highp mat4 uViewMatrix; uniform mat3 uNormalMatrix; uniform mat4 uModelMatrix; -uniform mat4 uModelView; uniform mat4 uProjection; +uniform lowp float uHasVertexColor; #ifdef SKINNING in vec4 aJoints; @@ -50,7 +60,7 @@ void main() { vec4 position = vec4(aPosition, 1.0); vec3 normal = aNormal; - vec3 tangent = aTangent; + vec3 tangent = aTangent.xyz; #ifdef MORPH int width = textureSize( sBlendShapeGeometry, 0 ).x; @@ -129,15 +139,16 @@ void main() tangent = (bone * vec4(tangent, 0.0)).xyz; #endif - vec4 vPosition = uModelMatrix * position; + vec4 positionW = uModelMatrix * position; + vec4 positionV = uViewMatrix * positionW; - vNormal = normalize(uNormalMatrix * normal); + vPositionToCamera = transpose(mat3(uViewMatrix)) * -vec3(positionV.xyz / positionV.w); - vTangent = normalize(uNormalMatrix * tangent); - - - vec4 viewPosition = uViewMatrix * vPosition; - gl_Position = uProjection * viewPosition; + lowp vec3 bitangent = cross(normal, tangent); +#ifdef VEC4_TANGENT + bitangent *= aTangent.w; +#endif + vTBN = mat3(uModelMatrix) * mat3(tangent, bitangent, normal); #ifdef FLIP_V vUV = vec2(aTexCoord.x, 1.0 - aTexCoord.y); @@ -145,5 +156,7 @@ void main() vUV = aTexCoord; #endif - vViewVec = viewPosition.xyz; + vColor = mix(vec4(1.0f), aVertexColor, uHasVertexColor); + + gl_Position = uProjection * positionV; } diff --git a/dali-scene-loader/public-api/environment-definition.cpp b/dali-scene-loader/public-api/environment-definition.cpp index c95883f..cc4e7e8 100644 --- a/dali-scene-loader/public-api/environment-definition.cpp +++ b/dali-scene-loader/public-api/environment-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. @@ -15,14 +15,32 @@ * */ +// EXTERNAL INCLUDES +#include +#include + // INTERNAL INCLUDES #include "dali-scene-loader/public-api/environment-definition.h" #include "dali-scene-loader/public-api/utils.h" +namespace +{ +#define TOKEN_STRING(x) #x +std::string GetDaliImagePath() +{ + return (nullptr == DALI_IMAGE_DIR) ? Dali::EnvironmentVariable::GetEnvironmentVariable(TOKEN_STRING(DALI_IMAGE_DIR)) : DALI_IMAGE_DIR; +} +} // unnamed namespace + namespace Dali { namespace SceneLoader { +namespace +{ +const std::string PRE_COMPUTED_BRDF_TEXTURE_FILE_NAME = "brdfLUT.png"; +} + EnvironmentDefinition::RawData EnvironmentDefinition::LoadRaw(const std::string& environmentsPath) const { @@ -44,6 +62,15 @@ EnvironmentDefinition::LoadRaw(const std::string& environmentsPath) const loadFn(mDiffuseMapPath, raw.mDiffuse); loadFn(mSpecularMapPath, raw.mSpecular); + + if(mUseBrdfTexture) + { + Devel::PixelBuffer pixelBuffer = LoadImageFromFile(GetDaliImagePath() + PRE_COMPUTED_BRDF_TEXTURE_FILE_NAME); + if(pixelBuffer) + { + raw.mBrdf = Devel::PixelBuffer::Convert(pixelBuffer); + } + } return raw; } @@ -62,6 +89,12 @@ EnvironmentDefinition::Textures EnvironmentDefinition::Load(RawData&& raw) const { textures.mSpecular = raw.mSpecular.CreateTexture(); } + + if(raw.mBrdf) + { + textures.mBrdf = Texture::New(TextureType::TEXTURE_2D, raw.mBrdf.GetPixelFormat(), raw.mBrdf.GetWidth(), raw.mBrdf.GetHeight()); + textures.mBrdf.Upload(raw.mBrdf); + } return textures; } diff --git a/dali-scene-loader/public-api/environment-definition.h b/dali-scene-loader/public-api/environment-definition.h index 066f6fa..90b0f9e 100644 --- a/dali-scene-loader/public-api/environment-definition.h +++ b/dali-scene-loader/public-api/environment-definition.h @@ -39,6 +39,7 @@ struct DALI_SCENE_LOADER_API EnvironmentDefinition { Texture mDiffuse; // irradiance Texture mSpecular; // radiance + Texture mBrdf; // pre-computed brdf bool IsLoaded() const { @@ -48,8 +49,9 @@ struct DALI_SCENE_LOADER_API EnvironmentDefinition struct RawData { - CubeData mDiffuse; - CubeData mSpecular; + CubeData mDiffuse; + CubeData mSpecular; + PixelData mBrdf; }; using EnvironmentData = std::pair; @@ -81,6 +83,7 @@ public: // DATA std::string mSpecularMapPath; Quaternion mCubeOrientation = Quaternion::IDENTITY; float mIblIntensity = 1.0f; + bool mUseBrdfTexture = false; }; } // namespace SceneLoader diff --git a/dali-scene-loader/public-api/gltf2-loader.cpp b/dali-scene-loader/public-api/gltf2-loader.cpp index be7e538..8af87a1 100644 --- a/dali-scene-loader/public-api/gltf2-loader.cpp +++ b/dali-scene-loader/public-api/gltf2-loader.cpp @@ -42,12 +42,12 @@ const std::string POSITION_PROPERTY("position"); const std::string ORIENTATION_PROPERTY("orientation"); const std::string SCALE_PROPERTY("scale"); const std::string BLEND_SHAPE_WEIGHTS_UNIFORM("uBlendShapeWeight"); - const std::string MRENDERER_MODEL_IDENTIFICATION("M-Renderer"); - const std::string ROOT_NODE_NAME("RootNode"); const Vector3 SCALE_TO_ADJUST(100.0f, 100.0f, 100.0f); +constexpr float DEFAULT_INTENSITY = 0.5f; + const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{ Geometry::POINTS, Geometry::LINES, @@ -66,6 +66,7 @@ struct AttributeMapping {gt::Attribute::NORMAL, &MeshDefinition::mNormals, sizeof(Vector3)}, {gt::Attribute::TANGENT, &MeshDefinition::mTangents, sizeof(Vector3)}, {gt::Attribute::TEXCOORD_0, &MeshDefinition::mTexCoords, sizeof(Vector2)}, + {gt::Attribute::COLOR_0, &MeshDefinition::mColors, sizeof(Vector4)}, {gt::Attribute::JOINTS_0, &MeshDefinition::mJoints0, sizeof(Vector4)}, {gt::Attribute::WEIGHTS_0, &MeshDefinition::mWeights0, sizeof(Vector4)}, }; @@ -439,7 +440,7 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials) matDef.SetAlphaCutoff(std::min(1.f, std::max(0.f, m.mAlphaCutoff))); } - matDef.mColor = pbr.mBaseColorFactor; + matDef.mBaseColorFactor = pbr.mBaseColorFactor; matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!m.mNormalTexture + !!m.mOcclusionTexture + !!m.mEmissiveTexture); if(pbr.mBaseColorTexture) @@ -449,6 +450,10 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials) // TODO: and there had better be one matDef.mFlags |= semantic; } + else + { + matDef.mNeedAlbedoTexture = false; + } matDef.mMetallic = pbr.mMetallicFactor; matDef.mRoughness = pbr.mRoughnessFactor; @@ -461,7 +466,12 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials) // TODO: and there had better be one matDef.mFlags |= semantic; } + else + { + matDef.mNeedMetallicRoughnessTexture = false; + } + matDef.mNormalScale = m.mNormalTexture.mScale; if(m.mNormalTexture) { const auto semantic = MaterialDefinition::NORMAL; @@ -469,6 +479,10 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials) // TODO: and there had better be one matDef.mFlags |= semantic; } + else + { + matDef.mNeedNormalTexture = false; + } // TODO: handle doubleSided if(m.mOcclusionTexture) @@ -580,6 +594,9 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx) auto& accPositions = *attribs.find(gt::Attribute::POSITION)->second; meshDef.mPositions = ConvertMeshPrimitiveAccessor(accPositions); + // glTF2 support vector4 tangent for mesh. + // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview + meshDef.mTangentType = Property::VECTOR4; const bool needNormalsTangents = accPositions.mType == gt::AccessorType::VEC3; for(auto& am : ATTRIBUTE_MAPPINGS) @@ -591,14 +608,6 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx) auto& accessor = meshDef.*(am.mAccessor); accessor = ConvertMeshPrimitiveAccessor(*iFind->second); - // Fixing up -- a few of glTF2 sample models have VEC4 tangents; we need VEC3s. - if(iFind->first == gt::Attribute::TANGENT && (accessor.mBlob.mElementSizeHint > am.mElementSizeRequired)) - { - accessor.mBlob.mStride = std::max(static_cast(accessor.mBlob.mStride + accessor.mBlob.mElementSizeHint - am.mElementSizeRequired), - accessor.mBlob.mElementSizeHint); - accessor.mBlob.mElementSizeHint = am.mElementSizeRequired; - } - if(iFind->first == gt::Attribute::JOINTS_0) { meshDef.mFlags |= (iFind->second->mComponentType == gt::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS; @@ -1156,6 +1165,14 @@ void SetObjectReaders() js::SetObjectReader(SCENE_READER); } +void SetDefaultEnvironmentMap(const gt::Document& doc, ConversionContext& cctx) +{ + EnvironmentDefinition envDef; + envDef.mUseBrdfTexture = true; + envDef.mIblIntensity = DEFAULT_INTENSITY; + cctx.mOutput.mResources.mEnvironmentMaps.push_back({std::move(envDef), EnvironmentDefinition::Textures()}); +} + } // namespace void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactory, LoadResult& params) @@ -1211,11 +1228,12 @@ void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactor ConvertMeshes(doc, cctx); ConvertNodes(doc, cctx, isMRendererModel); ConvertAnimations(doc, cctx); - ProcessSkins(doc, cctx); - ProduceShaders(shaderFactory, params.mScene); params.mScene.EnsureUniqueSkinningShaderInstances(params.mResources); + + // Set Default Environment map + SetDefaultEnvironmentMap(doc, cctx); } } // namespace SceneLoader diff --git a/dali-scene-loader/public-api/material-definition.cpp b/dali-scene-loader/public-api/material-definition.cpp index 1342ced..1766c3f 100644 --- a/dali-scene-loader/public-api/material-definition.cpp +++ b/dali-scene-loader/public-api/material-definition.cpp @@ -150,7 +150,7 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); ++iTexture; } - else // single value albedo, albedo-alpha or albedo-metallic + else if(mNeedAlbedoTexture) // single value albedo, albedo-alpha or albedo-metallic { uint32_t bufferSize = 4; uint8_t* buffer = nullptr; @@ -184,7 +184,7 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); ++iTexture; } - else if(createMetallicRoughnessAndNormal) + else if(createMetallicRoughnessAndNormal && mNeedMetallicRoughnessTexture) { // NOTE: we want to set both metallic and roughness to 1.0; dli uses the R & A channels, // glTF2 uses B & G, so we might as well just set all components to 1.0. @@ -198,17 +198,20 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags}); ++iTexture; } - else if(createMetallicRoughnessAndNormal) + else if(mNeedNormalTexture) { - const auto bufferSize = 3; - uint8_t* buffer = new uint8_t[bufferSize]{0x7f, 0x7f, 0xff}; // normal of (0, 0, 1) - raw.mTextures.push_back({PixelData::New(buffer, bufferSize, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER}); - } - else // single-value normal-roughness - { - const auto bufferSize = 4; - uint8_t* buffer = new uint8_t[bufferSize]{0x7f, 0x7f, 0xff, 0xff}; // normal of (0, 0, 1), roughness of 1.0 - raw.mTextures.push_back({PixelData::New(buffer, bufferSize, 1, 1, Pixel::RGBA8888, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER}); + if(createMetallicRoughnessAndNormal) + { + const auto bufferSize = 3; + uint8_t* buffer = new uint8_t[bufferSize]{0x7f, 0x7f, 0xff}; // normal of (0, 0, 1) + raw.mTextures.push_back({PixelData::New(buffer, bufferSize, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER}); + } + else // single-value normal-roughness + { + const auto bufferSize = 4; + uint8_t* buffer = new uint8_t[bufferSize]{0x7f, 0x7f, 0xff, 0xff}; // normal of (0, 0, 1), roughness of 1.0 + raw.mTextures.push_back({PixelData::New(buffer, bufferSize, 1, 1, Pixel::RGBA8888, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER}); + } } } @@ -273,6 +276,13 @@ TextureSet MaterialDefinition::Load(const EnvironmentDefinition::Vector& environ textureSet.SetTexture(n, envTextures.mSpecular); textureSet.SetSampler(n, specularSampler); + ++n; + } + + // If pre-computed brdf texture is defined, set the texture. + if(envTextures.mBrdf) + { + textureSet.SetTexture(n, envTextures.mBrdf); } } else diff --git a/dali-scene-loader/public-api/material-definition.h b/dali-scene-loader/public-api/material-definition.h index e36f74b..2c9ed6c 100644 --- a/dali-scene-loader/public-api/material-definition.h +++ b/dali-scene-loader/public-api/material-definition.h @@ -219,12 +219,20 @@ struct DALI_SCENE_LOADER_API MaterialDefinition public: // DATA uint32_t mFlags = 0x0; - Index mEnvironmentIdx = 0; - Vector4 mColor = Color::WHITE; - Vector3 mEmissiveFactor = Vector3::ZERO; - float mMetallic = 1.f; - float mRoughness = 1.f; - float mOcclusionStrength = 1.f; + Index mEnvironmentIdx = 0; + Vector4 mColor = Color::WHITE; + float mMetallic = 1.f; + float mRoughness = 1.f; + Vector4 mBaseColorFactor = Vector4::ONE; + float mNormalScale = 1.f; + float mOcclusionStrength = 1.f; + Vector3 mEmissiveFactor = Vector3::ZERO; + + // For the glTF, each of albedo, metallicRoughness, normal textures are not essential. + bool mNeedAlbedoTexture = true; + bool mNeedMetallicRoughnessTexture = true; + bool mNeedNormalTexture = true; + std::vector mTextureStages; }; diff --git a/dali-scene-loader/public-api/mesh-definition.cpp b/dali-scene-loader/public-api/mesh-definition.cpp index de37e30..373b445 100644 --- a/dali-scene-loader/public-api/mesh-definition.cpp +++ b/dali-scene-loader/public-api/mesh-definition.cpp @@ -681,8 +681,9 @@ MeshDefinition::LoadRaw(const std::string& modelsPath) const if(mTangents.IsDefined()) { - DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % sizeof(Vector3) == 0) || - mTangents.mBlob.mStride >= sizeof(Vector3)) && + uint32_t propertySize = (mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3); + DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) || + mTangents.mBlob.mStride >= propertySize) && "Tangents buffer length not a multiple of element size"); const auto bufferSize = mTangents.mBlob.GetBufferSize(); std::vector buffer(bufferSize); @@ -690,10 +691,9 @@ MeshDefinition::LoadRaw(const std::string& modelsPath) const { ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << meshPath << "'."; } + mTangents.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast(buffer.data())); - mTangents.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast(buffer.data())); - - raw.mAttribs.push_back({"aTangent", Property::VECTOR3, static_cast(bufferSize / sizeof(Vector3)), std::move(buffer)}); + raw.mAttribs.push_back({"aTangent", mTangentType, static_cast(bufferSize / propertySize), std::move(buffer)}); } else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles) { @@ -701,6 +701,27 @@ MeshDefinition::LoadRaw(const std::string& modelsPath) const hasUvs ? GenerateTangentsWithUvs(raw) : GenerateTangents(raw); } + if(mColors.IsDefined()) + { + uint32_t propertySize = mColors.mBlob.mElementSizeHint; + Property::Type propertyType = (propertySize == sizeof(Vector4)) ? Property::VECTOR4 : ((propertySize == sizeof(Vector3)) ? Property::VECTOR3 : Property::NONE); + if(propertyType != Property::NONE) + { + DALI_ASSERT_ALWAYS(((mColors.mBlob.mLength % propertySize == 0) || + mColors.mBlob.mStride >= propertySize) && + "Colors buffer length not a multiple of element size"); + const auto bufferSize = mColors.mBlob.GetBufferSize(); + std::vector buffer(bufferSize); + if(!ReadAccessor(mColors, binFile, buffer.data())) + { + ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << meshPath << "'."; + } + mColors.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast(buffer.data())); + + raw.mAttribs.push_back({"aVertexColor", propertyType, static_cast(bufferSize / propertySize), std::move(buffer)}); + } + } + if(IsSkinned()) { if(MaskMatch(mFlags, U16_JOINT_IDS)) diff --git a/dali-scene-loader/public-api/mesh-definition.h b/dali-scene-loader/public-api/mesh-definition.h index d03fa0b..2fe4394 100644 --- a/dali-scene-loader/public-api/mesh-definition.h +++ b/dali-scene-loader/public-api/mesh-definition.h @@ -243,9 +243,11 @@ public: // DATA Accessor mPositions; Accessor mNormals; // data can be generated based on positions Accessor mTexCoords; + Accessor mColors; Accessor mTangents; // data can be generated based on normals and texCoords (the latter isn't mandatory; the results will be better if available) Accessor mJoints0; Accessor mWeights0; + Property::Type mTangentType{Property::VECTOR3}; Blob mBlendShapeHeader; std::vector mBlendShapes; diff --git a/dali-scene-loader/public-api/node-definition.cpp b/dali-scene-loader/public-api/node-definition.cpp index e8f6b82..7542782 100644 --- a/dali-scene-loader/public-api/node-definition.cpp +++ b/dali-scene-loader/public-api/node-definition.cpp @@ -150,9 +150,13 @@ void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParam actor.SetProperty(Actor::Property::COLOR, mColor); + actor.RegisterProperty("uHasVertexColor", static_cast(mesh.first.mColors.IsDefined())); + auto& matDef = resources.mMaterials[mMaterialIdx].first; + actor.RegisterProperty("uColorFactor", matDef.mBaseColorFactor); actor.RegisterProperty("uMetallicFactor", matDef.mMetallic); actor.RegisterProperty("uRoughnessFactor", matDef.mRoughness); + actor.RegisterProperty("uNormalScale", matDef.mNormalScale); if(matDef.mFlags & MaterialDefinition::OCCLUSION) { actor.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength); @@ -165,11 +169,23 @@ void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParam Index envIdx = matDef.mEnvironmentIdx; actor.RegisterProperty("uIblIntensity", resources.mEnvironmentMaps[envIdx].first.mIblIntensity); - const auto alphaCutoff = matDef.GetAlphaCutoff(); - if(alphaCutoff > 0.f) + float opaque = 0.0f; + float mask = 0.0f; + float alphaCutoff = matDef.GetAlphaCutoff(); + if(!MaskMatch(matDef.mFlags, MaterialDefinition::TRANSPARENCY)) + { + opaque = 1.0f; + } + else { - actor.RegisterProperty("uAlphaThreshold", alphaCutoff); + if(alphaCutoff > 0.f) + { + mask = 1.0f; + } } + actor.RegisterProperty("uOpaque", opaque); + actor.RegisterProperty("uMask", mask); + actor.RegisterProperty("uAlphaThreshold", alphaCutoff); } void ArcNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const diff --git a/dali-scene-loader/public-api/shader-definition-factory.cpp b/dali-scene-loader/public-api/shader-definition-factory.cpp index 6f9ab4e..e025ebe 100644 --- a/dali-scene-loader/public-api/shader-definition-factory.cpp +++ b/dali-scene-loader/public-api/shader-definition-factory.cpp @@ -204,11 +204,27 @@ Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef) } if(hasTransparency || - materialDef.CheckTextures(MaterialDefinition::ALBEDO) || - materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) || - materialDef.CheckTextures(MaterialDefinition::NORMAL)) + !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) || + !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS)) + { shaderDef.mDefines.push_back("THREE_TEX"); + + // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential. + if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO)) + { + shaderDef.mDefines.push_back("BASECOLOR_TEX"); + } + + if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS)) + { + shaderDef.mDefines.push_back("METALLIC_ROUGHNESS_TEX"); + } + + if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL)) + { + shaderDef.mDefines.push_back("NORMAL_TEX"); + } } if(materialDef.GetAlphaCutoff() > 0.f) @@ -280,6 +296,11 @@ Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef) } } + if(meshDef.mTangentType == Property::VECTOR4) + { + shaderDef.mDefines.push_back("VEC4_TANGENT"); + } + shaderDef.mUniforms["uMaxLOD"] = 6.f; shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY; -- 2.7.4