| /**************************************************************************** |
| ** |
| ** Copyright (C) 2014 NVIDIA Corporation. |
| ** Copyright (C) 2019 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of Qt 3D Studio. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 or (at your option) any later version |
| ** approved by the KDE Free Qt Foundation. The licenses are as published by |
| ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #ifndef SAMPLE_LIGHT_GLSLLIB |
| #define SAMPLE_LIGHT_GLSLLIB |
| |
| #define MAX_NUM_SHADOWS 8 |
| |
| #ifndef QSSG_ENABLE_SSM |
| #define QSSG_ENABLE_SSM 0 |
| #endif |
| |
| #include "SSAOCustomMaterial.glsllib" |
| #if QSSG_ENABLE_SSM |
| #include "shadowMapping.glsllib" |
| #endif |
| |
| #include "funcsampleLightVars.glsllib" |
| |
| #if QSSG_ENABLE_SSM |
| uniform sampler2D shadowMaps[MAX_NUM_SHADOWS]; |
| uniform samplerCube shadowCubes[MAX_NUM_SHADOWS]; |
| uniform int shadowMapCount; |
| uniform int shadowCubeCount; |
| #endif |
| |
| void sampleLight(in LightSource light, |
| in vec3 pos, |
| out vec3 wi, |
| out vec3 opAmbient, |
| out vec3 opDiffuse, |
| out vec3 opSpecular) |
| { |
| float att = 1.0; |
| if (light.position.w == 0.0) // directional light |
| { |
| wi = normalize(light.position.xyz); |
| #if QSSG_ENABLE_SSM |
| if ( light.shadowIdx >= 0 ) |
| att *= sampleOrthographic( shadowMaps[light.shadowIdx], light.shadowControls, light.shadowView, pos, vec2(1.0, light.shadowControls.z) ); |
| #endif |
| } |
| else if (light.width > 0.01 && light.height > 0.01) // area light |
| { |
| // This approach is based on the 1994 Tech Report by James Arvo -- |
| // The Irradiance Jacobian for Partially Occluded Polyhedral Sources |
| // The nice thing about this approach is that it extends to arbitrary geometry (if we choose to support it), |
| // and accounts for distance & geometric attenuation automatically. |
| // Downsides -- only really works for diffuse reflection, does not account properly for an area light that |
| // intersects its receiver, in which case it illuminates as if the light source is two-sided Lambertian emitter. |
| vec3 v0 = light.position.xyz - (light.right.xyz * light.width * 0.5) - (light.up.xyz * light.height * 0.5); |
| vec3 v1 = light.position.xyz - (light.right.xyz * light.width * 0.5) + (light.up.xyz * light.height * 0.5); |
| vec3 v2 = light.position.xyz + (light.right.xyz * light.width * 0.5) + (light.up.xyz * light.height * 0.5); |
| vec3 v3 = light.position.xyz + (light.right.xyz * light.width * 0.5) - (light.up.xyz * light.height * 0.5); |
| |
| v0 = normalize( v0 - pos ); v1 = normalize( v1 - pos ); v2 = normalize( v2 - pos ); v3 = normalize( v3 - pos ); |
| |
| float a01 = acos( clamp( dot(v0, v1), -1.0, 1.0 ) ); |
| float a12 = acos( clamp( dot(v1, v2), -1.0, 1.0 ) ); |
| float a23 = acos( clamp( dot(v2, v3), -1.0, 1.0 ) ); |
| float a30 = acos( clamp( dot(v3, v0), -1.0, 1.0 ) ); |
| |
| wi = vec3( 0.0 ); |
| wi -= normalize(cross( v0, v1 )) * a01; |
| wi -= normalize(cross( v1, v2 )) * a12; |
| wi -= normalize(cross( v2, v3 )) * a23; |
| wi -= normalize(cross( v3, v0 )) * a30; |
| |
| att = length(wi) * 0.15915494309; // solid angle / 2*pi |
| wi = normalize(wi); |
| att *= clamp( dot( pos - light.position.xyz, light.direction.xyz ), 0.0, 1.0 ); |
| #if QSSG_ENABLE_SSM |
| if ( light.shadowIdx >= 0 ) |
| att *= sampleCubemap( shadowCubes[light.shadowIdx], light.shadowControls, light.shadowView, light.position.xyz, pos, vec2(1.0, light.shadowControls.z) ); |
| #endif |
| } |
| else // point or spot light |
| { |
| wi = light.position.xyz - pos; |
| float dist = length(wi); |
| wi = wi / dist; // == normalize(wi); |
| att = 1.0 / (light.constantAttenuation + (light.linearAttenuation + light.quadraticAttenuation * dist) * dist); |
| |
| if (light.coneAngle < 180.0) // spot light |
| { |
| float spotAngle = max(0.0, dot(wi, -light.direction.xyz)); |
| att *= (spotAngle > light.coneAngle) ? smoothstep(light.coneAngle, light.innerConeAngle, spotAngle) : 0.0; |
| } |
| |
| #if QSSG_ENABLE_SSM |
| if ( light.shadowIdx >= 0 ) |
| att *= sampleCubemap( shadowCubes[light.shadowIdx], light.shadowControls, light.shadowView, light.position.xyz, pos, vec2(1.0, light.shadowControls.z) ); |
| #endif |
| } |
| float shadow = customMaterialShadow( -light.direction.xyz, pos ); |
| opAmbient = att * light.ambient.xyz; |
| opDiffuse = att * shadow * light.diffuse.xyz; |
| opSpecular = att * shadow * light.specular.xyz; |
| } |
| |
| #include "sampleArea.glsllib" |
| |
| #endif |