danini-the-panini/mittsu-opengl

View on GitHub
lib/mittsu/opengl/shader/chunks/shadowmap_fragment.glsl

Summary

Maintainability
Test Coverage
#ifdef USE_SHADOWMAP

    #ifdef SHADOWMAP_DEBUG

        vec3 frustumColors[3];
        frustumColors[0] = vec3( 1.0, 0.5, 0.0 );
        frustumColors[1] = vec3( 0.0, 1.0, 0.8 );
        frustumColors[2] = vec3( 0.0, 0.5, 1.0 );

    #endif

    #ifdef SHADOWMAP_CASCADE

        int inFrustumCount = 0;

    #endif

    float fDepth;
    vec3 shadowColor = vec3( 1.0 );

    <% parameters[:max_shadows].times do |i| %>
        vec3 shadowCoord = vShadowCoord[ <%= i %> ].xyz / vShadowCoord[ <%= i %> ].w;

                // if ( something && something ) breaks ATI OpenGL shader compiler
                // if ( all( something, something ) ) using this instead

        bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
        bool inFrustum = all( inFrustumVec );

                // don't shadow pixels outside of light frustum
                // use just first frustum (for cascades)
                // don't shadow pixels behind far plane of light frustum

        #ifdef SHADOWMAP_CASCADE

            inFrustumCount += int( inFrustum );
            bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );

        #else

            bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );

        #endif

        bool frustumTest = all( frustumTestVec );

        if ( frustumTest ) {

            shadowCoord.z += shadowBias[ <%= i %> ];

            #if defined( SHADOWMAP_TYPE_PCF )

                        // Percentage-close filtering
                        // (9 pixel kernel)
                        // http://fabiensanglard.net/shadowmappingPCF/

                float shadow = 0.0;

        /*
                        // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL
                        // must enroll loop manually

                for ( float y = -1.25; y <= 1.25; y += 1.25 )
                    for ( float x = -1.25; x <= 1.25; x += 1.25 ) {

                        vec4 rgbaDepth = texture( shadowMap[ <%= i %> ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );

                                // doesn't seem to produce any noticeable visual difference compared to simple texture lookup
                                //vec4 rgbaDepth = textureProj( shadowMap[ <%= i %> ], vec4( vShadowCoord[ <%= i %> ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ <%= i %> ].w ) );

                        float fDepth = unpackDepth( rgbaDepth );

                        if ( fDepth < shadowCoord.z )
                            shadow += 1.0;

                }

                shadow /= 9.0;

        */

                const float shadowDelta = 1.0 / 9.0;

                float xPixelOffset = 1.0 / shadowMapSize[ <%= i %> ].x;
                float yPixelOffset = 1.0 / shadowMapSize[ <%= i %> ].y;

                float dx0 = -1.25 * xPixelOffset;
                float dy0 = -1.25 * yPixelOffset;
                float dx1 = 1.25 * xPixelOffset;
                float dy1 = 1.25 * yPixelOffset;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, dy0 ) ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, dy0 ) ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, dy1 ) ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, dy1 ) ) );
                if ( fDepth < shadowCoord.z ) shadow += shadowDelta;

                shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ <%= i %> ] * shadow ) );

            #elif defined( SHADOWMAP_TYPE_PCF_SOFT )

                        // Percentage-close filtering
                        // (9 pixel kernel)
                        // http://fabiensanglard.net/shadowmappingPCF/

                float shadow = 0.0;

                float xPixelOffset = 1.0 / shadowMapSize[ <%= i %> ].x;
                float yPixelOffset = 1.0 / shadowMapSize[ <%= i %> ].y;

                float dx0 = -1.0 * xPixelOffset;
                float dy0 = -1.0 * yPixelOffset;
                float dx1 = 1.0 * xPixelOffset;
                float dy1 = 1.0 * yPixelOffset;

                mat3 shadowKernel;
                mat3 depthKernel;

                depthKernel[0][0] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, dy0 ) ) );
                depthKernel[0][1] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );
                depthKernel[0][2] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, dy1 ) ) );
                depthKernel[1][0] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );
                depthKernel[1][1] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy ) );
                depthKernel[1][2] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );
                depthKernel[2][0] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, dy0 ) ) );
                depthKernel[2][1] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );
                depthKernel[2][2] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, dy1 ) ) );

                vec3 shadowZ = vec3( shadowCoord.z );
                shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));
                shadowKernel[0] *= vec3(0.25);

                shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));
                shadowKernel[1] *= vec3(0.25);

                shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));
                shadowKernel[2] *= vec3(0.25);

                vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[<%= i %>].xy );

                shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );
                shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );

                vec4 shadowValues;
                shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );
                shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );
                shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );
                shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );

                shadow = dot( shadowValues, vec4( 1.0 ) );

                shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ <%= i %> ] * shadow ) );

            #else

                vec4 rgbaDepth = texture( shadowMap[ <%= i %> ], shadowCoord.xy );
                float fDepth = unpackDepth( rgbaDepth );

                if ( fDepth < shadowCoord.z )

        // spot with multiple shadows is darker

                    shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ <%= i %> ] );

        // spot with multiple shadows has the same color as single shadow spot

        //                     shadowColor = min( shadowColor, vec3( shadowDarkness[ <%= i %> ] ) );

            #endif

        }


        #ifdef SHADOWMAP_DEBUG

            #ifdef SHADOWMAP_CASCADE

                if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ <%= i %> ];

            #else

                if ( inFrustum ) outgoingLight *= frustumColors[ <%= i %> ];

            #endif

        #endif

    <% end %>

    // NOTE: I am unsure if this is correct in linear space.  -bhouston, Dec 29, 2014
    shadowColor = inputToLinear( shadowColor );

    outgoingLight = outgoingLight * shadowColor;

#endif