//========================================================================================================================= // Optional //========================================================================================================================= HEADER { Description = "Glass Shader"; Version = 3; } //========================================================================================================================= // Optional //========================================================================================================================= FEATURES { #include "common/features.hlsl" Feature( F_RENDER_SIGHTS_ONLY, 0..1, "Glass"); } //========================================================================================================================= // Optional //========================================================================================================================= MODES { VrForward(); // Indicates this shader will be used for main rendering ToolsVis( S_MODE_TOOLS_VIS ); // Ability to see in the editor ToolsWireframe("vr_tools_wireframe.shader"); // Allows for mat_wireframe to work ToolsShadingComplexity("tools_shading_complexity.shader"); // Shows how expensive drawing is in debug view Depth( S_MODE_DEPTH ); } //========================================================================================================================= COMMON { #include "common/shared.hlsl" } //========================================================================================================================= struct VertexInput { #include "common/vertexinput.hlsl" }; //========================================================================================================================= struct PixelInput { #include "common/pixelinput.hlsl" }; //========================================================================================================================= VS { #include "common/vertex.hlsl" // // Main // PixelInput MainVs(VS_INPUT i) { PixelInput o = ProcessVertex(i); // Add your vertex manipulation functions here return FinalizeVertex(o); } } //========================================================================================================================= PS { // Combos ---------------------------------------------------------------------------------------------- StaticCombo( S_MODE_DEPTH, 0..1, Sys(ALL) ); StaticCombo( S_RENDER_SIGHTS_ONLY, F_RENDER_SIGHTS_ONLY, Sys(ALL) ); DynamicCombo( D_MULTIVIEW_INSTANCING, 0..1, Sys(PC) ); // Transparency #if (S_RENDER_SIGHTS_ONLY) #define BLEND_MODE_ALREADY_SET RenderState(BlendEnable, true); RenderState(SrcBlend, SRC_ALPHA); RenderState(DstBlend, INV_SRC_ALPHA); #endif // Attributes ------------------------------------------------------------------------------------------ #include "common/pixel.hlsl" BoolAttribute(bWantsFBCopyTexture, !F_RENDER_SIGHTS_ONLY ); BoolAttribute(translucent, true); CreateTexture2D( g_tFrameBufferCopyTexture ) < Attribute("FrameBufferCopyTexture"); SrgbRead( false ); Filter(MIN_MAG_MIP_LINEAR); AddressU( MIRROR ); AddressV( MIRROR ); > ; CreateTexture2DMS( g_tSceneDepth ) < Attribute( "DepthBuffer" ); SrgbRead( false ); Filter( POINT ); AddressU( MIRROR ); AddressV( MIRROR ); >; // // Blur and Refraction Settings // float g_flBlurAmount < Default(0.0f); Range(0.0f, 1.0f); UiGroup("Glass,10/10"); > ; float g_flRefractionStrength < Default(1.005); Range(1.0, 1.1); UiGroup("Glass,10/20"); > ; float g_flIridescence < Default(600.0); Range(0.0f, 1000.0); UiGroup("Glass,10/30"); > ; float g_flIridescenceScale < Default(1.0); Range(0.0f, 10.0); UiGroup("Glass,10/30"); > ; float3 g_vSightLightColor < UiType( Color ); Default3(1.0, 1.0, 1.0); UiGroup("Glass,10/40"); > ; float g_flSightDistanceScale < Default(1.0); Range(0.0, 20.0); UiGroup("Glass,10/50"); > ; // // Overlay layer // CreateInputTexture2D(RedDot, Srgb, 8, "", "_color", "Sight Dot,10/10", Default3(0.0, 0.0, 0.0)); CreateInputTexture2D(RedDot2, Srgb, 8, "", "_color", "Sight Dot,10/10", Default3(0.0, 0.0, 0.0)); CreateInputTexture2D(RedDot3, Srgb, 8, "", "_color", "Sight Dot,10/10", Default3(0.0, 0.0, 0.0)); CreateTexture2DWithoutSampler(g_tRedDot) < Channel(R, Box(RedDot), Linear); Channel(G, Box(RedDot2), Linear); Channel(B, Box(RedDot3), Linear); OutputFormat(BC7); SrgbRead(false); > ; float3 GetIridescence(float3 vCameraDirWs, float3 vNormalWs, float k) { const float3 c1 = float3(3.54585104, 2.93225262, 2.41593945); const float3 x1 = float3(0.69549072, 0.49228336, 0.27699880); const float3 y1 = float3(0.02312639, 0.15225084, 0.52607955); const float3 c2 = float3(3.90307140, 3.21182957, 3.96587128); const float3 x2 = float3(0.11748627, 0.86755042, 0.66077860); const float3 y2 = float3(0.84897130, 0.88445281, 0.73949448); float3 color = 0; float NDotV = dot(vNormalWs, vCameraDirWs); [unroll] for (int n = 1; n <= 8; n++) { float wavelength = abs( NDotV ) * k / float(n); float x = saturate( ( wavelength - 400.0f ) / 300.0f ); float3 col1 = saturate(1 - (c1 * (x - x1)) * (c1 * (x - x1)) - y1); float3 col2 = saturate(1 - (c2 * (x - x2)) * (c2 * (x - x2)) - y2); color += col1 + col2; } return color; } // // Main // float4 MainPs(PixelInput i) : SV_Target0 { Material m = Material::From(i); // Shadows #if S_MODE_DEPTH { float flOpacity = CalcBRDFReflectionFactor(dot(-i.vNormalWs.xyz, g_vCameraDirWs.xyz), m.Roughness, 0.04).x; flOpacity = pow(flOpacity, 1.0f / 2.0f); flOpacity = lerp(flOpacity, 0.75f, sqrt(m.Roughness)); // Glossiness flOpacity = lerp(flOpacity, 1.0 - dot(-i.vNormalWs.xyz, g_vCameraDirWs.xyz), ( g_flRefractionStrength - 1.0f ) * 5.0f ); // Refraction flOpacity = lerp(1.0f, flOpacity + 0.04f, length(m.Albedo)); // Albedo absorption OpaqueFadeDepth(flOpacity, i.vPositionSs.xy); return 1; } #endif m.Metalness = 0; // Glass is always non-metallic float3 vViewRayWs = normalize(i.vPositionWithOffsetWs.xyz); float flNDotV = saturate(dot(-m.Normal, vViewRayWs)); float3 vEnvBRDF = CalcBRDFReflectionFactor(flNDotV, m.Roughness, 0.04); float4 vDotColor; { float4 vRefractionColor = 0; float flDepthPs = RemapValClamped( Tex2DMS( 1 - g_tSceneDepth, i.vPositionSs.xy, 0 ).r, g_flViewportMinZ, g_flViewportMaxZ, 0.0, 1.0); float3 vRefractionWs = RecoverWorldPosFromProjectedDepthAndRay(flDepthPs, normalize(i.vPositionWithOffsetWs.xyz)) - g_vCameraPositionWs; float flDistanceVs = distance(i.vPositionWithOffsetWs.xyz, vRefractionWs); float3 vRefractRayWs = refract(vViewRayWs, m.Normal, 1.0 / g_flRefractionStrength); float3 vRefractWorldPosWs = i.vPositionWithOffsetWs.xyz + vRefractRayWs * flDistanceVs; float4 vPositionPs = Position4WsToPs(float4(vRefractWorldPosWs, 0)); float2 vPositionSs = vPositionPs.xy / vPositionPs.w; vPositionSs = vPositionSs * 0.5 + 0.5; vPositionSs.y = 1.0 - vPositionSs.y; // // Multiview // #if (D_MULTIVIEW_INSTANCING) { vPositionSs.x *= 0.5; } #endif float flAmount; float3 vAlbedoTint = m.Albedo; vAlbedoTint += GetIridescence( vViewRayWs, m.Normal, g_flIridescence ) * g_flIridescenceScale * m.Albedo; // // Color and blur // { flAmount = g_flBlurAmount * m.Roughness * (1.0 - (1.0 / flDistanceVs)); // Isotropic blur based on grazing angle flAmount /= flNDotV; const int nNumMips = 7; float2 vUV = float2(vPositionSs) * g_vFrameBufferCopyInvSizeAndUvScale.zw; vRefractionColor = Tex2DLevel(g_tFrameBufferCopyTexture, vUV, sqrt(flAmount) * nNumMips); } // Blend { m.Emission = lerp(vRefractionColor.xyz, 0.0f, vEnvBRDF); m.Emission *= vAlbedoTint; m.Albedo = 0; } // Sight dot { float3 vRedDotColor = g_vSightLightColor * 20.0f; float3 vCameraToPosition = i.vPositionWithOffsetWs; float3 vCameraDir = normalize( vCameraToPosition ); float flProjectDirOntoNormal = 1.0f / dot( vCameraDir, m.Normal ); float flProjectA = -g_flSightDistanceScale * flProjectDirOntoNormal ; float flProjectDirOntoTangentU = dot( vCameraDir, i.vTangentUWs ) ; float flProjectDirOntoTangentV = dot( vCameraDir, i.vTangentVWs ) ; float2 vRedDotUV = saturate( i.vTextureCoords.xy + ( flProjectA * 0.5 ) * float2( flProjectDirOntoTangentU, flProjectDirOntoTangentV ) ); float2 vRedDotUV2 = saturate( i.vTextureCoords.xy + ( flProjectA * 1.1 ) * float2( flProjectDirOntoTangentU, flProjectDirOntoTangentV ) ); float2 vRedDotUV3 = saturate( i.vTextureCoords.xy + ( flProjectA * 1.2 ) * float2( flProjectDirOntoTangentU, flProjectDirOntoTangentV ) ); float flRedDot = Tex2DLevelS(g_tRedDot, TextureFiltering, vRedDotUV, sqrt(flAmount) * 7 ).r; flRedDot += Tex2DLevelS(g_tRedDot, TextureFiltering, vRedDotUV2, sqrt(flAmount) * 7 ).g; flRedDot += Tex2DLevelS(g_tRedDot, TextureFiltering, vRedDotUV3, sqrt(flAmount) * 7 ).b; vDotColor = float4( flRedDot * vRedDotColor * vAlbedoTint, flRedDot ); m.Emission = lerp(m.Emission, vDotColor.rgb, vDotColor.a ); } #if S_MODE_TOOLS_VIS m.Albedo = m.Emission; m.Emission = 0; #endif } #if S_RENDER_SIGHTS_ONLY return vDotColor; #endif return ShadingModelStandard::Shade(i, m); } }