diff --git a/.gitignore b/.gitignore index 71ce0cece37..4ae3259c10d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ cmake-build-*/ /mingw/ /.cache/ /_skbuild/ - +/buildrelease/ # Meta data of macOS's Finder.app .DS_Store diff --git a/Components/RTShaderSystem/src/OgreShaderCookTorranceLighting.cpp b/Components/RTShaderSystem/src/OgreShaderCookTorranceLighting.cpp index 3542b3eef0f..8ca427f7397 100644 --- a/Components/RTShaderSystem/src/OgreShaderCookTorranceLighting.cpp +++ b/Components/RTShaderSystem/src/OgreShaderCookTorranceLighting.cpp @@ -97,6 +97,8 @@ bool CookTorranceLighting::createCpuSubPrograms(ProgramSet* programSet) // add the lighting computation auto mrparams = psMain->resolveLocalParameter(GCT_FLOAT2, "metalRoughness"); + auto ao = psMain->resolveLocalParameter(GCT_FLOAT1, "ao"); + fstage.assign(1.0f, ao); //Default to no AO. if(!mMetalRoughnessMapName.empty()) { auto metalRoughnessSampler = @@ -106,6 +108,7 @@ bool CookTorranceLighting::createCpuSubPrograms(ProgramSet* programSet) // This layout intentionally reserves the 'r' channel for (optional) occlusion map data fstage.sampleTexture(metalRoughnessSampler, psInTexcoord, mrSample); fstage.assign(In(mrSample).mask(Operand::OPM_YZ), mrparams); + fstage.assign(In(mrSample).x(), ao); } else { @@ -124,7 +127,7 @@ bool CookTorranceLighting::createCpuSubPrograms(ProgramSet* programSet) fstage.assign(Vector3(0), Out(outDiffuse).xyz()); fstage.mul(In(diffuse).w(), In(outDiffuse).w(), Out(outDiffuse).w()); // forward alpha - fstage.callFunction("PBR_MakeParams", {In(baseColor), In(mrparams), InOut(pixelParams)}); + fstage.callFunction("PBR_MakeParams", {In(baseColor), In(mrparams), In(ao), InOut(pixelParams)}); fstage = psMain->getStage(FFP_PS_PBR_LIGHTING_END); if(mLightCount > 0) diff --git a/Components/RTShaderSystem/src/OgreShaderImageBasedLighting.cpp b/Components/RTShaderSystem/src/OgreShaderImageBasedLighting.cpp index bc6b273a4fe..34f13801d28 100644 --- a/Components/RTShaderSystem/src/OgreShaderImageBasedLighting.cpp +++ b/Components/RTShaderSystem/src/OgreShaderImageBasedLighting.cpp @@ -24,7 +24,7 @@ int ImageBasedLighting::getExecutionOrder() const { return FFP_LIGHTING + 10; } bool ImageBasedLighting::setParameter(const String& name, const String& value) { - if (name == "texture" && !value.empty()) + if ((name == "texture" || name == "texture_diffuse") && !value.empty()) { mEnvMapName = value; return true; @@ -34,7 +34,12 @@ bool ImageBasedLighting::setParameter(const String& name, const String& value) mIsLuminanceParamDirty = true; return StringConverter::parse(value, mLuminance); } - + else if (name == "texture_specular" && !value.empty()) + { + //If set, the shader will use seperate "diffuse irradiance" and "specular ggx" cubemaps for IBL. + mEnvMapNameSpecular = value; + return true; + } return false; } @@ -42,6 +47,7 @@ void ImageBasedLighting::copyFrom(const SubRenderState& rhs) { const ImageBasedLighting& rhsIBL = static_cast(rhs); mEnvMapName = rhsIBL.mEnvMapName; + mEnvMapNameSpecular = rhsIBL.mEnvMapNameSpecular; mLuminance = rhsIBL.mLuminance; } @@ -66,6 +72,15 @@ bool ImageBasedLighting::preAddToRenderState(const RenderState* renderState, Pas tus->setHardwareGammaEnabled(true); mEnvMapSamplerIndex = dstPass->getNumTextureUnitStates() - 1; + // Check for dual cubemaps (diffuse irradiance plus specular convoluted). Add second texture if applicable. + if (mEnvMapNameSpecular != "") + { + tus = dstPass->createTextureUnitState(); + tus->setTextureName(mEnvMapNameSpecular, TEX_TYPE_CUBE_MAP); + tus->setHardwareGammaEnabled(true); + mEnvMapSamplerIndexSpecular = dstPass->getNumTextureUnitStates() - 1; + } + return true; } @@ -101,15 +116,37 @@ bool ImageBasedLighting::createCpuSubPrograms(ProgramSet* programSet) auto dfgLUTSampler = psProgram->resolveParameter(GCT_SAMPLER2D, "dfgLUTSampler", mDfgLUTSamplerIndex); auto iblEnvSampler = psProgram->resolveParameter(GCT_SAMPLERCUBE, "iblEnvSampler", mEnvMapSamplerIndex); + Ogre::RTShader::UniformParameterPtr iblEnvSpecularSampler = NULL; + Ogre::RTShader::UniformParameterPtr iblEnvSize = NULL; + + // Add secondary cubemap if applicable. + if (mEnvMapNameSpecular != "") + { + psProgram->addPreprocessorDefines("HAS_DUAL_TEXTURE"); + iblEnvSpecularSampler = psProgram->resolveParameter(GCT_SAMPLERCUBE, "iblEnvSpecularSampler", mEnvMapSamplerIndexSpecular); + iblEnvSize = psProgram->resolveParameter(GpuProgramParameters::ACT_TEXTURE_SIZE, mEnvMapSamplerIndexSpecular); + } + else + { + iblEnvSize = psProgram->resolveParameter(GpuProgramParameters::ACT_TEXTURE_SIZE, mEnvMapSamplerIndex); + } - auto iblEnvSize = psProgram->resolveParameter(GpuProgramParameters::ACT_TEXTURE_SIZE, mEnvMapSamplerIndex); auto invViewMat = psProgram->resolveParameter(GpuProgramParameters::ACT_INVERSE_VIEW_MATRIX); auto fstage = psMain->getStage(FFP_PS_PBR_LIGHTING_BEGIN + 5); - fstage.callFunction("evaluateIBL", - {InOut(pixel), In(viewNormal), In(viewPos), In(invViewMat), In(dfgLUTSampler), In(iblEnvSampler), - In(iblEnvSize).w(), In(mLuminanceParam), InOut(outDiffuse).xyz()}); + //Add second texture if set. + if (mEnvMapNameSpecular == "") + { + fstage.callFunction("evaluateIBL", + {InOut(pixel), In(viewNormal), In(viewPos), In(invViewMat), In(dfgLUTSampler), + In(iblEnvSampler), In(iblEnvSize).w(), In(mLuminanceParam), InOut(outDiffuse).xyz()}); + } + else + { + fstage.callFunction("evaluateIBL", {InOut(pixel), In(viewNormal), In(viewPos), In(invViewMat), In(dfgLUTSampler), + In(iblEnvSampler), In(iblEnvSpecularSampler), In(iblEnvSize).w(), In(mLuminanceParam), InOut(outDiffuse).xyz()}); + } return true; } @@ -134,13 +171,13 @@ SubRenderState* ImageBasedLightingFactory::createInstance(const ScriptProperty& if (prop.name != "image_based_lighting" || prop.values.size() < 2) return NULL; - if(prop.values[0] != "texture") + if (prop.values[0] != "texture" && prop.values[0] != "texture_diffuse") { translator->emitError(); return NULL; } auto ret = static_cast(createOrRetrieveInstance(translator)); - ret->setParameter("texture", prop.values[1]); + ret->setParameter(prop.values[0], prop.values[1]); if (prop.values.size() < 4) return ret; @@ -153,6 +190,18 @@ SubRenderState* ImageBasedLightingFactory::createInstance(const ScriptProperty& ret->setParameter("luminance", prop.values[3]); + if (prop.values.size() < 6) + return ret; + + //If this is set "texture" is then used as a diffuse texture only + if (prop.values[4] != "texture_specular") + { + translator->emitError(); + return NULL; + } + + ret->setParameter("texture_specular", prop.values[5]); + return ret; } diff --git a/Components/RTShaderSystem/src/OgreShaderImageBasedLighting.h b/Components/RTShaderSystem/src/OgreShaderImageBasedLighting.h index c9b38775d64..ed325953c50 100644 --- a/Components/RTShaderSystem/src/OgreShaderImageBasedLighting.h +++ b/Components/RTShaderSystem/src/OgreShaderImageBasedLighting.h @@ -30,10 +30,13 @@ class ImageBasedLighting : public SubRenderState friend class ImageBasedLightingFactory; int mDfgLUTSamplerIndex = 0; int mEnvMapSamplerIndex = 0; + int mEnvMapSamplerIndexSpecular = 0; float mLuminance = 1.0f; String mEnvMapName; + String mEnvMapNameSpecular; UniformParameterPtr mLuminanceParam; bool mIsLuminanceParamDirty = true; + public: const String& getType() const override; int getExecutionOrder() const override; diff --git a/Media/RTShaderLib/RTSLib_IBL.glsl b/Media/RTShaderLib/RTSLib_IBL.glsl index 927f53e10ae..84c0f4ae260 100644 --- a/Media/RTShaderLib/RTSLib_IBL.glsl +++ b/Media/RTShaderLib/RTSLib_IBL.glsl @@ -33,6 +33,10 @@ vec3 prefilteredRadiance(samplerCube light_iblSpecular, const vec3 r, float perc return decodeDataForIBL(textureCubeLod(light_iblSpecular, r, lod)); } +vec3 IrradianceMap(samplerCube iblDiffuse, const vec3 n) { + return decodeDataForIBL(textureCubeLod(iblDiffuse, n, 0.0)); +} + vec3 getSpecularDominantDirection(const vec3 n, const vec3 r, float roughness) { return mix(r, n, roughness * roughness); } @@ -43,6 +47,9 @@ void evaluateIBL(inout PixelParams pixel, in mat4 invViewMat, in sampler2D dfgTex, in samplerCube iblEnvTex, + #ifdef HAS_DUAL_TEXTURE + in samplerCube iblEnvTexSpecular, + #endif in float iblRoughnessOneLevel, in float iblLuminance, inout vec3 color) @@ -67,9 +74,16 @@ void evaluateIBL(inout PixelParams pixel, shading_normal = normalize(mul(invViewMat, vec4(shading_normal, 0.0)).xyz); // specular layer + #ifdef HAS_DUAL_TEXTURE + //Use dedicated specular texture, iblEnvTex should be diffuse irradiance. + vec3 Fr = E * prefilteredRadiance(iblEnvTexSpecular, r, pixel.perceptualRoughness, iblRoughnessOneLevel); + vec3 diffuseIrradiance = IrradianceMap(iblEnvTex, shading_normal); + #else + //Old behaviour vec3 Fr = E * prefilteredRadiance(iblEnvTex, r, pixel.perceptualRoughness, iblRoughnessOneLevel); - vec3 diffuseIrradiance = Irradiance_RoughnessOne(iblEnvTex, shading_normal, iblRoughnessOneLevel); + #endif + vec3 Fd = pixel.diffuseColor * diffuseIrradiance * (1.0 - E); Fr *= iblLuminance; diff --git a/Media/RTShaderLib/SGXLib_CookTorrance.glsl b/Media/RTShaderLib/SGXLib_CookTorrance.glsl index bdede2a5606..18356fe76c5 100644 --- a/Media/RTShaderLib/SGXLib_CookTorrance.glsl +++ b/Media/RTShaderLib/SGXLib_CookTorrance.glsl @@ -29,6 +29,7 @@ struct PixelParams vec3 f0; vec3 dfg; vec3 energyCompensation; + float ao; }; float clampNoV(float NoV) { @@ -65,6 +66,14 @@ float perceptualRoughnessToRoughness(float perceptualRoughness) { return perceptualRoughness * perceptualRoughness; } +// https://github.com/google/filament/blob/7701e7a65afb14c081d2aebbb426c646cc6cb2b9/shaders/src/surface_lighting.fs +float computeMicroShadowing(float NoL, float visibility) { + // Chan 2018, "Material Advances in Call of Duty: WWII" + float aperture = inversesqrt(1.0 - min(visibility, 0.9999)); + float microShadow = saturate(NoL * aperture); + return microShadow * microShadow; +} + // https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg) float V_SmithGGXCorrelated(float roughness, float NoV, float NoL) { // Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs" @@ -133,7 +142,6 @@ vec3 evaluateLight( f32vec3 vNormalView = normalize(vNormal); float NoL = saturate(dot(vNormalView, vLightView)); - if(NoL <= 0.0) return vec3_splat(0.0); // not lit by this light @@ -154,8 +162,12 @@ vec3 evaluateLight( vec3 Fr = (D * V) * F; vec3 Fd = pixel.diffuseColor * Fd_Lambert(); + //Compute AO + float visibility = 1.0; + visibility *= computeMicroShadowing(NoL, pixel.ao); + // https://google.github.io/filament/Filament.md.html#materialsystem/improvingthebrdfs/energylossinspecularreflectance - vec3 color = NoL * lightColor * (Fr * pixel.energyCompensation + Fd); + vec3 color = visibility * NoL * lightColor * (Fr * pixel.energyCompensation + Fd); color *= getDistanceAttenuation(pointParams.yzw, fLightD); @@ -167,9 +179,10 @@ vec3 evaluateLight( return color; } -void PBR_MakeParams(in vec3 baseColor, in vec2 mrParam, inout PixelParams pixel) +void PBR_MakeParams(in vec3 baseColor, in vec2 mrParam, in float ao, inout PixelParams pixel) { pixel.baseColor = baseColor; + pixel.ao = ao; float perceptualRoughness = mrParam.x; // Clamp the roughness to a minimum value to avoid divisions by 0 during lighting @@ -233,6 +246,6 @@ void PBR_Lights( vOutColour += lightVal; } - vOutColour += pixel.baseColor * pow(ambient.rgb, vec3_splat(2.2)); + vOutColour += pixel.baseColor * pow(ambient.rgb, vec3_splat(2.2)) * pixel.ao; } #endif \ No newline at end of file diff --git a/RenderSystems/Direct3D11/src/OgreD3D11Mappings.cpp b/RenderSystems/Direct3D11/src/OgreD3D11Mappings.cpp index cba7e2bfb3d..f7350c208ec 100644 --- a/RenderSystems/Direct3D11/src/OgreD3D11Mappings.cpp +++ b/RenderSystems/Direct3D11/src/OgreD3D11Mappings.cpp @@ -745,8 +745,8 @@ namespace Ogre UINT flags = 0; - if((bindflags & D3D11_BIND_SHADER_RESOURCE) && (bindflags & D3D11_BIND_RENDER_TARGET)) - flags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; + if((bindflags & D3D11_BIND_SHADER_RESOURCE) && (bindflags & D3D11_BIND_RENDER_TARGET) && (usage & TU_AUTOMIPMAP)) + flags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; if(textype == TEX_TYPE_CUBE_MAP) flags |= D3D11_RESOURCE_MISC_TEXTURECUBE;