diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/MaterialFunctions/EvaluateSixPointSurface.azsli b/atom_gems/AtomTutorials/Assets/SixPointLighting/MaterialFunctions/EvaluateSixPointSurface.azsli new file mode 100644 index 0000000..be7a46f --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/MaterialFunctions/EvaluateSixPointSurface.azsli @@ -0,0 +1,65 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include <../SixPointSurface.azsli> +#include + +void EvaluateSixPointSurface( + float3 vertexNormal, + float2 uv[UvSetCount], + float3 tangents[UvSetCount], + float3 bitangents[UvSetCount], + bool isFrontFace, + bool displacementIsClipped, + inout Surface surface) +{ + // ------- Base Color ------- + float2 baseColorUv = uv[MaterialSrg::m_baseColorMapUvIndex]; + float2 sixPointUv = GetUvForCurrentFrame(baseColorUv); + float3 sampledColor = GetBaseColorInput(MaterialSrg::m_baseColorMap, MaterialSrg::m_sampler, sixPointUv, MaterialSrg::m_baseColor.rgb, o_baseColor_useTexture); + float3 baseColor = BlendBaseColor(sampledColor, MaterialSrg::m_baseColor.rgb, MaterialSrg::m_baseColorFactor, o_baseColorTextureBlendMode, o_baseColor_useTexture); + + // ------- Metallic ------- + float metallic = MaterialSrg::m_metallicFactor; + + // ------- Specular ------- + float specularF0Factor = MaterialSrg::m_specularF0Factor; + surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic); + + if(o_sixPointTexturePackMode == SixPointTexturePackMode::TpLftRtBt_FrBck) + { + float4 topLeftRightBottom = MaterialSrg::m_topLeftRightBottomMap.Sample(MaterialSrg::m_sampler, sixPointUv); + float4 frontBack = MaterialSrg::m_frontBackMap.Sample(MaterialSrg::m_sampler, sixPointUv); + surface.top = topLeftRightBottom.r; + surface.left = topLeftRightBottom.g; + surface.right = topLeftRightBottom.b; + surface.bottom = topLeftRightBottom.a; + surface.frontside = frontBack.r; + surface.backside = frontBack.g; + } + else + { + float4 rightLeftTop = MaterialSrg::m_rightLeftTopMap.Sample(MaterialSrg::m_sampler, sixPointUv); + float4 bottomBackFront = MaterialSrg::m_bottomBackFrontMap.Sample(MaterialSrg::m_sampler, sixPointUv); + surface.right = rightLeftTop.r; + surface.left = rightLeftTop.g; + surface.top = rightLeftTop.b; + surface.bottom = bottomBackFront.r; + surface.backside = bottomBackFront.g; + surface.frontside = bottomBackFront.b; + } + surface.tangent = tangents[0]; + surface.bitangent = bitangents[0]; + + // ------- Roughness ------- + surface.roughnessLinear = MaterialSrg::m_roughnessFactor;; + surface.CalculateRoughnessA(); + + // ------- Clearcoat ------- + surface.clearCoat.InitializeToZero(); +} diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/MaterialInputs/SixPointLightingPropertyGroup.json b/atom_gems/AtomTutorials/Assets/SixPointLighting/MaterialInputs/SixPointLightingPropertyGroup.json new file mode 100644 index 0000000..7a92590 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/MaterialInputs/SixPointLightingPropertyGroup.json @@ -0,0 +1,148 @@ +{ + "name": "sixPointLighting", + "displayName": "Six Point Lighting", + "description": "Six point lighting settings.", + "properties": [ + { + "name": "texturePackMode", + "displayName": "Texture Pack Mode", + "description": "Determines how the textures are sampled.", + "type": "Enum", + "enumValues": [ "TpLftRtBt_FrBck", "RtLftTp_BtBckFr" ], + "defaultValue": "TpLftRtBt_FrBck", + "connection": { + "type": "ShaderOption", + "name": "o_sixPointTexturePackMode" + } + }, + { + "name": "TLRB", + "displayName": "Top Left Right Bottom", + "description": "Top Left Right Bottom Lightmap", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_topLeftRightBottomMap" + } + }, + { + "name": "FB", + "displayName": "Front Back", + "description": "Front Back Lightmap", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_frontBackMap" + } + }, + { + "name": "RLT", + "displayName": "Right Left Top", + "description": "Right Left Top Lightmap", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_rightLeftTopMap" + } + }, + { + "name": "BBF", + "displayName": "Bottom Back Front", + "description": "Bottom Back Front Lightmap", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_bottomBackFrontMap" + } + }, + { + "name": "useDepthTexture", + "displayName": "Use Depth", + "description": "Whether to use the depth map.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "depthMap", + "displayName": "Depth", + "description": "Depth texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_depthMap" + } + }, + { + "name": "depthScale", + "displayName": "Scale the Depth Texture", + "description": "Multiplier for the depth texture", + "type": "Float", + "defaultValue": 10.0, + "min": 0.01, + "connection": { + "type": "ShaderInput", + "name": "m_depthScale" + } + }, + { + "name": "rowCount", + "displayName": "Rows in Flipbook", + "description": "Total rows of animation in the flipbook", + "type": "Float", + "defaultValue": 8.0, + "min": 1.0, + "step": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_rowCount" + } + }, + { + "name": "columnCount", + "displayName": "Columns in Flipbook", + "description": "Total columns of animation in the flipbook", + "type": "Float", + "defaultValue": 8.0, + "min": 1.0, + "step": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_columnCount" + } + }, + { + "name": "enableDebugFrame", + "displayName": "Enable debugging a specific frame", + "description": "Locks the frame of the animation", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_enableDebugFrame" + } + }, + { + "name": "debugFrame", + "displayName": "Debug Frame", + "description": "The frame you want to debug", + "type": "Float", + "defaultValue": 1.0, + "min": 1.0, + "step": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_debugFrame" + } + } + ], + "functors": [ + { + "type": "UseTexture", + "args": { + "textureProperty": "depthMap", + "useTextureProperty": "useDepthTexture", + "shaderOption": "o_enableDepthTexture" + } + } + ] +} diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/LICENSE.txt b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/LICENSE.txt new file mode 100644 index 0000000..06264a2 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Thomas Iché + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/README.md b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/README.md new file mode 100644 index 0000000..8901196 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/README.md @@ -0,0 +1,6 @@ +[This repository (Unity-URP-SmokeLighting)](https://github.com/peeweek/Unity-URP-SmokeLighting/tree/main/Assets/VFX/SmokeLighting/Textures/2D) provides the following assets that we include in this directory: +* SmokeBall01_6Way_BBF_8x8.png +* SmokeBall01_6Way_RLT_8x8.png +* SmokeBall01_ColorCC_8x8.png + +These assets are distributed under the MIT license, as included in this directory. diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_6Way_BBF_8x8.png b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_6Way_BBF_8x8.png new file mode 100644 index 0000000..98f657c Binary files /dev/null and b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_6Way_BBF_8x8.png differ diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_6Way_RLT_8x8.png b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_6Way_RLT_8x8.png new file mode 100644 index 0000000..339decd Binary files /dev/null and b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_6Way_RLT_8x8.png differ diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_ColorCC_8x8.png b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_ColorCC_8x8.png new file mode 100644 index 0000000..e7af691 Binary files /dev/null and b/atom_gems/AtomTutorials/Assets/SixPointLighting/Objects/SmokeBall01_ColorCC_8x8.png differ diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting.azsli b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting.azsli new file mode 100644 index 0000000..fbb8d06 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting.azsli @@ -0,0 +1,145 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +// Include options first +#include + +// Then include custom surface and lighting data types +#include +#include + +#include +#include +#include + +float ComputeLightMap(const float3 dirToLightWS, const Surface surface) +{ + float3 dirToLightTS = WorldSpaceToTangent(dirToLightWS, surface.normal, surface.tangent, surface.bitangent); + float hMap = (dirToLightTS.x > 0.0f) ? (surface.right) : (surface.left); // Picks the correct horizontal side. + float vMap = (dirToLightTS.y > 0.0f) ? (surface.bottom) : (surface.top); // Picks the correct vertical side. + float dMap = (dirToLightTS.z > 0.0f) ? (surface.frontside) : (surface.backside); // Picks the correct front/back side + float lightMap = hMap*dirToLightTS.x*dirToLightTS.x + vMap*dirToLightTS.y*dirToLightTS.y + dMap*dirToLightTS.z*dirToLightTS.z; // Pythagoras! + return lightMap; +} + +// Then define the Diffuse and Specular lighting functions +float3 GetDiffuseLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight) +{ + float lightMap = ComputeLightMap(dirToLight, surface); + float3 diffuse = lightMap.rrr; + + diffuse *= lightIntensity; + return diffuse; +} + +float3 GetSpecularLighting(Surface surface, LightingData lightingData, const float3 lightIntensity, const float3 dirToLight) +{ + return float3(0.0f, 0.0f, 0.0f); +} + +// Then include everything else +#include + +#include + +#include +#include + +// Include IBL functions +float3 GetIblSample(Surface surface, float3 direction) +{ + float3 irradianceDir = TangentSpaceToWorld(direction, surface.normal, surface.tangent, surface.bitangent); + irradianceDir = MultiplyVectorQuaternion(irradianceDir, SceneSrg::m_iblOrientation); + float3 diffuseSample = SceneSrg::m_diffuseEnvMap.Sample(SceneSrg::m_samplerEnv, GetCubemapCoords(irradianceDir)).rgb; + + return diffuseSample; +} + +float3 GetIblDiffuse(Surface surface, float3 diffuseResponse) +{ + float3 rightSample = GetIblSample(surface, float3(1.0f, 0.0f, 0.0f)); + float3 leftSample = GetIblSample(surface, float3(-1.0f, 0.0f, 0.0f)); + float3 topSample = GetIblSample(surface, float3(0.0f, -1.0f, 0.0f)); + float3 bottomSample = GetIblSample(surface, float3(0.0f, 1.0f, 0.0f)); + float3 frontsideSample = GetIblSample(surface, float3(0.0f, 0.0f, 1.0f)); + float3 backsideSample = GetIblSample(surface, float3(0.0f, 0.0f, -1.0f)); + + float3 totalDiffuseSample = (leftSample * surface.left) + + (rightSample * surface.right) + + (topSample * surface.top) + + (bottomSample * surface.bottom) + + (frontsideSample * surface.frontside) + + (backsideSample * surface.backside); + + return diffuseResponse * surface.albedo * totalDiffuseSample; +} + +void ApplyIBL(Surface surface, inout LightingData lightingData) +{ + bool useIbl = o_enableIBL && IsIndirectLightingEnabled(); + +#ifdef FORCE_IBL_IN_FORWARD_PASS + bool useDiffuseIbl = true; +#else + bool isTransparent = (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent); + bool useDiffuseIbl = isTransparent; + useIbl = useIbl && useDiffuseIbl; +#endif + + if(useIbl) + { + float globalIblExposure = pow(2.0, SceneSrg::m_iblExposure); + + if(useDiffuseIbl) + { + float3 iblDiffuse = GetIblDiffuse(surface, lightingData.diffuseResponse); + lightingData.diffuseLighting += (iblDiffuse * globalIblExposure * lightingData.diffuseAmbientOcclusion); + } + } +} + +struct PbrLightingOutput +{ + float4 m_diffuseColor; + float4 m_specularColor; + float4 m_albedo; + float4 m_specularF0; + float4 m_normal; +}; + + +PbrLightingOutput GetPbrLightingOutput(Surface surface, LightingData lightingData, float alpha) +{ + PbrLightingOutput lightingOutput; + + lightingOutput.m_diffuseColor = float4(lightingData.diffuseLighting, alpha); + lightingOutput.m_specularColor = float4(lightingData.specularLighting, 1.0); + + // albedo, specularF0, roughness, and normals for later passes (specular IBL, Diffuse GI, SSR, AO, etc) + lightingOutput.m_specularF0 = float4(0.0f, 0.0f, 0.0f, surface.roughnessLinear); + lightingOutput.m_albedo.rgb = float3(1.0f, 1.0f, 1.0f) * lightingData.diffuseResponse * lightingData.diffuseAmbientOcclusion; + lightingOutput.m_albedo.a = lightingData.specularOcclusion; + lightingOutput.m_normal.rgb = EncodeNormalSignedOctahedron(surface.normal); + lightingOutput.m_normal.a = 0.0f; + + return lightingOutput; +} + +PbrLightingOutput DebugOutput(float3 color) +{ + PbrLightingOutput output = (PbrLightingOutput)0; + + float3 defaultNormal = float3(0.0f, 0.0f, 1.0f); + + output.m_diffuseColor = float4(color.rgb, 1.0f); + output.m_normal.rgb = EncodeNormalSignedOctahedron(defaultNormal); + + return output; +} diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting.materialtype b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting.materialtype new file mode 100644 index 0000000..7613d47 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting.materialtype @@ -0,0 +1,96 @@ +{ + "description": "Material Type with six point lighting of a flipbook animation.", + "version": 1, + "propertyLayout": { + "propertyGroups": [ + { + "$import": "MaterialInputs/SixPointLightingPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/BaseColorPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/MetallicPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/RoughnessPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/SpecularPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/NormalPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/OcclusionPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/EmissivePropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/ClearCoatPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/OpacityPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/UvPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/IrradiancePropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/GeneralCommonPropertyGroup.json" + } + ] + }, + "shaders": [ + { + "file": "./SixPointLighting_ForwardPass.shader", + "tag": "ForwardPass_EDS" + }, + { + "file": "./SixPointLighting_DepthPass_WithPS.shader", + "tag": "DepthPass_WithPS" + }, + // Used by the light culling system to produce accurate depth bounds for this object when it uses blended transparency + { + "file": "./SixPointLighting_DepthPassTransparentMin_WithPS.shader", + "tag": "DepthPassTransparentMin_WithPS" + }, + { + "file": "./SixPointLighting_DepthPassTransparentMax_WithPS.shader", + "tag": "DepthPassTransparentMax_WithPS" + } + ], + "functors": [ + { + "type": "Lua", + "args": { + "file": "SixPointLighting_TexturePackEnum.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "SixPointLighting_HandleOpacityDoubleSided.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "SixPointLighting_HandleOpacityMode.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "SixPointLighting_ShaderEnable.lua" + } + } + ], + "uvNameMap": { + "UV0": "Tiled", + "UV1": "Unwrapped" + } +} diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_Common.azsli b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_Common.azsli new file mode 100644 index 0000000..ccb87d1 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_Common.azsli @@ -0,0 +1,104 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/BaseColorInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/RoughnessInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/MetallicInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/SpecularInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/NormalInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/ClearCoatInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/OcclusionInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/EmissiveInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/UvSetCount.azsli" + +ShaderResourceGroup MaterialSrg : SRG_PerMaterial +{ + Texture2D m_topLeftRightBottomMap; + Texture2D m_frontBackMap; + Texture2D m_rightLeftTopMap; + Texture2D m_bottomBackFrontMap; + Texture2D m_depthMap; + float m_depthScale; + float m_rowCount; + float m_columnCount; + float m_debugFrame; + + // Auto-generate material SRG fields for common inputs + COMMON_SRG_INPUTS_BASE_COLOR() + COMMON_SRG_INPUTS_ROUGHNESS() + COMMON_SRG_INPUTS_METALLIC() + COMMON_SRG_INPUTS_SPECULAR_F0() + COMMON_SRG_INPUTS_NORMAL() + COMMON_SRG_INPUTS_CLEAR_COAT() + COMMON_SRG_INPUTS_OCCLUSION() + COMMON_SRG_INPUTS_EMISSIVE() + + float3x3 m_uvMatrix; + float4 m_pad1; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + float3x3 m_uvMatrixInverse; + float4 m_pad2; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + + float m_opacityFactor; + float m_opacityAffectsSpecularFactor; + Texture2D m_opacityMap; + uint m_opacityMapUvIndex; + + Sampler m_sampler + { + AddressU = Wrap; + AddressV = Wrap; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + MaxAnisotropy = 16; + }; + + Texture2D m_brdfMap; + + Sampler m_samplerBrdf + { + AddressU = Clamp; + AddressV = Clamp; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + }; +} + +// Allows you to specify a specific frame of the flipbook to render in MaterialSrg::m_debugFrame +option bool o_enableDebugFrame = false; +option bool o_enableDepthTexture = false; + +float2 GetUvForCurrentFrame(float2 baseUv) +{ + // Fixed frequency of 30hz + // Get the current frame + float frame = (float)(((double)SceneSrg::m_time / (33.3333)) * 1000.0) % (MaterialSrg::m_columnCount * MaterialSrg::m_rowCount); + if(o_enableDebugFrame) + { + // The frame input by the material is 1-indexed, so subtract 1 here to make it 0-indexed + frame = MaterialSrg::m_debugFrame - 1.0f; + } + // Get the row/column of the frame + float frameColumn = floor(frame % MaterialSrg::m_columnCount); + float frameRow = floor(frame / MaterialSrg::m_columnCount) % MaterialSrg::m_rowCount; + + float2 invColumnRowCounts = float2(1.0f, 1.0f) / float2(MaterialSrg::m_columnCount, MaterialSrg::m_rowCount); + float2 sixPointUv = (baseUv + float2(frameColumn, frameRow)) * invColumnRowCounts; + + return sixPointUv; +} \ No newline at end of file diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPassTransparentMax_WithPS.shader b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPassTransparentMax_WithPS.shader new file mode 100644 index 0000000..6db45e8 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPassTransparentMax_WithPS.shader @@ -0,0 +1,32 @@ +{ + "Source" : "./SixPointLighting_DepthPass_WithPS.azsl", + + "RasterState": { "CullMode": "None" }, + + "DepthStencilState" : { + // Note that we assuming reversed depth buffer, which normally means we + // are rendering with GreaterEqual. But in our case we want to render the maximum (furthest) values from the camera. + "Depth" : { "Enable" : true, "CompareFunc" : "LessEqual" } + }, + + + "CompilerHints" : { + }, + + "ProgramSettings" : + { + "EntryPoints": + [ + { + "name": "MainVS", + "type" : "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + }, + + "DrawList" : "depthTransparentMax" +} diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPassTransparentMin_WithPS.shader b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPassTransparentMin_WithPS.shader new file mode 100644 index 0000000..1419c2f --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPassTransparentMin_WithPS.shader @@ -0,0 +1,30 @@ +{ + "Source" : "./SixPointLighting_DepthPass_WithPS.azsl", + + "RasterState": { "CullMode": "None" }, + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } + }, + + "CompilerHints" : { + "DisableOptimizations" : false + }, + + "ProgramSettings" : + { + "EntryPoints": + [ + { + "name": "MainVS", + "type" : "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + }, + + "DrawList" : "depthTransparentMin" +} diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPass_WithPS.azsl b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPass_WithPS.azsl new file mode 100644 index 0000000..303a426 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPass_WithPS.azsl @@ -0,0 +1,82 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include "./SixPointLighting_Common.azsli" +#include + +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/EvaluateTangentFrame.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetNormalToWorld.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetObjectToWorld.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetAlphaAndClip.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardTransformUvs.azsli" + +struct VSInput +{ + float3 m_position : POSITION; + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; + + // only used for parallax depth calculation + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; +}; + +struct VSDepthOutput +{ + // "centroid" is needed for SV_Depth to compile + precise linear centroid float4 m_position : SV_Position; + float2 m_uv[UvSetCount] : UV1; + + // only used for parallax depth calculation + float3 m_normal : NORMAL; + float3 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; +}; + +VSDepthOutput MainVS(VSInput IN) +{ + VSDepthOutput OUT; + + float4x4 objectToWorld = GetObjectToWorld(); + float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0)); + + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition); + + float2 uvs[UvSetCount] = { IN.m_uv0, IN.m_uv1 }; + TransformUvs(uvs, OUT.m_uv); + + return OUT; +} + +struct PSDepthOutput +{ + precise float m_depth : SV_Depth; +}; + +PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + const float3 vertexNormal = normalize(IN.m_normal); + + PSDepthOutput OUT; + + OUT.m_depth = IN.m_position.z; + + float2 sixPointUv = GetUvForCurrentFrame(IN.m_uv[0]); + float alpha = MaterialSrg::m_opacityMap.Sample(MaterialSrg::m_sampler, sixPointUv).r; + + if(o_enableDepthTexture) + { + float depthOffset = MaterialSrg::m_depthMap.Sample(MaterialSrg::m_sampler, sixPointUv).r; + OUT.m_depth += depthOffset; + } + + return OUT; +} + diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPass_WithPS.shader b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPass_WithPS.shader new file mode 100644 index 0000000..1a0bd3e --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_DepthPass_WithPS.shader @@ -0,0 +1,28 @@ +{ + "Source" : "./SixPointLighting_DepthPass_WithPS.azsl", + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } + }, + + "CompilerHints" : { + "DisableOptimizations" : false + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + }, + + "DrawList" : "depth" +} diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ForwardPass.azsl b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ForwardPass.azsl new file mode 100644 index 0000000..943dfa9 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ForwardPass.azsl @@ -0,0 +1,264 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include "Atom/Features/ShaderQualityOptions.azsli" + +#include "SixPointLighting_Common.azsli" + +// SRGs +#include +#include + +// Pass Output +#include + +// Utility +#include +#include + +// Custom Surface & Lighting +#include + +// Decals +#include + + +// ---------- Material Parameters ---------- + +COMMON_OPTIONS_BASE_COLOR() +COMMON_OPTIONS_ROUGHNESS() +COMMON_OPTIONS_METALLIC() +COMMON_OPTIONS_SPECULAR_F0() +COMMON_OPTIONS_NORMAL() +COMMON_OPTIONS_CLEAR_COAT() +COMMON_OPTIONS_OCCLUSION() +COMMON_OPTIONS_EMISSIVE() + +enum class SixPointTexturePackMode { TpLftRtBt_FrBck, RtLftTp_BtBckFr }; +option SixPointTexturePackMode o_sixPointTexturePackMode = SixPointTexturePackMode::TpLftRtBt_FrBck; + +// Alpha +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/AlphaInput.azsli" + +#include "MaterialFunctions/EvaluateSixPointSurface.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/EvaluateTangentFrame.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetNormalToWorld.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetObjectToWorld.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetAlphaAndClip.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardTransformUvs.azsli" + +// ---------- Vertex Shader ---------- + +struct VSInput +{ + // Base fields (required by the template azsli file)... + float3 m_position : POSITION; + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; +}; + +struct VSOutput +{ + // Base fields (required by the template azsli file)... + // "centroid" is needed for SV_Depth to compile + linear centroid float4 m_position : SV_Position; + float3 m_normal: NORMAL; + float3 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; + float3 m_shadowCoords[ViewSrg::MaxCascadeCount] : UV3; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv[UvSetCount] : UV1; +}; + +#include + +VSOutput SixPointLighting_ForwardPassVS(VSInput IN) +{ + VSOutput OUT; + + float4x4 objectToWorld = GetObjectToWorld(); + float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0)); + OUT.m_worldPosition = worldPosition.xyz; + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition); + + float2 uvs[UvSetCount] = { IN.m_uv0, IN.m_uv1 }; + TransformUvs(uvs, OUT.m_uv); + + VertexHelper(IN, OUT, worldPosition, false); + + return OUT; +} + +// ---------- Pixel Shader ---------- + +PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depthNDC) +{ + const float3 vertexNormal = normalize(IN.m_normal); + + // ------- Tangents & Bitangents ------- + float3 tangents[UvSetCount] = { IN.m_tangent, IN.m_tangent }; + float3 bitangents[UvSetCount] = { IN.m_bitangent, IN.m_bitangent }; + + if (o_normal_useTexture || (o_clearCoat_enabled && o_clearCoat_normal_useTexture)) + { + for (int i = 0; i != UvSetCount; ++i) + { + EvaluateTangentFrame( + vertexNormal, + IN.m_worldPosition, + isFrontFace, + IN.m_uv[i], + i, + IN.m_tangent, + IN.m_bitangent, + tangents[i], + bitangents[i]); + } + } + + // ------- Depth ------- + + depthNDC = IN.m_position.z; + bool displacementIsClipped = false; + + Surface surface; + surface.transmission.InitializeToZero(); + surface.position = IN.m_worldPosition.xyz; + surface.normal = vertexNormal; + surface.vertexNormal = surface.normal; + + // ------- Alpha & Clip ------- + float2 baseColorUv = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex]; + float2 sixPointUv = GetUvForCurrentFrame(baseColorUv); + + float alpha = GetAlphaInputAndClip(MaterialSrg::m_baseColorMap, MaterialSrg::m_opacityMap, sixPointUv, sixPointUv, MaterialSrg::m_sampler, MaterialSrg::m_opacityFactor, o_opacity_source); + + EvaluateSixPointSurface(vertexNormal, IN.m_uv, tangents, bitangents, isFrontFace, displacementIsClipped, surface); + + // ------- Lighting Data ------- + + LightingData lightingData; + + // Light iterator + lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData); + lightingData.Init(surface.position, surface.normal, surface.roughnessLinear); + + // Diffuse and Specular response (used in IBL calculations) + lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear); + lightingData.diffuseResponse = 1.0 - lightingData.specularResponse; + + if(o_clearCoat_feature_enabled) + { + // Clear coat layer has fixed IOR = 1.5 and transparent => F0 = (1.5 - 1)^2 / (1.5 + 1)^2 = 0.04 + lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor); + } + + // ------- Multiscatter ------- + + lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation); + + // ------- Lighting Calculation ------- + // Here is where we tie into the light loop for our custom lighting. + // We call the default ApplyDirectLighting and ApplyIBL functions, which will iterate over each light type in lightingData. + // These functions will then call our custom GetDiffuseLighting and GetSpecularLighting functions for each light. + + // Apply Decals + ApplyDecals(lightingData.tileIterator, surface); + + // Apply Direct Lighting + ApplyDirectLighting(surface, lightingData, IN.m_position); + + // Apply Image Based Lighting (IBL) + ApplyIBL(surface, lightingData); + + // Finalize Lighting + lightingData.FinalizeLighting(); + + PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha); + + // ------- Opacity ------- + + if (o_opacity_mode == OpacityMode::Blended) + { + // Increase opacity at grazing angles for surfaces with a low m_opacityAffectsSpecularFactor. + // For m_opacityAffectsSpecularFactor values close to 0, that indicates a transparent surface + // like glass, so it becomes less transparent at grazing angles. For m_opacityAffectsSpecularFactor + // values close to 1.0, that indicates the absence of a surface entirely, so this effect should + // not apply. + float fresnelAlpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; + alpha = lerp(fresnelAlpha, alpha, MaterialSrg::m_opacityAffectsSpecularFactor); + + // [GFX_TODO ATOM-13187] PbrLighting shouldn't be writing directly to render targets. It's confusing when + // specular is being added to diffuse just because we're calling render target 0 "diffuse". + + // For blended mode, we do (dest * alpha) + (source * 1.0). This allows the specular + // to be added on top of the diffuse, but then the diffuse must be pre-multiplied. + // It's done this way because surface transparency doesn't really change specular response (eg, glass). + + lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; + + lightingOutput.m_diffuseColor.w = alpha; + } + + return lightingOutput; +} + +ForwardPassOutputWithDepth SixPointLighting_ForwardPassPS(VSOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + ForwardPassOutputWithDepth OUT; + float depth; + + PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth); + +#ifdef UNIFIED_FORWARD_OUTPUT + OUT.m_color.rgb = lightingOutput.m_diffuseColor.rgb + lightingOutput.m_specularColor.rgb; + OUT.m_color.a = lightingOutput.m_diffuseColor.a; + OUT.m_depth = depth; +#else + OUT.m_diffuseColor = lightingOutput.m_diffuseColor; + OUT.m_specularColor = lightingOutput.m_specularColor; + OUT.m_specularF0 = lightingOutput.m_specularF0; + OUT.m_albedo = lightingOutput.m_albedo; + OUT.m_normal = lightingOutput.m_normal; + OUT.m_depth = depth; +#endif + return OUT; +} + +[earlydepthstencil] +ForwardPassOutput SixPointLighting_ForwardPassPS_EDS(VSOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + ForwardPassOutput OUT; + float depth; + + PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth); + +#ifdef UNIFIED_FORWARD_OUTPUT + OUT.m_color.rgb = lightingOutput.m_diffuseColor.rgb + lightingOutput.m_specularColor.rgb; + OUT.m_color.a = lightingOutput.m_diffuseColor.a; +#else + OUT.m_diffuseColor = lightingOutput.m_diffuseColor; + OUT.m_specularColor = lightingOutput.m_specularColor; + OUT.m_specularF0 = lightingOutput.m_specularF0; + OUT.m_albedo = lightingOutput.m_albedo; + OUT.m_normal = lightingOutput.m_normal; +#endif + return OUT; +} \ No newline at end of file diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ForwardPass.shader b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ForwardPass.shader new file mode 100644 index 0000000..ff18c8a --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ForwardPass.shader @@ -0,0 +1,49 @@ +{ + "Source" : "./SixPointLighting_ForwardPass.azsl", + + "DepthStencilState" : + { + "Depth" : + { + "Enable" : true, + "CompareFunc" : "GreaterEqual" + }, + "Stencil" : + { + "Enable" : true, + "ReadMask" : "0x00", + "WriteMask" : "0xFF", + "FrontFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + }, + "BackFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + } + } + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "SixPointLighting_ForwardPassVS", + "type": "Vertex" + }, + { + "name": "SixPointLighting_ForwardPassPS_EDS", + "type": "Fragment" + } + ] + }, + + "DrawList" : "transparent" +} diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_HandleOpacityDoubleSided.lua b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_HandleOpacityDoubleSided.lua new file mode 100644 index 0000000..9584698 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_HandleOpacityDoubleSided.lua @@ -0,0 +1,32 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +function GetMaterialPropertyDependencies() + return {"general.doubleSided"} +end + +ForwardPassIndex = 0 +ForwardPassEdsIndex = 1 + +function Process(context) + local doubleSided = context:GetMaterialPropertyValue_bool("general.doubleSided") + local lastShader = context:GetShaderCount() - 1; + + if(doubleSided) then + for i=0,lastShader do + context:GetShader(i):GetRenderStatesOverride():SetCullMode(CullMode_None) + end + else + for i=0,lastShader do + context:GetShader(i):GetRenderStatesOverride():ClearCullMode() + end + end +end diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_HandleOpacityMode.lua b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_HandleOpacityMode.lua new file mode 100644 index 0000000..9315131 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_HandleOpacityMode.lua @@ -0,0 +1,106 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +function GetMaterialPropertyDependencies() + return {"opacity.mode", "opacity.alphaSource", "opacity.textureMap"} +end + +OpacityMode_Opaque = 0 +OpacityMode_Cutout = 1 +OpacityMode_Blended = 2 +OpacityMode_TintedTransparent = 3 + +AlphaSource_Packed = 0 +AlphaSource_Split = 1 +AlphaSource_None = 2 + +function ConfigureAlphaBlending(shaderItem) + shaderItem:GetRenderStatesOverride():SetDepthEnabled(true) + shaderItem:GetRenderStatesOverride():SetDepthWriteMask(DepthWriteMask_Zero) + shaderItem:GetRenderStatesOverride():SetBlendEnabled(0, true) + shaderItem:GetRenderStatesOverride():SetBlendSource(0, BlendFactor_One) + shaderItem:GetRenderStatesOverride():SetBlendDest(0, BlendFactor_AlphaSourceInverse) + shaderItem:GetRenderStatesOverride():SetBlendOp(0, BlendOp_Add) +end + +function ConfigureDualSourceBlending(shaderItem) + -- This blend multiplies the dest against color source 1, then adds color source 0. + shaderItem:GetRenderStatesOverride():SetDepthEnabled(true) + shaderItem:GetRenderStatesOverride():SetDepthWriteMask(DepthWriteMask_Zero) + shaderItem:GetRenderStatesOverride():SetBlendEnabled(0, true) + shaderItem:GetRenderStatesOverride():SetBlendSource(0, BlendFactor_One) + shaderItem:GetRenderStatesOverride():SetBlendDest(0, BlendFactor_ColorSource1) + shaderItem:GetRenderStatesOverride():SetBlendOp(0, BlendOp_Add) +end + +function ResetAlphaBlending(shaderItem) + shaderItem:GetRenderStatesOverride():ClearDepthEnabled() + shaderItem:GetRenderStatesOverride():ClearDepthWriteMask() + shaderItem:GetRenderStatesOverride():ClearBlendEnabled(0) + shaderItem:GetRenderStatesOverride():ClearBlendSource(0) + shaderItem:GetRenderStatesOverride():ClearBlendDest(0) + shaderItem:GetRenderStatesOverride():ClearBlendOp(0) +end + +function Process(context) + local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") + + local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS") + + if(opacityMode == OpacityMode_Blended) then + ConfigureAlphaBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("transparent") + elseif(opacityMode == OpacityMode_TintedTransparent) then + ConfigureDualSourceBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("transparent") + else + ResetAlphaBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("") -- reset to default draw list + end +end + +function ProcessEditor(context) + local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") + + local mainVisibility + if(opacityMode == OpacityMode_Opaque) then + mainVisibility = MaterialPropertyVisibility_Hidden + else + mainVisibility = MaterialPropertyVisibility_Enabled + end + + context:SetMaterialPropertyVisibility("opacity.alphaSource", mainVisibility) + context:SetMaterialPropertyVisibility("opacity.textureMap", mainVisibility) + context:SetMaterialPropertyVisibility("opacity.textureMapUv", mainVisibility) + context:SetMaterialPropertyVisibility("opacity.factor", mainVisibility) + + if(opacityMode == OpacityMode_Blended or opacityMode == OpacityMode_TintedTransparent) then + context:SetMaterialPropertyVisibility("opacity.alphaAffectsSpecular", MaterialPropertyVisibility_Enabled) + else + context:SetMaterialPropertyVisibility("opacity.alphaAffectsSpecular", MaterialPropertyVisibility_Hidden) + end + + if(mainVisibility == MaterialPropertyVisibility_Enabled) then + local alphaSource = context:GetMaterialPropertyValue_enum("opacity.alphaSource") + + if(alphaSource ~= AlphaSource_Split) then + context:SetMaterialPropertyVisibility("opacity.textureMap", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Hidden) + else + local textureMap = context:GetMaterialPropertyValue_Image("opacity.textureMap") + + if(nil == textureMap) then + context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Disabled) + context:SetMaterialPropertyVisibility("opacity.factor", MaterialPropertyVisibility_Disabled) + end + end + end +end diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ShaderEnable.lua b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ShaderEnable.lua new file mode 100644 index 0000000..e840207 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_ShaderEnable.lua @@ -0,0 +1,45 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +function GetMaterialPropertyDependencies() + return {"opacity.mode"} +end + +OpacityMode_Opaque = 0 +OpacityMode_Cutout = 1 +OpacityMode_Blended = 2 +OpacityMode_TintedTransparent = 3 + +function TryGetShaderByTag(context, shaderTag) + if context:HasShaderWithTag(shaderTag) then + return context:GetShaderByTag(shaderTag) + else + return nil + end +end + +function TrySetShaderEnabled(shader, enabled) + if shader then + shader:SetEnabled(enabled) + end +end + +function Process(context) + local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") + + local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS") + local depthPassWithPS = context:GetShaderByTag("DepthPass_WithPS") + depthPassWithPS:SetEnabled(false) + forwardPassEDS:SetEnabled(true) + + context:GetShaderByTag("DepthPassTransparentMin_WithPS"):SetEnabled(false) + context:GetShaderByTag("DepthPassTransparentMax_WithPS"):SetEnabled(true) +end diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_TexturePackEnum.lua b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_TexturePackEnum.lua new file mode 100644 index 0000000..48b479b --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointLighting_TexturePackEnum.lua @@ -0,0 +1,36 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +TexturePackMode_TpLftRtBt_FrBck = 0; +TexturePackMode_RtLftTp_BtBckFr = 1; + +function GetMaterialPropertyDependencies() + return {"sixPointLighting.texturePackMode"} +end + +function ProcessEditor(context) + local texturePackMode = context:GetMaterialPropertyValue_enum("sixPointLighting.texturePackMode"); + + -- Depending on which texture pack mode is being used, display the correct one + if(texturePackMode == TexturePackMode_TpLftRtBt_FrBck) then + -- TopLeftRightBack is the first texture, FrontBack is the second. Disable RightLeftTop and BottomBackFront. + context:SetMaterialPropertyVisibility("sixPointLighting.TLRB", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("sixPointLighting.FB", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("sixPointLighting.RLT", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("sixPointLighting.BBF", MaterialPropertyVisibility_Hidden) + elseif(texturePackMode == TexturePackMode_RtLftTp_BtBckFr) then + -- RightLeftTop is the first texture, BottomBackFront is the second. Disable TopLeftRightBack and FrontBack. + context:SetMaterialPropertyVisibility("sixPointLighting.TLRB", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("sixPointLighting.FB", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("sixPointLighting.RLT", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("sixPointLighting.BBF", MaterialPropertyVisibility_Enabled) + end +end \ No newline at end of file diff --git a/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointSurface.azsli b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointSurface.azsli new file mode 100644 index 0000000..ca3a537 --- /dev/null +++ b/atom_gems/AtomTutorials/Assets/SixPointLighting/SixPointSurface.azsli @@ -0,0 +1,109 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +class Surface +{ + +#if ENABLE_CLEAR_COAT + ClearCoatSurfaceData clearCoat; +#endif + TransmissionSurfaceData transmission; + // ------- BasePbrSurfaceData ------- + + precise float3 position; //!< Position in world-space + float3 normal; //!< Normal in world-space + float3 vertexNormal; //!< Vertex normal in world-space + float3 baseColor; //!< Surface base color + float metallic; //!< Surface metallic property + float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use + float roughnessA; //!< Actual roughness value ( a.k.a. "alpha roughness") to be used in microfacet calculations + float roughnessA2; //!< Alpha roughness ^ 2 (i.e. roughnessA * roughnessA), used in GGX, cached here for perfromance + + // Six-point lighting properties + float3 tangent; + float3 bitangent; + float top; + float left; + float right; + float bottom; + float frontside; + float backside; + + // Increase opacity at grazing angles for surfaces with a low m_opacityAffectsSpecularFactor. + // For m_opacityAffectsSpecularFactor values close to 0, that indicates a transparent surface + // like glass, so it becomes less transparent at grazing angles. For m_opacityAffectsSpecularFactor + // values close to 1.0, that indicates the absence of a surface entirely, so this effect should + // not apply. + float opacityAffectsSpecularFactor; + + //! Surface lighting data + float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value + float3 specularF0; //!< Fresnel f0 spectral value of the surface + + //! Applies specular anti-aliasing to roughnessA2 + void ApplySpecularAA(); + + //! Calculates roughnessA and roughnessA2 after roughness has been set + void CalculateRoughnessA(); + + //! Sets albedo, base color, specularF0, and metallic properties using metallic workflow + void SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor, float metallic); +}; + +// Specular Anti-Aliasing technique from this paper: +// http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf +void Surface::ApplySpecularAA() +{ + // Constants for formula below + const float screenVariance = 0.25f; + const float varianceThresh = 0.18f; + + // Specular Anti-Aliasing + float3 dndu = ddx_fine( normal ); + float3 dndv = ddy_fine( normal ); + float variance = screenVariance * (dot( dndu , dndu ) + dot( dndv , dndv )); + float kernelRoughnessA2 = min(2.0 * variance , varianceThresh ); + float filteredRoughnessA2 = saturate ( roughnessA2 + kernelRoughnessA2 ); + roughnessA2 = filteredRoughnessA2; +} + +void Surface::CalculateRoughnessA() +{ + // The roughness value in microfacet calculations (called "alpha" in the literature) does not give perceptually + // linear results. Disney found that squaring the roughness value before using it in microfacet equations causes + // the user-provided roughness parameter to be more perceptually linear. We keep both values available as some + // equations need roughnessLinear (i.e. IBL sampling) while others need roughnessA (i.e. GGX equations). + // See Burley's Disney PBR: https://pdfs.semanticscholar.org/eeee/3b125c09044d3e2f58ed0e4b1b66a677886d.pdf + + roughnessA = max(roughnessLinear * roughnessLinear, MinRoughnessA); + + roughnessA2 = roughnessA * roughnessA; + if(o_applySpecularAA) + { + ApplySpecularAA(); + } +} + +void Surface::SetAlbedoAndSpecularF0(float3 newBaseColor, float specularF0Factor, float newMetallic) +{ + baseColor = newBaseColor; + metallic = newMetallic; + + float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * specularF0Factor; + + // Compute albedo and specularF0 based on metalness + albedo = lerp(baseColor, float3(0.0f, 0.0f, 0.0f), metallic); + specularF0 = lerp(dielectricSpecularF0, baseColor, metallic); +} diff --git a/atom_gems/AtomTutorials/Templates/README.md b/atom_gems/AtomTutorials/Templates/README.md new file mode 100644 index 0000000..deab520 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/README.md @@ -0,0 +1 @@ +The files in this folder serve as starting points for people who would like to code the features in this Gem by following the [O3DE rendering tutorials](https://www.o3de.org/docs/learning-guide/tutorials/rendering/). \ No newline at end of file diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/MaterialFunctions/EvaluateSixPointSurface.azsli b/atom_gems/AtomTutorials/Templates/SixPointLighting/MaterialFunctions/EvaluateSixPointSurface.azsli new file mode 100644 index 0000000..14b761b --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/MaterialFunctions/EvaluateSixPointSurface.azsli @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include <../SixPointSurface.azsli> +#include + +void EvaluateSixPointSurface( + float3 vertexNormal, + float2 uv[UvSetCount], + float3 tangents[UvSetCount], + float3 bitangents[UvSetCount], + bool isFrontFace, + bool displacementIsClipped, + inout Surface surface) +{ + // ------- Base Color ------- + float2 baseColorUv = uv[MaterialSrg::m_baseColorMapUvIndex]; + float3 sampledColor = GetBaseColorInput(MaterialSrg::m_baseColorMap, MaterialSrg::m_sampler, baseColorUv, MaterialSrg::m_baseColor.rgb, o_baseColor_useTexture); + float3 baseColor = BlendBaseColor(sampledColor, MaterialSrg::m_baseColor.rgb, MaterialSrg::m_baseColorFactor, o_baseColorTextureBlendMode, o_baseColor_useTexture); + + // ------- Metallic ------- + float metallic = MaterialSrg::m_metallicFactor; + + // ------- Specular ------- + float specularF0Factor = MaterialSrg::m_specularF0Factor; + surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic); + + // ------- Roughness ------- + surface.roughnessLinear = MaterialSrg::m_roughnessFactor;; + surface.CalculateRoughnessA(); + + // ------- Clearcoat ------- + surface.clearCoat.InitializeToZero(); +} diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/MaterialInputs/SixPointLightingPropertyGroup.json b/atom_gems/AtomTutorials/Templates/SixPointLighting/MaterialInputs/SixPointLightingPropertyGroup.json new file mode 100644 index 0000000..7a92590 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/MaterialInputs/SixPointLightingPropertyGroup.json @@ -0,0 +1,148 @@ +{ + "name": "sixPointLighting", + "displayName": "Six Point Lighting", + "description": "Six point lighting settings.", + "properties": [ + { + "name": "texturePackMode", + "displayName": "Texture Pack Mode", + "description": "Determines how the textures are sampled.", + "type": "Enum", + "enumValues": [ "TpLftRtBt_FrBck", "RtLftTp_BtBckFr" ], + "defaultValue": "TpLftRtBt_FrBck", + "connection": { + "type": "ShaderOption", + "name": "o_sixPointTexturePackMode" + } + }, + { + "name": "TLRB", + "displayName": "Top Left Right Bottom", + "description": "Top Left Right Bottom Lightmap", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_topLeftRightBottomMap" + } + }, + { + "name": "FB", + "displayName": "Front Back", + "description": "Front Back Lightmap", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_frontBackMap" + } + }, + { + "name": "RLT", + "displayName": "Right Left Top", + "description": "Right Left Top Lightmap", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_rightLeftTopMap" + } + }, + { + "name": "BBF", + "displayName": "Bottom Back Front", + "description": "Bottom Back Front Lightmap", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_bottomBackFrontMap" + } + }, + { + "name": "useDepthTexture", + "displayName": "Use Depth", + "description": "Whether to use the depth map.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "depthMap", + "displayName": "Depth", + "description": "Depth texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_depthMap" + } + }, + { + "name": "depthScale", + "displayName": "Scale the Depth Texture", + "description": "Multiplier for the depth texture", + "type": "Float", + "defaultValue": 10.0, + "min": 0.01, + "connection": { + "type": "ShaderInput", + "name": "m_depthScale" + } + }, + { + "name": "rowCount", + "displayName": "Rows in Flipbook", + "description": "Total rows of animation in the flipbook", + "type": "Float", + "defaultValue": 8.0, + "min": 1.0, + "step": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_rowCount" + } + }, + { + "name": "columnCount", + "displayName": "Columns in Flipbook", + "description": "Total columns of animation in the flipbook", + "type": "Float", + "defaultValue": 8.0, + "min": 1.0, + "step": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_columnCount" + } + }, + { + "name": "enableDebugFrame", + "displayName": "Enable debugging a specific frame", + "description": "Locks the frame of the animation", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_enableDebugFrame" + } + }, + { + "name": "debugFrame", + "displayName": "Debug Frame", + "description": "The frame you want to debug", + "type": "Float", + "defaultValue": 1.0, + "min": 1.0, + "step": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_debugFrame" + } + } + ], + "functors": [ + { + "type": "UseTexture", + "args": { + "textureProperty": "depthMap", + "useTextureProperty": "useDepthTexture", + "shaderOption": "o_enableDepthTexture" + } + } + ] +} diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting.azsli b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting.azsli new file mode 100644 index 0000000..4f57291 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting.azsli @@ -0,0 +1,140 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +// Include options first +#include + +// Then include custom surface and lighting data types +#include +#include + +#include +#include +#include + +// Then define the Diffuse and Specular lighting functions +float3 GetDiffuseLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight) +{ + float3 diffuse = DiffuseLambertian(surface.albedo, surface.normal, dirToLight, lightingData.diffuseResponse); + + if(o_clearCoat_feature_enabled) + { + // Attenuate diffuse term by clear coat's fresnel term to account for energy loss + float HdotV = saturate(dot(normalize(dirToLight + lightingData.dirToCamera), lightingData.dirToCamera)); + diffuse *= 1.0 - (FresnelSchlick(HdotV, 0.04) * surface.clearCoat.factor); + } + + diffuse *= lightIntensity; + return diffuse; +} + +float3 GetSpecularLighting(Surface surface, LightingData lightingData, const float3 lightIntensity, const float3 dirToLight) +{ + float3 specular = SpecularGGX(lightingData.dirToCamera, dirToLight, surface.normal, surface.specularF0, lightingData.NdotV, surface.roughnessA2, lightingData.multiScatterCompensation); + + if(o_clearCoat_feature_enabled) + { + float3 halfVector = normalize(dirToLight + lightingData.dirToCamera); + float NdotH = saturate(dot(surface.clearCoat.normal, halfVector)); + float NdotL = saturate(dot(surface.clearCoat.normal, dirToLight)); + float HdotL = saturate(dot(halfVector, dirToLight)); + + // HdotV = HdotL due to the definition of half vector + float3 clearCoatF = FresnelSchlick(HdotL, 0.04) * surface.clearCoat.factor; + float clearCoatRoughness = max(surface.clearCoat.roughness * surface.clearCoat.roughness, 0.0005f); + float3 clearCoatSpecular = ClearCoatGGX(NdotH, HdotL, NdotL, surface.clearCoat.normal, clearCoatRoughness, clearCoatF); + + specular = specular * (1.0 - clearCoatF) + clearCoatSpecular; + } + + specular *= lightIntensity; + + return specular; +} + +// Then include everything else +#include + +#include + +#include +#include + +// Include IBL functions +float3 GetIblDiffuse(Surface surface, float3 diffuseResponse) +{ + float3 irradianceDir = MultiplyVectorQuaternion(surface.normal, SceneSrg::m_iblOrientation); + float3 diffuseSample = SceneSrg::m_diffuseEnvMap.Sample(SceneSrg::m_samplerEnv, GetCubemapCoords(irradianceDir)).rgb; + + return diffuseResponse * surface.albedo * diffuseSample; +} + +void ApplyIBL(Surface surface, inout LightingData lightingData) +{ + bool useIbl = o_enableIBL && IsIndirectLightingEnabled(); + +#ifdef FORCE_IBL_IN_FORWARD_PASS + bool useDiffuseIbl = true; +#else + bool isTransparent = (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent); + bool useDiffuseIbl = isTransparent; + useIbl = useIbl && useDiffuseIbl; +#endif + + if(useIbl) + { + float globalIblExposure = pow(2.0, SceneSrg::m_iblExposure); + + if(useDiffuseIbl) + { + float3 iblDiffuse = GetIblDiffuse(surface, lightingData.diffuseResponse); + lightingData.diffuseLighting += (iblDiffuse * globalIblExposure * lightingData.diffuseAmbientOcclusion); + } + } +} + +struct PbrLightingOutput +{ + float4 m_diffuseColor; + float4 m_specularColor; + float4 m_albedo; + float4 m_specularF0; + float4 m_normal; +}; + + +PbrLightingOutput GetPbrLightingOutput(Surface surface, LightingData lightingData, float alpha) +{ + PbrLightingOutput lightingOutput; + + lightingOutput.m_diffuseColor = float4(lightingData.diffuseLighting, alpha); + lightingOutput.m_specularColor = float4(lightingData.specularLighting, 1.0); + + // albedo, specularF0, roughness, and normals for later passes (specular IBL, Diffuse GI, SSR, AO, etc) + lightingOutput.m_specularF0 = float4(0.0f, 0.0f, 0.0f, surface.roughnessLinear); + lightingOutput.m_albedo.rgb = float3(1.0f, 1.0f, 1.0f) * lightingData.diffuseResponse * lightingData.diffuseAmbientOcclusion; + lightingOutput.m_albedo.a = lightingData.specularOcclusion; + lightingOutput.m_normal.rgb = EncodeNormalSignedOctahedron(surface.normal); + lightingOutput.m_normal.a = 0.0f; + + return lightingOutput; +} + +PbrLightingOutput DebugOutput(float3 color) +{ + PbrLightingOutput output = (PbrLightingOutput)0; + + float3 defaultNormal = float3(0.0f, 0.0f, 1.0f); + + output.m_diffuseColor = float4(color.rgb, 1.0f); + output.m_normal.rgb = EncodeNormalSignedOctahedron(defaultNormal); + + return output; +} diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting.materialtype b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting.materialtype new file mode 100644 index 0000000..7613d47 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting.materialtype @@ -0,0 +1,96 @@ +{ + "description": "Material Type with six point lighting of a flipbook animation.", + "version": 1, + "propertyLayout": { + "propertyGroups": [ + { + "$import": "MaterialInputs/SixPointLightingPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/BaseColorPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/MetallicPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/RoughnessPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/SpecularPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/NormalPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/OcclusionPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/EmissivePropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/ClearCoatPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/OpacityPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/UvPropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/IrradiancePropertyGroup.json" + }, + { + "$import": "{your-path-to-o3de}/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/GeneralCommonPropertyGroup.json" + } + ] + }, + "shaders": [ + { + "file": "./SixPointLighting_ForwardPass.shader", + "tag": "ForwardPass_EDS" + }, + { + "file": "./SixPointLighting_DepthPass_WithPS.shader", + "tag": "DepthPass_WithPS" + }, + // Used by the light culling system to produce accurate depth bounds for this object when it uses blended transparency + { + "file": "./SixPointLighting_DepthPassTransparentMin_WithPS.shader", + "tag": "DepthPassTransparentMin_WithPS" + }, + { + "file": "./SixPointLighting_DepthPassTransparentMax_WithPS.shader", + "tag": "DepthPassTransparentMax_WithPS" + } + ], + "functors": [ + { + "type": "Lua", + "args": { + "file": "SixPointLighting_TexturePackEnum.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "SixPointLighting_HandleOpacityDoubleSided.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "SixPointLighting_HandleOpacityMode.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "SixPointLighting_ShaderEnable.lua" + } + } + ], + "uvNameMap": { + "UV0": "Tiled", + "UV1": "Unwrapped" + } +} diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_Common.azsli b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_Common.azsli new file mode 100644 index 0000000..4b84c63 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_Common.azsli @@ -0,0 +1,85 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + + +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/BaseColorInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/RoughnessInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/MetallicInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/SpecularInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/NormalInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/ClearCoatInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/OcclusionInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/EmissiveInput.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/UvSetCount.azsli" + +ShaderResourceGroup MaterialSrg : SRG_PerMaterial +{ + Texture2D m_topLeftRightBottomMap; + Texture2D m_frontBackMap; + Texture2D m_rightLeftTopMap; + Texture2D m_bottomBackFrontMap; + Texture2D m_depthMap; + float m_depthScale; + float m_rowCount; + float m_columnCount; + float m_debugFrame; + + // Auto-generate material SRG fields for common inputs + COMMON_SRG_INPUTS_BASE_COLOR() + COMMON_SRG_INPUTS_ROUGHNESS() + COMMON_SRG_INPUTS_METALLIC() + COMMON_SRG_INPUTS_SPECULAR_F0() + COMMON_SRG_INPUTS_NORMAL() + COMMON_SRG_INPUTS_CLEAR_COAT() + COMMON_SRG_INPUTS_OCCLUSION() + COMMON_SRG_INPUTS_EMISSIVE() + + float3x3 m_uvMatrix; + float4 m_pad1; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + float3x3 m_uvMatrixInverse; + float4 m_pad2; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + + float m_opacityFactor; + float m_opacityAffectsSpecularFactor; + Texture2D m_opacityMap; + uint m_opacityMapUvIndex; + + Sampler m_sampler + { + AddressU = Wrap; + AddressV = Wrap; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + MaxAnisotropy = 16; + }; + + Texture2D m_brdfMap; + + Sampler m_samplerBrdf + { + AddressU = Clamp; + AddressV = Clamp; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + }; +} + +// Allows you to specify a specific frame of the flipbook to render in MaterialSrg::m_debugFrame +option bool o_enableDebugFrame = false; +option bool o_enableDepthTexture = false; diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPassTransparentMax_WithPS.shader b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPassTransparentMax_WithPS.shader new file mode 100644 index 0000000..6db45e8 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPassTransparentMax_WithPS.shader @@ -0,0 +1,32 @@ +{ + "Source" : "./SixPointLighting_DepthPass_WithPS.azsl", + + "RasterState": { "CullMode": "None" }, + + "DepthStencilState" : { + // Note that we assuming reversed depth buffer, which normally means we + // are rendering with GreaterEqual. But in our case we want to render the maximum (furthest) values from the camera. + "Depth" : { "Enable" : true, "CompareFunc" : "LessEqual" } + }, + + + "CompilerHints" : { + }, + + "ProgramSettings" : + { + "EntryPoints": + [ + { + "name": "MainVS", + "type" : "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + }, + + "DrawList" : "depthTransparentMax" +} diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPassTransparentMin_WithPS.shader b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPassTransparentMin_WithPS.shader new file mode 100644 index 0000000..1419c2f --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPassTransparentMin_WithPS.shader @@ -0,0 +1,30 @@ +{ + "Source" : "./SixPointLighting_DepthPass_WithPS.azsl", + + "RasterState": { "CullMode": "None" }, + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } + }, + + "CompilerHints" : { + "DisableOptimizations" : false + }, + + "ProgramSettings" : + { + "EntryPoints": + [ + { + "name": "MainVS", + "type" : "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + }, + + "DrawList" : "depthTransparentMin" +} diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPass_WithPS.azsl b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPass_WithPS.azsl new file mode 100644 index 0000000..12adaf1 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPass_WithPS.azsl @@ -0,0 +1,73 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include "./SixPointLighting_Common.azsli" +#include + +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/EvaluateTangentFrame.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetNormalToWorld.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetObjectToWorld.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetAlphaAndClip.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardTransformUvs.azsli" + +struct VSInput +{ + float3 m_position : POSITION; + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; + + // only used for parallax depth calculation + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; +}; + +struct VSDepthOutput +{ + // "centroid" is needed for SV_Depth to compile + precise linear centroid float4 m_position : SV_Position; + float2 m_uv[UvSetCount] : UV1; + + // only used for parallax depth calculation + float3 m_normal : NORMAL; + float3 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; +}; + +VSDepthOutput MainVS(VSInput IN) +{ + VSDepthOutput OUT; + + float4x4 objectToWorld = GetObjectToWorld(); + float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0)); + + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition); + + float2 uvs[UvSetCount] = { IN.m_uv0, IN.m_uv1 }; + TransformUvs(uvs, OUT.m_uv); + + return OUT; +} + +struct PSDepthOutput +{ + precise float m_depth : SV_Depth; +}; + +PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + const float3 vertexNormal = normalize(IN.m_normal); + + PSDepthOutput OUT; + + OUT.m_depth = IN.m_position.z; + + return OUT; +} + diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPass_WithPS.shader b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPass_WithPS.shader new file mode 100644 index 0000000..1a0bd3e --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_DepthPass_WithPS.shader @@ -0,0 +1,28 @@ +{ + "Source" : "./SixPointLighting_DepthPass_WithPS.azsl", + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } + }, + + "CompilerHints" : { + "DisableOptimizations" : false + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + }, + + "DrawList" : "depth" +} diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ForwardPass.azsl b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ForwardPass.azsl new file mode 100644 index 0000000..ceeed40 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ForwardPass.azsl @@ -0,0 +1,257 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include "Atom/Features/ShaderQualityOptions.azsli" + +#include "SixPointLighting_Common.azsli" + +// SRGs +#include +#include + +// Pass Output +#include + +// Utility +#include +#include + +// Custom Surface & Lighting +#include + +// Decals +#include + +// ---------- Material Parameters ---------- + +COMMON_OPTIONS_BASE_COLOR() +COMMON_OPTIONS_ROUGHNESS() +COMMON_OPTIONS_METALLIC() +COMMON_OPTIONS_SPECULAR_F0() +COMMON_OPTIONS_NORMAL() +COMMON_OPTIONS_CLEAR_COAT() +COMMON_OPTIONS_OCCLUSION() +COMMON_OPTIONS_EMISSIVE() + +enum class SixPointTexturePackMode { TpLftRtBt_FrBck, RtLftTp_BtBckFr }; +option SixPointTexturePackMode o_sixPointTexturePackMode = SixPointTexturePackMode::TpLftRtBt_FrBck; + +// Alpha +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/AlphaInput.azsli" + +#include "MaterialFunctions/EvaluateSixPointSurface.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/EvaluateTangentFrame.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetNormalToWorld.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetObjectToWorld.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardGetAlphaAndClip.azsli" +#include "Atom/Feature/Common/Assets/Materials/Types/MaterialFunctions/StandardTransformUvs.azsli" + + +// ---------- Vertex Shader ---------- + +struct VSInput +{ + // Base fields (required by the template azsli file)... + float3 m_position : POSITION; + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; +}; + +struct VSOutput +{ + // Base fields (required by the template azsli file)... + // "centroid" is needed for SV_Depth to compile + precise linear centroid float4 m_position : SV_Position; + float3 m_normal: NORMAL; + float3 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv[UvSetCount] : UV1; +}; + +#include + +VSOutput SixPointLighting_ForwardPassVS(VSInput IN) +{ + VSOutput OUT; + + float4x4 objectToWorld = GetObjectToWorld(); + float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0)); + OUT.m_worldPosition = worldPosition.xyz; + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition); + + float2 uvs[UvSetCount] = { IN.m_uv0, IN.m_uv1 }; + TransformUvs(uvs, OUT.m_uv); + + VertexHelper(IN, OUT, worldPosition, false); + + return OUT; +} + +// ---------- Pixel Shader ---------- + +PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depthNDC) +{ + const float3 vertexNormal = normalize(IN.m_normal); + + // ------- Tangents & Bitangents ------- + float3 tangents[UvSetCount] = { IN.m_tangent, IN.m_tangent }; + float3 bitangents[UvSetCount] = { IN.m_bitangent, IN.m_bitangent }; + + if (o_normal_useTexture || (o_clearCoat_enabled && o_clearCoat_normal_useTexture)) + { + for (int i = 0; i != UvSetCount; ++i) + { + EvaluateTangentFrame( + vertexNormal, + IN.m_worldPosition, + isFrontFace, + IN.m_uv[i], + i, + IN.m_tangent, + IN.m_bitangent, + tangents[i], + bitangents[i]); + } + } + + // ------- Depth ------- + + depthNDC = IN.m_position.z; + bool displacementIsClipped = false; + + Surface surface; + surface.transmission.InitializeToZero(); + surface.position = IN.m_worldPosition.xyz; + surface.normal = vertexNormal; + surface.vertexNormal = vertexNormal; + + // ------- Alpha & Clip ------- + float alpha = GetAlphaAndClip(IN.m_uv); + + EvaluateSixPointSurface(vertexNormal, IN.m_uv, tangents, bitangents, isFrontFace, displacementIsClipped, surface); + + // ------- Lighting Data ------- + + LightingData lightingData; + + // Light iterator + lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData); + lightingData.Init(surface.position, surface.normal, surface.roughnessLinear); + + // Diffuse and Specular response (used in IBL calculations) + lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear); + lightingData.diffuseResponse = 1.0 - lightingData.specularResponse; + + if(o_clearCoat_feature_enabled) + { + // Clear coat layer has fixed IOR = 1.5 and transparent => F0 = (1.5 - 1)^2 / (1.5 + 1)^2 = 0.04 + lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor); + } + + // ------- Multiscatter ------- + + lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation); + + // ------- Lighting Calculation ------- + + // Apply Decals + ApplyDecals(lightingData.tileIterator, surface); + + // Apply Direct Lighting + ApplyDirectLighting(surface, lightingData, IN.m_position); + + // Apply Image Based Lighting (IBL) + ApplyIBL(surface, lightingData); + + // Finalize Lighting + lightingData.FinalizeLighting(); + + PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha); + + // ------- Opacity ------- + + if (o_opacity_mode == OpacityMode::Blended) + { + // Increase opacity at grazing angles for surfaces with a low m_opacityAffectsSpecularFactor. + // For m_opacityAffectsSpecularFactor values close to 0, that indicates a transparent surface + // like glass, so it becomes less transparent at grazing angles. For m_opacityAffectsSpecularFactor + // values close to 1.0, that indicates the absence of a surface entirely, so this effect should + // not apply. + float fresnelAlpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; + alpha = lerp(fresnelAlpha, alpha, MaterialSrg::m_opacityAffectsSpecularFactor); + + // [GFX_TODO ATOM-13187] PbrLighting shouldn't be writing directly to render targets. It's confusing when + // specular is being added to diffuse just because we're calling render target 0 "diffuse". + + // For blended mode, we do (dest * alpha) + (source * 1.0). This allows the specular + // to be added on top of the diffuse, but then the diffuse must be pre-multiplied. + // It's done this way because surface transparency doesn't really change specular response (eg, glass). + + lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; + + lightingOutput.m_diffuseColor.w = alpha; + } + + return lightingOutput; +} + +ForwardPassOutputWithDepth SixPointLighting_ForwardPassPS(VSOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + ForwardPassOutputWithDepth OUT; + float depth; + + PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth); + +#ifdef UNIFIED_FORWARD_OUTPUT + OUT.m_color.rgb = lightingOutput.m_diffuseColor.rgb + lightingOutput.m_specularColor.rgb; + OUT.m_color.a = lightingOutput.m_diffuseColor.a; + OUT.m_depth = depth; +#else + OUT.m_diffuseColor = lightingOutput.m_diffuseColor; + OUT.m_specularColor = lightingOutput.m_specularColor; + OUT.m_specularF0 = lightingOutput.m_specularF0; + OUT.m_albedo = lightingOutput.m_albedo; + OUT.m_normal = lightingOutput.m_normal; + OUT.m_depth = depth; +#endif + return OUT; +} + +[earlydepthstencil] +ForwardPassOutput SixPointLighting_ForwardPassPS_EDS(VSOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + ForwardPassOutput OUT; + float depth; + + PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth); + +#ifdef UNIFIED_FORWARD_OUTPUT + OUT.m_color.rgb = lightingOutput.m_diffuseColor.rgb + lightingOutput.m_specularColor.rgb; + OUT.m_color.a = lightingOutput.m_diffuseColor.a; +#else + OUT.m_diffuseColor = lightingOutput.m_diffuseColor; + OUT.m_specularColor = lightingOutput.m_specularColor; + OUT.m_specularF0 = lightingOutput.m_specularF0; + OUT.m_albedo = lightingOutput.m_albedo; + OUT.m_normal = lightingOutput.m_normal; +#endif + return OUT; +} \ No newline at end of file diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ForwardPass.shader b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ForwardPass.shader new file mode 100644 index 0000000..5e57c5f --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ForwardPass.shader @@ -0,0 +1,49 @@ +{ + "Source" : "./SixPointLighting_ForwardPass.azsl", + + "DepthStencilState" : + { + "Depth" : + { + "Enable" : true, + "CompareFunc" : "GreaterEqual" + }, + "Stencil" : + { + "Enable" : true, + "ReadMask" : "0x00", + "WriteMask" : "0xFF", + "FrontFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + }, + "BackFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + } + } + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "SixPointLighting_ForwardPassVS", + "type": "Vertex" + }, + { + "name": "SixPointLighting_ForwardPassPS_EDS", + "type": "Fragment" + } + ] + }, + + "DrawList" : "forward" +} diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_HandleOpacityDoubleSided.lua b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_HandleOpacityDoubleSided.lua new file mode 100644 index 0000000..9584698 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_HandleOpacityDoubleSided.lua @@ -0,0 +1,32 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +function GetMaterialPropertyDependencies() + return {"general.doubleSided"} +end + +ForwardPassIndex = 0 +ForwardPassEdsIndex = 1 + +function Process(context) + local doubleSided = context:GetMaterialPropertyValue_bool("general.doubleSided") + local lastShader = context:GetShaderCount() - 1; + + if(doubleSided) then + for i=0,lastShader do + context:GetShader(i):GetRenderStatesOverride():SetCullMode(CullMode_None) + end + else + for i=0,lastShader do + context:GetShader(i):GetRenderStatesOverride():ClearCullMode() + end + end +end diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_HandleOpacityMode.lua b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_HandleOpacityMode.lua new file mode 100644 index 0000000..9315131 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_HandleOpacityMode.lua @@ -0,0 +1,106 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +function GetMaterialPropertyDependencies() + return {"opacity.mode", "opacity.alphaSource", "opacity.textureMap"} +end + +OpacityMode_Opaque = 0 +OpacityMode_Cutout = 1 +OpacityMode_Blended = 2 +OpacityMode_TintedTransparent = 3 + +AlphaSource_Packed = 0 +AlphaSource_Split = 1 +AlphaSource_None = 2 + +function ConfigureAlphaBlending(shaderItem) + shaderItem:GetRenderStatesOverride():SetDepthEnabled(true) + shaderItem:GetRenderStatesOverride():SetDepthWriteMask(DepthWriteMask_Zero) + shaderItem:GetRenderStatesOverride():SetBlendEnabled(0, true) + shaderItem:GetRenderStatesOverride():SetBlendSource(0, BlendFactor_One) + shaderItem:GetRenderStatesOverride():SetBlendDest(0, BlendFactor_AlphaSourceInverse) + shaderItem:GetRenderStatesOverride():SetBlendOp(0, BlendOp_Add) +end + +function ConfigureDualSourceBlending(shaderItem) + -- This blend multiplies the dest against color source 1, then adds color source 0. + shaderItem:GetRenderStatesOverride():SetDepthEnabled(true) + shaderItem:GetRenderStatesOverride():SetDepthWriteMask(DepthWriteMask_Zero) + shaderItem:GetRenderStatesOverride():SetBlendEnabled(0, true) + shaderItem:GetRenderStatesOverride():SetBlendSource(0, BlendFactor_One) + shaderItem:GetRenderStatesOverride():SetBlendDest(0, BlendFactor_ColorSource1) + shaderItem:GetRenderStatesOverride():SetBlendOp(0, BlendOp_Add) +end + +function ResetAlphaBlending(shaderItem) + shaderItem:GetRenderStatesOverride():ClearDepthEnabled() + shaderItem:GetRenderStatesOverride():ClearDepthWriteMask() + shaderItem:GetRenderStatesOverride():ClearBlendEnabled(0) + shaderItem:GetRenderStatesOverride():ClearBlendSource(0) + shaderItem:GetRenderStatesOverride():ClearBlendDest(0) + shaderItem:GetRenderStatesOverride():ClearBlendOp(0) +end + +function Process(context) + local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") + + local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS") + + if(opacityMode == OpacityMode_Blended) then + ConfigureAlphaBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("transparent") + elseif(opacityMode == OpacityMode_TintedTransparent) then + ConfigureDualSourceBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("transparent") + else + ResetAlphaBlending(forwardPassEDS) + forwardPassEDS:SetDrawListTagOverride("") -- reset to default draw list + end +end + +function ProcessEditor(context) + local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") + + local mainVisibility + if(opacityMode == OpacityMode_Opaque) then + mainVisibility = MaterialPropertyVisibility_Hidden + else + mainVisibility = MaterialPropertyVisibility_Enabled + end + + context:SetMaterialPropertyVisibility("opacity.alphaSource", mainVisibility) + context:SetMaterialPropertyVisibility("opacity.textureMap", mainVisibility) + context:SetMaterialPropertyVisibility("opacity.textureMapUv", mainVisibility) + context:SetMaterialPropertyVisibility("opacity.factor", mainVisibility) + + if(opacityMode == OpacityMode_Blended or opacityMode == OpacityMode_TintedTransparent) then + context:SetMaterialPropertyVisibility("opacity.alphaAffectsSpecular", MaterialPropertyVisibility_Enabled) + else + context:SetMaterialPropertyVisibility("opacity.alphaAffectsSpecular", MaterialPropertyVisibility_Hidden) + end + + if(mainVisibility == MaterialPropertyVisibility_Enabled) then + local alphaSource = context:GetMaterialPropertyValue_enum("opacity.alphaSource") + + if(alphaSource ~= AlphaSource_Split) then + context:SetMaterialPropertyVisibility("opacity.textureMap", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Hidden) + else + local textureMap = context:GetMaterialPropertyValue_Image("opacity.textureMap") + + if(nil == textureMap) then + context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Disabled) + context:SetMaterialPropertyVisibility("opacity.factor", MaterialPropertyVisibility_Disabled) + end + end + end +end diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ShaderEnable.lua b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ShaderEnable.lua new file mode 100644 index 0000000..e840207 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_ShaderEnable.lua @@ -0,0 +1,45 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +function GetMaterialPropertyDependencies() + return {"opacity.mode"} +end + +OpacityMode_Opaque = 0 +OpacityMode_Cutout = 1 +OpacityMode_Blended = 2 +OpacityMode_TintedTransparent = 3 + +function TryGetShaderByTag(context, shaderTag) + if context:HasShaderWithTag(shaderTag) then + return context:GetShaderByTag(shaderTag) + else + return nil + end +end + +function TrySetShaderEnabled(shader, enabled) + if shader then + shader:SetEnabled(enabled) + end +end + +function Process(context) + local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") + + local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS") + local depthPassWithPS = context:GetShaderByTag("DepthPass_WithPS") + depthPassWithPS:SetEnabled(false) + forwardPassEDS:SetEnabled(true) + + context:GetShaderByTag("DepthPassTransparentMin_WithPS"):SetEnabled(false) + context:GetShaderByTag("DepthPassTransparentMax_WithPS"):SetEnabled(true) +end diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_TexturePackEnum.lua b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_TexturePackEnum.lua new file mode 100644 index 0000000..a78abc5 --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointLighting_TexturePackEnum.lua @@ -0,0 +1,30 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +TexturePackMode_TpLftRtBt_FrBck = 0; +TexturePackMode_RtLftTp_BtBckFr = 1; + +function GetMaterialPropertyDependencies() + return {"sixPointLighting.texturePackMode"} +end + +function ProcessEditor(context) + local texturePackMode = context:GetMaterialPropertyValue_enum("sixPointLighting.texturePackMode"); + + -- Depending on which texture pack mode is being used, display the correct one + if(texturePackMode == TexturePackMode_TpLftRtBt_FrBck) then + -- TopLeftRightBack is the first texture, FrontBack is the second. Disable RightLeftTop and BottomBackFront. + context:SetMaterialPropertyVisibility("sixPointLighting.TLRB", MaterialPropertyVisibility_Enabled) + elseif(texturePackMode == TexturePackMode_RtLftTp_BtBckFr) then + -- RightLeftTop is the first texture, BottomBackFront is the second. Disable TopLeftRightBack and FrontBack. + context:SetMaterialPropertyVisibility("sixPointLighting.TLRB", MaterialPropertyVisibility_Hidden) + end +end \ No newline at end of file diff --git a/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointSurface.azsli b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointSurface.azsli new file mode 100644 index 0000000..3d4373a --- /dev/null +++ b/atom_gems/AtomTutorials/Templates/SixPointLighting/SixPointSurface.azsli @@ -0,0 +1,99 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +class Surface +{ + +#if ENABLE_CLEAR_COAT + ClearCoatSurfaceData clearCoat; +#endif + TransmissionSurfaceData transmission; + // ------- BasePbrSurfaceData ------- + + precise float3 position; //!< Position in world-space + float3 normal; //!< Normal in world-space + float3 vertexNormal; //!< Vertex normal in world-space + float3 baseColor; //!< Surface base color + float metallic; //!< Surface metallic property + float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use + float roughnessA; //!< Actual roughness value ( a.k.a. "alpha roughness") to be used in microfacet calculations + float roughnessA2; //!< Alpha roughness ^ 2 (i.e. roughnessA * roughnessA), used in GGX, cached here for perfromance + + // Increase opacity at grazing angles for surfaces with a low m_opacityAffectsSpecularFactor. + // For m_opacityAffectsSpecularFactor values close to 0, that indicates a transparent surface + // like glass, so it becomes less transparent at grazing angles. For m_opacityAffectsSpecularFactor + // values close to 1.0, that indicates the absence of a surface entirely, so this effect should + // not apply. + float opacityAffectsSpecularFactor; + + //! Surface lighting data + float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value + float3 specularF0; //!< Fresnel f0 spectral value of the surface + + //! Applies specular anti-aliasing to roughnessA2 + void ApplySpecularAA(); + + //! Calculates roughnessA and roughnessA2 after roughness has been set + void CalculateRoughnessA(); + + //! Sets albedo, base color, specularF0, and metallic properties using metallic workflow + void SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor, float metallic); +}; + +// Specular Anti-Aliasing technique from this paper: +// http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf +void Surface::ApplySpecularAA() +{ + // Constants for formula below + const float screenVariance = 0.25f; + const float varianceThresh = 0.18f; + + // Specular Anti-Aliasing + float3 dndu = ddx_fine( normal ); + float3 dndv = ddy_fine( normal ); + float variance = screenVariance * (dot( dndu , dndu ) + dot( dndv , dndv )); + float kernelRoughnessA2 = min(2.0 * variance , varianceThresh ); + float filteredRoughnessA2 = saturate ( roughnessA2 + kernelRoughnessA2 ); + roughnessA2 = filteredRoughnessA2; +} + +void Surface::CalculateRoughnessA() +{ + // The roughness value in microfacet calculations (called "alpha" in the literature) does not give perceptually + // linear results. Disney found that squaring the roughness value before using it in microfacet equations causes + // the user-provided roughness parameter to be more perceptually linear. We keep both values available as some + // equations need roughnessLinear (i.e. IBL sampling) while others need roughnessA (i.e. GGX equations). + // See Burley's Disney PBR: https://pdfs.semanticscholar.org/eeee/3b125c09044d3e2f58ed0e4b1b66a677886d.pdf + + roughnessA = max(roughnessLinear * roughnessLinear, MinRoughnessA); + + roughnessA2 = roughnessA * roughnessA; + if(o_applySpecularAA) + { + ApplySpecularAA(); + } +} + +void Surface::SetAlbedoAndSpecularF0(float3 newBaseColor, float specularF0Factor, float newMetallic) +{ + baseColor = newBaseColor; + metallic = newMetallic; + + float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * specularF0Factor; + + // Compute albedo and specularF0 based on metalness + albedo = lerp(baseColor, float3(0.0f, 0.0f, 0.0f), metallic); + specularF0 = lerp(dielectricSpecularF0, baseColor, metallic); +}