#version 330 core #extension GL_ARB_shading_language_420pack: require #define float2 vec2 #define float3 vec3 #define float4 vec4 #define int2 ivec2 #define int3 ivec3 #define int4 ivec4 #define uint2 uvec2 #define uint3 uvec3 #define uint4 uvec4 #define float3x3 mat3 #define float4x4 mat4 #extension GL_ARB_texture_gather: require #extension GL_AMD_shader_trinary_minmax: require layout(std140) uniform; #define FRAG_COLOR 0 layout(location = FRAG_COLOR, index = 0) out vec4 outColour; // START UNIFORM DECLARATION struct ShadowReceiverData { mat4 texViewProj; vec2 shadowDepthRange; vec4 invShadowMapSize; }; struct Light { vec3 position; vec3 diffuse; vec3 specular; vec3 attenuation; vec3 spotDirection; vec3 spotParams; }; //Uniforms that change per pass layout(binding = 0) uniform PassBuffer { //Vertex shader (common to both receiver and casters) mat4 viewProj; //Vertex shader mat4 view; ShadowReceiverData shadowRcv[2]; //------------------------------------------------------------------------- //Pixel shader mat3 invViewMatCubemap; float pssmSplitPoints0; float pssmSplitPoints1; Light lights[1]; } pass; //Uniforms that change per Item/Entity, but change very infrequently struct Material { /* kD is already divided by PI to make it energy conserving. (formula is finalDiffuse = NdotL * surfaceDiffuse / PI) */ vec4 bgDiffuse; vec4 kD; //kD.w is alpha_test_threshold vec4 kS; //kS.w is roughness //Fresnel coefficient, may be per colour component (vec3) or scalar (float) //F0.w is transparency vec4 F0; vec4 normalWeights; vec4 cDetailWeights; vec4 detailOffsetScaleD[4]; vec4 detailOffsetScaleN[4]; uvec4 indices0_3; //uintBitsToFloat( indices4_7.w ) contains mNormalMapWeight. uvec4 indices4_7; }; layout(binding = 1) uniform MaterialBuf { Material m[256]; } materialArray; //Uniforms that change per Item/Entity layout(binding = 2) uniform InstanceBuffer { //.x = //The lower 9 bits contain the material's start index. //The higher 23 bits contain the world matrix start index. // //.y = //shadowConstantBias. Send the bias directly to avoid an //unnecessary indirection during the shadow mapping pass. //Must be loaded with uintBitsToFloat uvec4 worldMaterialIdx[4096]; } instance; // END UNIFORM DECLARATION in block { flat uint drawId; vec3 pos; vec3 normal; vec2 uv0; vec4 posL0; vec4 posL1; float depth; } inPs; #define ROUGHNESS material.kS.w //vec4 diffuseCol; Material material; vec3 nNormal; uniform sampler2DShadow texShadowMap[2]; float getShadow( sampler2DShadow shadowMap, vec4 psPosLN, vec4 invShadowMapSize ) { float fDepth = psPosLN.z; vec2 uv = psPosLN.xy / psPosLN.w; float retVal = 0; vec2 fW; vec4 c; retVal += texture( shadowMap, vec3( uv, fDepth ) ).r; return retVal; } /* //Default BRDF vec3 BRDF( vec3 lightDir, vec3 viewDir, float NdotV, vec3 lightDiffuse, vec3 lightSpecular ) { vec3 halfWay= normalize( lightDir + viewDir ); float NdotL = clamp( dot( nNormal, lightDir ), 0.0, 1.0 ); float NdotH = clamp( dot( nNormal, halfWay ), 0.0, 1.0 ); float VdotH = clamp( dot( viewDir, halfWay ), 0.0, 1.0 ); float sqR = ROUGHNESS * ROUGHNESS; //Roughness/Distribution/NDF term (GGX) //Formula: // Where alpha = roughness // R = alpha^2 / [ PI * [ ( NdotH^2 * (alpha^2 - 1) ) + 1 ]^2 ] float f = ( NdotH * sqR - NdotH ) * NdotH + 1.0; float R = sqR / (f * f + 1e-6f); //Geometric/Visibility term (Smith GGX Height-Correlated) float Lambda_GGXV = NdotL * sqrt( (-NdotV * sqR + NdotV) * NdotV + sqR ); float Lambda_GGXL = NdotV * sqrt( (-NdotL * sqR + NdotL) * NdotL + sqR ); float G = 0.5 / (( Lambda_GGXV + Lambda_GGXL + 1e-6f ) * 3.141592654); //Formula: // fresnelS = lerp( (1 - V*H)^5, 1, F0 ) float fresnelS = material.F0.x + pow( 1.0 - VdotH, 5.0 ) * (1.0 - material.F0.x); //We should divide Rs by PI, but it was done inside G for performance vec3 Rs = ( fresnelS * (R * G) ) * material.kS.xyz * lightSpecular; //Diffuse BRDF (*Normalized* Disney, see course_notes_moving_frostbite_to_pbr.pdf //"Moving Frostbite to Physically Based Rendering" Sebastien Lagarde & Charles de Rousiers) float energyBias = ROUGHNESS * 0.5; float energyFactor = mix( 1.0, 1.0 / 1.51, ROUGHNESS ); float fd90 = energyBias + 2.0 * VdotH * VdotH * ROUGHNESS; float lightScatter = 1.0 + (fd90 - 1.0) * pow( 1.0 - NdotL, 5.0 ); float viewScatter = 1.0 + (fd90 - 1.0) * pow( 1.0 - NdotV, 5.0 ); float fresnelD = 1.0f - fresnelS; //We should divide Rd by PI, but it is already included in kD vec3 Rd = (lightScatter * viewScatter * energyFactor * fresnelD) * diffuseCol.xyz * lightDiffuse; return NdotL * (Rs + Rd); } */ void main() { uint materialId = instance.worldMaterialIdx[0].x & 0x1FFu; material = materialArray.m[0]; /// Sample detail maps and weight them against the weight map in the next foreach loop. /// 'insertpiece( SampleDiffuseMap )' must've written to diffuseCol. However if there are no /// diffuse maps, we must initialize it to some value. If there are no diffuse or detail maps, /// we must not access diffuseCol at all, but rather use material.kD directly (see piece( kD ) ). //diffuseCol = material.bgDiffuse; /// Blend the detail diffuse maps with the main diffuse. /// Apply the material's diffuse over the textures //diffuseCol.xyz *= material.kD.xyz; // Geometric normal //nNormal = normalize( inPs.normal ) ; float fShadow = 1.0; vec3 tint = vec3( 1, 1, 1 ); if( inPs.depth <= pass.pssmSplitPoints0 ) { fShadow = getShadow( texShadowMap[0], inPs.posL0, /*pass.shadowRcv[0].invShadowMapSize*/vec4( 0.000488281, 0.000488281, 1, 1 ) ); tint = vec3( 0.0, 0, 1 ); } else if( inPs.depth <= pass.pssmSplitPoints1 ) { fShadow = getShadow( texShadowMap[1], inPs.posL1, /*pass.shadowRcv[1].invShadowMapSize*/vec4( 0.000976562, 0.000976562, 1, 1 ) ); tint = vec3( 1 == 2 ? 1.0 : 0.0, 1 == 1 ? 1.0 : 0.0, 0.0 ); } /// If there is no normal map, the first iteration must /// initialize nNormal instead of try to merge with it. /// Blend the detail normal maps with the main normal. //Everything's in Camera space vec3 viewDir = normalize( -inPs.pos ); float NdotV = clamp( dot( nNormal, viewDir ), 0.0, 1.0 ); vec3 finalColour = vec3(0); //finalColour += BRDF( pass.lights[0].position, viewDir, NdotV, pass.lights[0].diffuse, pass.lights[0].specular ) * fShadow; finalColour = fShadow.xxx; finalColour = mix( finalColour, tint, 0.5 ); /*vec3 lightDir; float fDistance; vec3 tmpColour; float spotCosAngle;*/ //Point lights //Spot lights //spotParams[0].x = 1.0 / cos( InnerAngle ) - cos( OuterAngle ) //spotParams[0].y = cos( OuterAngle / 2 ) //spotParams[0].z = falloff outColour.xyz = finalColour; outColour.w = 1.0; }