summaryrefslogtreecommitdiffstats
path: root/res/effectlib/funcdiffuseReflectionBSDF.glsllib
blob: 250056af7ecedc1b294f918ba15f514bd63c8f21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#ifndef PI
#define PI          3.14159265358979f
#define PI_SQUARE   ( PI * PI )
#endif

vec4 diffuseReflectionBSDF(in vec3 N, in vec3 L, in vec3 viewDir,
                           in vec3 lightDiffuse, in float roughness)
{
    float cosThetaI = max( 0.0f, dot( N, L ) );
    float factor = cosThetaI;
    if ( ( 0.0f < factor ) && ( 0.0f < roughness ) )
    {
        // see http://en.wikipedia.org/wiki/Oren%E2%80%93Nayar_reflectance_model
        float sigmaSquare = 0.25f * PI_SQUARE * roughness * roughness;
        float A = 1.0f - 0.5f * sigmaSquare / ( sigmaSquare + 0.33f );
        float B = 0.45f * sigmaSquare / ( sigmaSquare + 0.09f );

        // project L and viewDir on surface to get the azimuthal angle between them
        // as we don't really need the projections, but the angle between them,
        // it's enough to just use the cross instead
        vec3 pl = normalize( cross( L, N ) );
        vec3 pv = normalize( cross( viewDir, N ) );
        float cosPhi = max( 0.0f, dot( pl, pv ) );

        float sinAlpha, tanBeta;
        float cosThetaO = max( 0.0f, dot( N, viewDir ) );
        float sinThetaI = sqrt( max( 0.0f, 1.0f - cosThetaI * cosThetaI ) );
        float sinThetaO = sqrt( max( 0.0f, 1.0f - cosThetaO * cosThetaO ) );
        if ( cosThetaI < cosThetaO )
        { // -> thetaO < thetaI
            sinAlpha = sinThetaI;
            tanBeta = sinThetaO / cosThetaO;
        }
        else
        {
            sinAlpha = sinThetaO;
            tanBeta = sinThetaI / cosThetaI;
        }

        factor *= A + B * cosPhi * sinAlpha * tanBeta;
    }
    return( vec4( factor * lightDiffuse, 1.0f ) );
}