Torque3D/Templates/BaseGame/game/data/shaders/common/lighting.hlsl
Areloch 1ed8b05169 Initial implementation of the new Base Game Template and some starting modules.
This makes some tweaks to the engine to support this, specifically, it tweaks the hardcoded shaderpaths to defer to a pref variable, so none of the shader paths are hardcoded.

Also tweaks how post effects read in texture files, removing a bizzare filepath interpretation choice, where if the file path didn't start with "/" it forcefully appended the script's file path. This made it impossible to have images not in the same dir as the script file defining the post effect.

This was changed and the existing template's post effects tweaked for now to just add "./" to those few paths impacted, as well as the perf vars to support the non-hardcoded shader paths in the engine.
2017-02-24 02:40:56 -06:00

249 lines
8.3 KiB
HLSL

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "./torque.hlsl"
#ifndef TORQUE_SHADERGEN
// These are the uniforms used by most lighting shaders.
uniform float4 inLightPos[3];
uniform float4 inLightInvRadiusSq;
uniform float4 inLightColor[4];
#ifndef TORQUE_BL_NOSPOTLIGHT
uniform float4 inLightSpotDir[3];
uniform float4 inLightSpotAngle;
uniform float4 inLightSpotFalloff;
#endif
uniform float4 ambient;
#define ambientCameraFactor 0.3
uniform float specularPower;
uniform float4 specularColor;
#endif // !TORQUE_SHADERGEN
void compute4Lights( float3 wsView,
float3 wsPosition,
float3 wsNormal,
float4 shadowMask,
#ifdef TORQUE_SHADERGEN
float4 inLightPos[3],
float4 inLightInvRadiusSq,
float4 inLightColor[4],
float4 inLightSpotDir[3],
float4 inLightSpotAngle,
float4 inLightSpotFalloff,
float specularPower,
float4 specularColor,
#endif // TORQUE_SHADERGEN
out float4 outDiffuse,
out float4 outSpecular )
{
// NOTE: The light positions and spotlight directions
// are stored in SoA order, so inLightPos[0] is the
// x coord for all 4 lights... inLightPos[1] is y... etc.
//
// This is the key to fully utilizing the vector units and
// saving a huge amount of instructions.
//
// For example this change saved more than 10 instructions
// over a simple for loop for each light.
int i;
float4 lightVectors[3];
for ( i = 0; i < 3; i++ )
lightVectors[i] = wsPosition[i] - inLightPos[i];
float4 squareDists = 0;
for ( i = 0; i < 3; i++ )
squareDists += lightVectors[i] * lightVectors[i];
// Accumulate the dot product between the light
// vector and the normal.
//
// The normal is negated because it faces away from
// the surface and the light faces towards the
// surface... this keeps us from needing to flip
// the light vector direction which complicates
// the spot light calculations.
//
// We normalize the result a little later.
//
float4 nDotL = 0;
for ( i = 0; i < 3; i++ )
nDotL += lightVectors[i] * -wsNormal[i];
float4 rDotL = 0;
#ifndef TORQUE_BL_NOSPECULAR
// We're using the Phong specular reflection model
// here where traditionally Torque has used Blinn-Phong
// which has proven to be more accurate to real materials.
//
// We do so because its cheaper as do not need to
// calculate the half angle for all 4 lights.
//
// Advanced Lighting still uses Blinn-Phong, but the
// specular reconstruction it does looks fairly similar
// to this.
//
float3 R = reflect( wsView, -wsNormal );
for ( i = 0; i < 3; i++ )
rDotL += lightVectors[i] * R[i];
#endif
// Normalize the dots.
//
// Notice we're using the half type here to get a
// much faster sqrt via the rsq_pp instruction at
// the loss of some precision.
//
// Unless we have some extremely large point lights
// i don't believe the precision loss will matter.
//
half4 correction = (half4)rsqrt( squareDists );
nDotL = saturate( nDotL * correction );
rDotL = clamp( rDotL * correction, 0.00001, 1.0 );
// First calculate a simple point light linear
// attenuation factor.
//
// If this is a directional light the inverse
// radius should be greater than the distance
// causing the attenuation to have no affect.
//
float4 atten = saturate( 1.0 - ( squareDists * inLightInvRadiusSq ) );
#ifndef TORQUE_BL_NOSPOTLIGHT
// The spotlight attenuation factor. This is really
// fast for what it does... 6 instructions for 4 spots.
float4 spotAtten = 0;
for ( i = 0; i < 3; i++ )
spotAtten += lightVectors[i] * inLightSpotDir[i];
float4 cosAngle = ( spotAtten * correction ) - inLightSpotAngle;
atten *= saturate( cosAngle * inLightSpotFalloff );
#endif
// Finally apply the shadow masking on the attenuation.
atten *= shadowMask;
// Get the final light intensity.
float4 intensity = nDotL * atten;
// Combine the light colors for output.
outDiffuse = 0;
for ( i = 0; i < 4; i++ )
outDiffuse += intensity[i] * inLightColor[i];
// Output the specular power.
float4 specularIntensity = pow( rDotL, specularPower.xxxx ) * atten;
// Apply the per-light specular attenuation.
float4 specular = float4(0,0,0,1);
for ( i = 0; i < 4; i++ )
specular += float4( inLightColor[i].rgb * inLightColor[i].a * specularIntensity[i], 1 );
// Add the final specular intensity values together
// using a single dot product operation then get the
// final specular lighting color.
outSpecular = specularColor * specular;
}
// This value is used in AL as a constant power to raise specular values
// to, before storing them into the light info buffer. The per-material
// specular value is then computer by using the integer identity of
// exponentiation:
//
// (a^m)^n = a^(m*n)
//
// or
//
// (specular^constSpecular)^(matSpecular/constSpecular) = specular^(matSpecular*constSpecular)
//
#define AL_ConstantSpecularPower 12.0f
/// The specular calculation used in Advanced Lighting.
///
/// @param toLight Normalized vector representing direction from the pixel
/// being lit, to the light source, in world space.
///
/// @param normal Normalized surface normal.
///
/// @param toEye The normalized vector representing direction from the pixel
/// being lit to the camera.
///
float AL_CalcSpecular( float3 toLight, float3 normal, float3 toEye )
{
// (R.V)^c
float specVal = dot( normalize( -reflect( toLight, normal ) ), toEye );
// Return the specular factor.
return pow( max( specVal, 0.00001f ), AL_ConstantSpecularPower );
}
/// The output for Deferred Lighting
///
/// @param toLight Normalized vector representing direction from the pixel
/// being lit, to the light source, in world space.
///
/// @param normal Normalized surface normal.
///
/// @param toEye The normalized vector representing direction from the pixel
/// being lit to the camera.
///
float4 AL_DeferredOutput(
float3 lightColor,
float3 diffuseColor,
float4 matInfo,
float4 ambient,
float specular,
float shadowAttenuation)
{
float3 specularColor = float3(specular, specular, specular);
bool metalness = getFlag(matInfo.r, 3);
if ( metalness )
{
specularColor = 0.04 * (1 - specular) + diffuseColor * specular;
}
//specular = color * map * spec^gloss
float specularOut = (specularColor * matInfo.b * min(pow(abs(specular), max(( matInfo.a/ AL_ConstantSpecularPower),1.0f)),matInfo.a)).r;
lightColor *= shadowAttenuation;
lightColor += ambient.rgb;
return float4(lightColor.rgb, specularOut);
}