文章主要是分享一些优秀开源的人物的gpu代码、主流的3D引擎,动画的蒙皮的驱动都是很类似的
vs
#version 150
#define COMPILEVS
#define MAXBONES 128
#define DIRLIGHT
#define NOUV
#define PERPIXEL
#define SHADOW
#define SKINNED
#define GL3
// Use of constant buffers on OpenGL 3 commented out for now as it seems to be slower in practice
//#define USE_CBUFFERS
#if !defined(GL3) || !defined(USE_CBUFFERS)
// OpenGL 2 uniforms (no constant buffers)
#ifdef COMPILEVS
// Vertex shader uniforms
uniform vec3 cAmbientStartColor;
uniform vec3 cAmbientEndColor;
uniform mat3 cBillboardRot;
uniform vec3 cCameraPos;
uniform float cNearClip;
uniform float cFarClip;
uniform vec4 cDepthMode;
uniform vec3 cFrustumSize;
uniform float cDeltaTime;
uniform float cElapsedTime;
uniform vec4 cGBufferOffsets;
uniform vec4 cLightPos;
uniform vec3 cLightDir;
uniform vec4 cNormalOffsetScale;
uniform mat4 cModel;
uniform mat4 cView;
uniform mat4 cViewInv;
uniform mat4 cViewProj;
uniform vec4 cUOffset;
uniform vec4 cVOffset;
uniform mat4 cZone;
#if !defined(GL_ES) || defined(WEBGL)
uniform mat4 cLightMatrices[4];
#else
uniform highp mat4 cLightMatrices[2];
#endif
#ifdef SKINNED
uniform vec4 cSkinMatrices[MAXBONES*3];
#endif
#ifdef NUMVERTEXLIGHTS
uniform vec4 cVertexLights[4*3];
#endif
#ifdef GL3
uniform vec4 cClipPlane;
#endif
#endif
#ifdef COMPILEPS
// Fragment shader uniforms
#ifdef GL_ES
precision mediump float;
#endif
uniform vec4 cAmbientColor;
uniform vec3 cCameraPosPS;
uniform float cDeltaTimePS;
uniform vec4 cDepthReconstruct;
uniform float cElapsedTimePS;
uniform vec4 cFogParams;
uniform vec3 cFogColor;
uniform vec2 cGBufferInvSize;
uniform vec4 cLightColor;
uniform vec4 cLightPosPS;
uniform vec3 cLightDirPS;
uniform vec4 cNormalOffsetScalePS;
uniform vec4 cMatDiffColor;
uniform vec3 cMatEmissiveColor;
uniform vec3 cMatEnvMapColor;
uniform vec4 cMatSpecColor;
#ifdef PBR
uniform float cRoughness;
uniform float cMetallic;
uniform float cLightRad;
uniform float cLightLength;
#endif
uniform vec3 cZoneMin;
uniform vec3 cZoneMax;
uniform float cNearClipPS;
uniform float cFarClipPS;
uniform vec4 cShadowCubeAdjust;
uniform vec4 cShadowDepthFade;
uniform vec2 cShadowIntensity;
uniform vec2 cShadowMapInvSize;
uniform vec4 cShadowSplits;
uniform mat4 cLightMatricesPS[4];
#ifdef VSM_SHADOW
uniform vec2 cVSMShadowParams;
#endif
#endif
#else
// OpenGL 3 uniforms (using constant buffers)
#ifdef COMPILEVS
uniform FrameVS
{
float cDeltaTime;
float cElapsedTime;
};
uniform CameraVS
{
vec3 cCameraPos;
float cNearClip;
float cFarClip;
vec4 cDepthMode;
vec3 cFrustumSize;
vec4 cGBufferOffsets;
mat4 cView;
mat4 cViewInv;
mat4 cViewProj;
vec4 cClipPlane;
};
uniform ZoneVS
{
vec3 cAmbientStartColor;
vec3 cAmbientEndColor;
mat4 cZone;
};
uniform LightVS
{
vec4 cLightPos;
vec3 cLightDir;
vec4 cNormalOffsetScale;
#ifdef NUMVERTEXLIGHTS
vec4 cVertexLights[4 * 3];
#else
mat4 cLightMatrices[4];
#endif
};
#ifndef CUSTOM_MATERIAL_CBUFFER
uniform MaterialVS
{
vec4 cUOffset;
vec4 cVOffset;
};
#endif
uniform ObjectVS
{
mat4 cModel;
#ifdef BILLBOARD
mat3 cBillboardRot;
#endif
#ifdef SKINNED
uniform vec4 cSkinMatrices[MAXBONES*3];
#endif
};
#endif
#ifdef COMPILEPS
// Pixel shader uniforms
uniform FramePS
{
float cDeltaTimePS;
float cElapsedTimePS;
};
uniform CameraPS
{
vec3 cCameraPosPS;
vec4 cDepthReconstruct;
vec2 cGBufferInvSize;
float cNearClipPS;
float cFarClipPS;
};
uniform ZonePS
{
vec4 cAmbientColor;
vec4 cFogParams;
vec3 cFogColor;
vec3 cZoneMin;
vec3 cZoneMax;
};
uniform LightPS
{
vec4 cLightColor;
vec4 cLightPosPS;
vec3 cLightDirPS;
vec4 cNormalOffsetScalePS;
vec4 cShadowCubeAdjust;
vec4 cShadowDepthFade;
vec2 cShadowIntensity;
vec2 cShadowMapInvSize;
vec4 cShadowSplits;
mat4 cLightMatricesPS[4];
#ifdef VSM_SHADOW
vec2 cVSMShadowParams;
#endif
#ifdef PBR
float cLightRad;
float cLightLength;
#endif
};
#ifndef CUSTOM_MATERIAL_CBUFFER
uniform MaterialPS
{
vec4 cMatDiffColor;
vec3 cMatEmissiveColor;
vec3 cMatEnvMapColor;
vec4 cMatSpecColor;
#ifdef PBR
float cRoughness;
float cMetallic;
#endif
};
#endif
#endif
#endif
#ifdef COMPILEPS
uniform sampler2D sDiffMap;
uniform samplerCube sDiffCubeMap;
uniform sampler2D sNormalMap;
uniform sampler2D sSpecMap;
uniform sampler2D sEmissiveMap;
uniform sampler2D sEnvMap;
uniform samplerCube sEnvCubeMap;
uniform sampler2D sLightRampMap;
uniform sampler2D sLightSpotMap;
uniform samplerCube sLightCubeMap;
#ifndef GL_ES
uniform sampler3D sVolumeMap;
uniform sampler2D sAlbedoBuffer;
uniform sampler2D sNormalBuffer;
uniform sampler2D sDepthBuffer;
uniform sampler2D sLightBuffer;
#ifdef VSM_SHADOW
uniform sampler2D sShadowMap;
#else
uniform sampler2DShadow sShadowMap;
#endif
uniform samplerCube sFaceSelectCubeMap;
uniform samplerCube sIndirectionCubeMap;
uniform samplerCube sZoneCubeMap;
uniform sampler3D sZoneVolumeMap;
#else
uniform highp sampler2D sShadowMap;
#endif
#ifdef GL3
#define texture2D texture
#define texture2DProj textureProj
#define texture3D texture
#define textureCube texture
#define texture2DLod textureLod
#define texture2DLodOffset textureLodOffset
#endif
vec3 DecodeNormal(vec4 normalInput)
{
#ifdef PACKEDNORMAL
vec3 normal;
normal.xy = normalInput.ag * 2.0 - 1.0;
normal.z = sqrt(max(1.0 - dot(normal.xy, normal.xy), 0.0));
return normal;
#else
return normalize(normalInput.rgb * 2.0 - 1.0);
#endif
}
vec3 EncodeDepth(float depth)
{
#ifndef GL3
vec3 ret;
depth *= 255.0;
ret.x = floor(depth);
depth = (depth - ret.x) * 255.0;
ret.y = floor(depth);
ret.z = (depth - ret.y);
ret.xy *= 1.0 / 255.0;
return ret;
#else
// OpenGL 3 can use different MRT formats, so no need for encoding
return vec3(depth, 0.0, 0.0);
#endif
}
float DecodeDepth(vec3 depth)
{
#ifndef GL3
const vec3 dotValues = vec3(1.0, 1.0 / 255.0, 1.0 / (255.0 * 255.0));
return dot(depth, dotValues);
#else
// OpenGL 3 can use different MRT formats, so no need for encoding
return depth.r;
#endif
}
float ReconstructDepth(float hwDepth)
{
return dot(vec2(hwDepth, cDepthReconstruct.y / (hwDepth - cDepthReconstruct.x)), cDepthReconstruct.zw);
}
#endif
#ifdef COMPILEVS
// Silence WARNING: Shader ... does not use the define NOUV
#ifdef NOUV
#endif
// Silence GLSL 150 deprecation warnings
#ifdef GL3
#define attribute in
#define varying out
#endif
attribute vec4 iPos;
attribute vec3 iNormal;
attribute vec4 iColor;
attribute vec2 iTexCoord;
attribute vec2 iTexCoord1;
attribute vec4 iTangent;
attribute vec4 iBlendWeights;
attribute vec4 iBlendIndices;
attribute vec3 iCubeTexCoord;
attribute vec4 iCubeTexCoord1;
#ifdef INSTANCED
attribute vec4 iTexCoord4;
attribute vec4 iTexCoord5;
attribute vec4 iTexCoord6;
#endif
attribute float iObjectIndex;
#ifdef SKINNED
mat4 GetSkinMatrix(vec4 blendWeights, vec4 blendIndices)
{
ivec4 idx = ivec4(blendIndices) * 3;
const vec4 lastColumn = vec4(0.0, 0.0, 0.0, 1.0);
return mat4(cSkinMatrices[idx.x], cSkinMatrices[idx.x + 1], cSkinMatrices[idx.x + 2], lastColumn) * blendWeights.x +
mat4(cSkinMatrices[idx.y], cSkinMatrices[idx.y + 1], cSkinMatrices[idx.y + 2], lastColumn) * blendWeights.y +
mat4(cSkinMatrices[idx.z], cSkinMatrices[idx.z + 1], cSkinMatrices[idx.z + 2], lastColumn) * blendWeights.z +
mat4(cSkinMatrices[idx.w], cSkinMatrices[idx.w + 1], cSkinMatrices[idx.w + 2], lastColumn) * blendWeights.w;
}
#endif
#ifdef INSTANCED
mat4 GetInstanceMatrix()
{
const vec4 lastColumn = vec4(0.0, 0.0, 0.0, 1.0);
return mat4(iTexCoord4, iTexCoord5, iTexCoord6, lastColumn);
}
#endif
mat3 GetNormalMatrix(mat4 modelMatrix)
{
return mat3(modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz);
}
vec2 GetTexCoord(vec2 texCoord)
{
return vec2(dot(texCoord, cUOffset.xy) + cUOffset.w, dot(texCoord, cVOffset.xy) + cVOffset.w);
}
vec4 GetClipPos(vec3 worldPos)
{
vec4 ret = vec4(worldPos, 1.0) * cViewProj;
// While getting the clip coordinate, also automatically set gl_ClipVertex for user clip planes
#if !defined(GL_ES) && !defined(GL3)
gl_ClipVertex = ret;
#elif defined(GL3)
gl_ClipDistance[0] = dot(cClipPlane, ret);
#endif
return ret;
}
float GetZonePos(vec3 worldPos)
{
return clamp((vec4(worldPos, 1.0) * cZone).z, 0.0, 1.0);
}
float GetDepth(vec4 clipPos)
{
return dot(clipPos.zw, cDepthMode.zw);
}
#ifdef BILLBOARD
vec3 GetBillboardPos(vec4 iPos, vec2 iSize, mat4 modelMatrix)
{
return (iPos * modelMatrix).xyz + vec3(iSize.x, iSize.y, 0.0) * cBillboardRot;
}
vec3 GetBillboardNormal()
{
return vec3(-cBillboardRot[0][2], -cBillboardRot[1][2], -cBillboardRot[2][2]);
}
#endif
#ifdef DIRBILLBOARD
mat3 GetFaceCameraRotation(vec3 position, vec3 direction)
{
vec3 cameraDir = normalize(position - cCameraPos);
vec3 front = normalize(direction);
vec3 right = normalize(cross(front, cameraDir));
vec3 up = normalize(cross(front, right));
return mat3(
right.x, up.x, front.x,
right.y, up.y, front.y,
right.z, up.z, front.z
);
}
vec3 GetBillboardPos(vec4 iPos, vec3 iDirection, mat4 modelMatrix)
{
vec3 worldPos = (iPos * modelMatrix).xyz;
return worldPos + vec3(iTexCoord1.x, 0.0, iTexCoord1.y) * GetFaceCameraRotation(worldPos, iDirection);
}
vec3 GetBillboardNormal(vec4 iPos, vec3 iDirection, mat4 modelMatrix)
{
vec3 worldPos = (iPos * modelMatrix).xyz;
return vec3(0.0, 1.0, 0.0) * GetFaceCameraRotation(worldPos, iDirection);
}
#endif
#ifdef TRAILFACECAM
vec3 GetTrailPos(vec4 iPos, vec3 iFront, float iScale, mat4 modelMatrix)
{
vec3 up = normalize(cCameraPos - iPos.xyz);
vec3 right = normalize(cross(iFront, up));
return (vec4((iPos.xyz + right * iScale), 1.0) * modelMatrix).xyz;
}
vec3 GetTrailNormal(vec4 iPos)
{
return normalize(cCameraPos - iPos.xyz);
}
#endif
#ifdef TRAILBONE
vec3 GetTrailPos(vec4 iPos, vec3 iParentPos, float iScale, mat4 modelMatrix)
{
vec3 right = iParentPos - iPos.xyz;
return (vec4((iPos.xyz + right * iScale), 1.0) * modelMatrix).xyz;
}
vec3 GetTrailNormal(vec4 iPos, vec3 iParentPos, vec3 iForward)
{
vec3 left = normalize(iPos.xyz - iParentPos);
vec3 up = normalize(cross(normalize(iForward), left));
return up;
}
#endif
#if defined(SKINNED)
#define iModelMatrix GetSkinMatrix(iBlendWeights, iBlendIndices)
#elif defined(INSTANCED)
#define iModelMatrix GetInstanceMatrix()
#else
#define iModelMatrix cModel
#endif
vec3 GetWorldPos(mat4 modelMatrix)
{
#if defined(BILLBOARD)
return GetBillboardPos(iPos, iTexCoord1, modelMatrix);
#elif defined(DIRBILLBOARD)
return GetBillboardPos(iPos, iNormal, modelMatrix);
#elif defined(TRAILFACECAM)
return GetTrailPos(iPos, iTangent.xyz, iTangent.w, modelMatrix);
#elif defined(TRAILBONE)
return GetTrailPos(iPos, iTangent.xyz, iTangent.w, modelMatrix);
#else
return (iPos * modelMatrix).xyz;
#endif
}
vec3 GetWorldNormal(mat4 modelMatrix)
{
#if defined(BILLBOARD)
return GetBillboardNormal();
#elif defined(DIRBILLBOARD)
return GetBillboardNormal(iPos, iNormal, modelMatrix);
#elif defined(TRAILFACECAM)
return GetTrailNormal(iPos);
#elif defined(TRAILBONE)
return GetTrailNormal(iPos, iTangent.xyz, iNormal);
#else
return normalize(iNormal * GetNormalMatrix(modelMatrix));
#endif
}
vec4 GetWorldTangent(mat4 modelMatrix)
{
#if defined(BILLBOARD)
return vec4(normalize(vec3(1.0, 0.0, 0.0) * cBillboardRot), 1.0);
#elif defined(DIRBILLBOARD)
return vec4(normalize(vec3(1.0, 0.0, 0.0) * GetNormalMatrix(modelMatrix)), 1.0);
#else
return vec4(normalize(iTangent.xyz * GetNormalMatrix(modelMatrix)), iTangent.w);
#endif
}
#else
// Silence GLSL 150 deprecation warnings
#ifdef GL3
#define varying in
#ifndef MRT_COUNT
#if defined(DEFERRED)
#define MRT_COUNT 4
#elif defined(PREPASS)
#define MRT_COUNT 2
#else
#define MRT_COUNT 1
#endif
#endif
out vec4 fragData[MRT_COUNT];
#define gl_FragColor fragData[0]
#define gl_FragData fragData
#endif
#endif
#ifdef COMPILEVS
mat3 GetCameraRot()
{
return mat3(cViewInv[0][0], cViewInv[0][1], cViewInv[0][2],
cViewInv[1][0], cViewInv[1][1], cViewInv[1][2],
cViewInv[2][0], cViewInv[2][1], cViewInv[2][2]);
}
vec4 GetScreenPos(vec4 clipPos)
{
return vec4(
clipPos.x * cGBufferOffsets.z + cGBufferOffsets.x * clipPos.w,
clipPos.y * cGBufferOffsets.w + cGBufferOffsets.y * clipPos.w,
0.0,
clipPos.w);
}
vec2 GetScreenPosPreDiv(vec4 clipPos)
{
return vec2(
clipPos.x / clipPos.w * cGBufferOffsets.z + cGBufferOffsets.x,
clipPos.y / clipPos.w * cGBufferOffsets.w + cGBufferOffsets.y);
}
vec2 GetQuadTexCoord(vec4 clipPos)
{
return vec2(
clipPos.x / clipPos.w * 0.5 + 0.5,
clipPos.y / clipPos.w * 0.5 + 0.5);
}
vec2 GetQuadTexCoordNoFlip(vec3 worldPos)
{
return vec2(
worldPos.x * 0.5 + 0.5,
-worldPos.y * 0.5 + 0.5);
}
vec3 GetFarRay(vec4 clipPos)
{
vec3 viewRay = vec3(
clipPos.x / clipPos.w * cFrustumSize.x,
clipPos.y / clipPos.w * cFrustumSize.y,
cFrustumSize.z);
return viewRay * GetCameraRot();
}
vec3 GetNearRay(vec4 clipPos)
{
vec3 viewRay = vec3(
clipPos.x / clipPos.w * cFrustumSize.x,
clipPos.y / clipPos.w * cFrustumSize.y,
0.0);
return (viewRay * GetCameraRot()) * cDepthMode.x;
}
#endif
#ifdef COMPILEVS
vec3 GetAmbient(float zonePos)
{
return cAmbientStartColor + zonePos * cAmbientEndColor;
}
#ifdef NUMVERTEXLIGHTS
float GetVertexLight(int index, vec3 worldPos, vec3 normal)
{
vec3 lightDir = cVertexLights[index * 3 + 1].xyz;
vec3 lightPos = cVertexLights[index * 3 + 2].xyz;
float invRange = cVertexLights[index * 3].w;
float cutoff = cVertexLights[index * 3 + 1].w;
float invCutoff = cVertexLights[index * 3 + 2].w;
// Directional light
if (invRange == 0.0)
{
#ifdef TRANSLUCENT
float NdotL = abs(dot(normal, lightDir));
#else
float NdotL = max(dot(normal, lightDir), 0.0);
#endif
return NdotL;
}
// Point/spot light
else
{
vec3 lightVec = (lightPos - worldPos) * invRange;
float lightDist = length(lightVec);
vec3 localDir = lightVec / lightDist;
#ifdef TRANSLUCENT
float NdotL = abs(dot(normal, localDir));
#else
float NdotL = max(dot(normal, localDir), 0.0);
#endif
float atten = clamp(1.0 - lightDist * lightDist, 0.0, 1.0);
float spotEffect = dot(localDir, lightDir);
float spotAtten = clamp((spotEffect - cutoff) * invCutoff, 0.0, 1.0);
return NdotL * atten * spotAtten;
}
}
float GetVertexLightVolumetric(int index, vec3 worldPos)
{
vec3 lightDir = cVertexLights[index * 3 + 1].xyz;
vec3 lightPos = cVertexLights[index * 3 + 2].xyz;
float invRange = cVertexLights[index * 3].w;
float cutoff = cVertexLights[index * 3 + 1].w;
float invCutoff = cVertexLights[index * 3 + 2].w;
// Directional light
if (invRange == 0.0)
return 1.0;
// Point/spot light
else
{
vec3 lightVec = (lightPos - worldPos) * invRange;
float lightDist = length(lightVec);
vec3 localDir = lightVec / lightDist;
float atten = clamp(1.0 - lightDist * lightDist, 0.0, 1.0);
float spotEffect = dot(localDir, lightDir);
float spotAtten = clamp((spotEffect - cutoff) * invCutoff, 0.0, 1.0);
return atten * spotAtten;
}
}
#endif
#ifdef SHADOW
#if defined(DIRLIGHT) && (!defined(GL_ES) || defined(WEBGL))
#define NUMCASCADES 4
#else
#define NUMCASCADES 1
#endif
vec4 GetShadowPos(int index, vec3 normal, vec4 projWorldPos)
{
#ifdef NORMALOFFSET
float normalOffsetScale[4];
normalOffsetScale[0] = cNormalOffsetScale.x;
normalOffsetScale[1] = cNormalOffsetScale.y;
normalOffsetScale[2] = cNormalOffsetScale.z;
normalOffsetScale[3] = cNormalOffsetScale.w;
#ifdef DIRLIGHT
float cosAngle = clamp(1.0 - dot(normal, cLightDir), 0.0, 1.0);
#else
float cosAngle = clamp(1.0 - dot(normal, normalize(cLightPos.xyz - projWorldPos.xyz)), 0.0, 1.0);
#endif
projWorldPos.xyz += cosAngle * normalOffsetScale[index] * normal;
#endif
#if defined(DIRLIGHT)
return projWorldPos * cLightMatrices[index];
#elif defined(SPOTLIGHT)
return projWorldPos * cLightMatrices[1];
#else
return vec4(projWorldPos.xyz - cLightPos.xyz, 1.0);
#endif
}
#endif
#endif
#ifdef COMPILEPS
float GetDiffuse(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
#ifdef DIRLIGHT
lightDir = cLightDirPS;
#ifdef TRANSLUCENT
return abs(dot(normal, lightDir));
#else
return max(dot(normal, lightDir), 0.0);
#endif
#else
vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
float lightDist = length(lightVec);
lightDir = lightVec / lightDist;
#ifdef TRANSLUCENT
return abs(dot(normal, lightDir)) * texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
#else
return max(dot(normal, lightDir), 0.0) * texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
#endif
#endif
}
float GetAtten(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
lightDir = cLightDirPS;
return clamp(dot(normal, lightDir), 0.0, 1.0);
}
float GetAttenPoint(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
float lightDist = length(lightVec);
float falloff = pow(clamp(1.0 - pow(lightDist / 1.0, 4.0), 0.0, 1.0), 2.0) * 3.14159265358979323846 / (4.0 * 3.14159265358979323846)*(pow(lightDist, 2.0) + 1.0);
lightDir = lightVec / lightDist;
return clamp(dot(normal, lightDir), 0.0, 1.0) * falloff;
}
float GetAttenSpot(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
float lightDist = length(lightVec);
float falloff = pow(clamp(1.0 - pow(lightDist / 1.0, 4.0), 0.0, 1.0), 2.0) / (pow(lightDist, 2.0) + 1.0);
lightDir = lightVec / lightDist;
return clamp(dot(normal, lightDir), 0.0, 1.0) * falloff;
}
float GetDiffuseVolumetric(vec3 worldPos)
{
#ifdef DIRLIGHT
return 1.0;
#else
vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
float lightDist = length(lightVec);
return texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
#endif
}
float GetSpecular(vec3 normal, vec3 eyeVec, vec3 lightDir, float specularPower)
{
vec3 halfVec = normalize(normalize(eyeVec) + lightDir);
return pow(max(dot(normal, halfVec), 0.0), specularPower);
}
float GetIntensity(vec3 color)
{
return dot(color, vec3(0.299, 0.587, 0.114));
}
#ifdef SHADOW
#if defined(DIRLIGHT) && (!defined(GL_ES) || defined(WEBGL))
#define NUMCASCADES 4
#else
#define NUMCASCADES 1
#endif
#ifdef VSM_SHADOW
float ReduceLightBleeding(float min, float p_max)
{
return clamp((p_max - min) / (1.0 - min), 0.0, 1.0);
}
float Chebyshev(vec2 Moments, float depth)
{
//One-tailed inequality valid if depth > Moments.x
float p = float(depth <= Moments.x);
//Compute variance.
float Variance = Moments.y - (Moments.x * Moments.x);
float minVariance = cVSMShadowParams.x;
Variance = max(Variance, minVariance);
//Compute probabilistic upper bound.
float d = depth - Moments.x;
float p_max = Variance / (Variance + d*d);
// Prevent light bleeding
p_max = ReduceLightBleeding(cVSMShadowParams.y, p_max);
return max(p, p_max);
}
#endif
#ifndef GL_ES
float GetShadow(vec4 shadowPos)
{
#if defined(SIMPLE_SHADOW)
// Take one sample
#ifndef GL3
float inLight = shadow2DProj(sShadowMap, shadowPos).r;
#else
float inLight = textureProj(sShadowMap, shadowPos);
#endif
return cShadowIntensity.y + cShadowIntensity.x * inLight;
#elif defined(PCF_SHADOW)
// Take four samples and average them
// Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
#ifndef POINTLIGHT
vec2 offsets = cShadowMapInvSize * shadowPos.w;
#else
vec2 offsets = cShadowMapInvSize;
#endif
#ifndef GL3
return cShadowIntensity.y + cShadowIntensity.x * (shadow2DProj(sShadowMap, shadowPos).r +
shadow2DProj(sShadowMap, vec4(shadowPos.x + offsets.x, shadowPos.yzw)).r +
shadow2DProj(sShadowMap, vec4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r +
shadow2DProj(sShadowMap, vec4(shadowPos.xy + offsets.xy, shadowPos.zw)).r);
#else
return cShadowIntensity.y + cShadowIntensity.x * (textureProj(sShadowMap, shadowPos) +
textureProj(sShadowMap, vec4(shadowPos.x + offsets.x, shadowPos.yzw)) +
textureProj(sShadowMap, vec4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)) +
textureProj(sShadowMap, vec4(shadowPos.xy + offsets.xy, shadowPos.zw)));
#endif
#elif defined(VSM_SHADOW)
vec2 samples = texture2D(sShadowMap, shadowPos.xy / shadowPos.w).rg;
return cShadowIntensity.y + cShadowIntensity.x * Chebyshev(samples, shadowPos.z / shadowPos.w);
#endif
}
#else
float GetShadow(highp vec4 shadowPos)
{
#if defined(SIMPLE_SHADOW)
// Take one sample
return cShadowIntensity.y + (texture2DProj(sShadowMap, shadowPos).r * shadowPos.w > shadowPos.z ? cShadowIntensity.x : 0.0);
#elif defined(PCF_SHADOW)
// Take four samples and average them
vec2 offsets = cShadowMapInvSize * shadowPos.w;
vec4 inLight = vec4(
texture2DProj(sShadowMap, shadowPos).r * shadowPos.w > shadowPos.z,
texture2DProj(sShadowMap, vec4(shadowPos.x + offsets.x, shadowPos.yzw)).r * shadowPos.w > shadowPos.z,
texture2DProj(sShadowMap, vec4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r * shadowPos.w > shadowPos.z,
texture2DProj(sShadowMap, vec4(shadowPos.xy + offsets.xy, shadowPos.zw)).r * shadowPos.w > shadowPos.z
);
return cShadowIntensity.y + dot(inLight, vec4(cShadowIntensity.x));
#elif defined(VSM_SHADOW)
vec2 samples = texture2D(sShadowMap, shadowPos.xy / shadowPos.w).rg;
return cShadowIntensity.y + cShadowIntensity.x * Chebyshev(samples, shadowPos.z / shadowPos.w);
#endif
}
#endif
#ifdef POINTLIGHT
float GetPointShadow(vec3 lightVec)
{
vec3 axis = textureCube(sFaceSelectCubeMap, lightVec).rgb;
float depth = abs(dot(lightVec, axis));
// Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
// and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
// case filtering across faces is wrong
const vec3 factor = vec3(1.0 / 256.0);
lightVec += factor * axis * lightVec;
// Read the 2D UV coordinates, adjust according to shadow map size and add face offset
vec4 indirectPos = textureCube(sIndirectionCubeMap, lightVec);
indirectPos.xy *= cShadowCubeAdjust.xy;
indirectPos.xy += vec2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
vec4 shadowPos = vec4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
return GetShadow(shadowPos);
}
#endif
#ifdef DIRLIGHT
float GetDirShadowFade(float inLight, float depth)
{
return min(inLight + max((depth - cShadowDepthFade.z) * cShadowDepthFade.w, 0.0), 1.0);
}
#if !defined(GL_ES) || defined(WEBGL)
float GetDirShadow(const vec4 iShadowPos[NUMCASCADES], float depth)
{
vec4 shadowPos;
if (depth < cShadowSplits.x)
shadowPos = iShadowPos[0];
else if (depth < cShadowSplits.y)
shadowPos = iShadowPos[1];
else if (depth < cShadowSplits.z)
shadowPos = iShadowPos[2];
else
shadowPos = iShadowPos[3];
return GetDirShadowFade(GetShadow(shadowPos), depth);
}
#else
float GetDirShadow(const highp vec4 iShadowPos[NUMCASCADES], float depth)
{
return GetDirShadowFade(GetShadow(iShadowPos[0]), depth);
}
#endif
#ifndef GL_ES
float GetDirShadowDeferred(vec4 projWorldPos, vec3 normal, float depth)
{
vec4 shadowPos;
#ifdef NORMALOFFSET
float cosAngle = clamp(1.0 - dot(normal, cLightDirPS), 0.0, 1.0);
if (depth < cShadowSplits.x)
shadowPos = vec4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.x * normal, 1.0) * cLightMatricesPS[0];
else if (depth < cShadowSplits.y)
shadowPos = vec4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.y * normal, 1.0) * cLightMatricesPS[1];
else if (depth < cShadowSplits.z)
shadowPos = vec4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.z * normal, 1.0) * cLightMatricesPS[2];
else
shadowPos = vec4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.w * normal, 1.0) * cLightMatricesPS[3];
#else
if (depth < cShadowSplits.x)
shadowPos = projWorldPos * cLightMatricesPS[0];
else if (depth < cShadowSplits.y)
shadowPos = projWorldPos * cLightMatricesPS[1];
else if (depth < cShadowSplits.z)
shadowPos = projWorldPos * cLightMatricesPS[2];
else
shadowPos = projWorldPos * cLightMatricesPS[3];
#endif
return GetDirShadowFade(GetShadow(shadowPos), depth);
}
#endif
#endif
#ifndef GL_ES
float GetShadow(const vec4 iShadowPos[NUMCASCADES], float depth)
#else
float GetShadow(const highp vec4 iShadowPos[NUMCASCADES], float depth)
#endif
{
#if defined(DIRLIGHT)
return GetDirShadow(iShadowPos, depth);
#elif defined(SPOTLIGHT)
return GetShadow(iShadowPos[0]);
#else
return GetPointShadow(iShadowPos[0].xyz);
#endif
}
#ifndef GL_ES
float GetShadowDeferred(vec4 projWorldPos, vec3 normal, float depth)
{
#ifdef DIRLIGHT
return GetDirShadowDeferred(projWorldPos, normal, depth);
#else
#ifdef NORMALOFFSET
float cosAngle = clamp(1.0 - dot(normal, normalize(cLightPosPS.xyz - projWorldPos.xyz)), 0.0, 1.0);
projWorldPos.xyz += cosAngle * cNormalOffsetScalePS.x * normal;
#endif
#ifdef SPOTLIGHT
vec4 shadowPos = projWorldPos * cLightMatricesPS[1];
return GetShadow(shadowPos);
#else
vec3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
return GetPointShadow(shadowPos);
#endif
#endif
}
#endif
#endif
#endif
#ifdef COMPILEPS
vec3 GetFog(vec3 color, float fogFactor)
{
return mix(cFogColor, color, fogFactor);
}
vec3 GetLitFog(vec3 color, float fogFactor)
{
return color * fogFactor;
}
float GetFogFactor(float depth)
{
return clamp((cFogParams.x - depth) * cFogParams.y, 0.0, 1.0);
}
float GetHeightFogFactor(float depth, float height)
{
float fogFactor = GetFogFactor(depth);
float heightFogFactor = (height - cFogParams.z) * cFogParams.w;
heightFogFactor = 1.0 - clamp(exp(-(heightFogFactor * heightFogFactor)), 0.0, 1.0);
return min(heightFogFactor, fogFactor);
}
#endif
#ifdef NORMALMAP
varying vec4 vTexCoord;
varying vec4 vTangent;
#else
varying vec2 vTexCoord;
#endif
varying vec3 vNormal;
varying vec4 vWorldPos;
#ifdef VERTEXCOLOR
varying vec4 vColor;
#endif
#ifdef PERPIXEL
#ifdef SHADOW
#ifndef GL_ES
varying vec4 vShadowPos[NUMCASCADES];
#else
varying highp vec4 vShadowPos[NUMCASCADES];
#endif
#endif
#ifdef SPOTLIGHT
varying vec4 vSpotPos;
#endif
#ifdef POINTLIGHT
varying vec3 vCubeMaskVec;
#endif
#else
varying vec3 vVertexLight;
varying vec4 vScreenPos;
#ifdef ENVCUBEMAP
varying vec3 vReflectionVec;
#endif
#if defined(LIGHTMAP) || defined(AO)
varying vec2 vTexCoord2;
#endif
#endif
void main()
{
mat4 modelMatrix = iModelMatrix;
vec3 worldPos = GetWorldPos(modelMatrix);
gl_Position = GetClipPos(worldPos);
vNormal = GetWorldNormal(modelMatrix);
vWorldPos = vec4(worldPos, GetDepth(gl_Position));
#ifdef VERTEXCOLOR
vColor = iColor;
#endif
#ifdef NORMALMAP
vec4 tangent = GetWorldTangent(modelMatrix);
vec3 bitangent = cross(tangent.xyz, vNormal) * tangent.w;
vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
vTangent = vec4(tangent.xyz, bitangent.z);
#else
vTexCoord = GetTexCoord(iTexCoord);
#endif
#ifdef PERPIXEL
// Per-pixel forward lighting
vec4 projWorldPos = vec4(worldPos, 1.0);
#ifdef SHADOW
// Shadow projection: transform from world space to shadow space
for (int i = 0; i < NUMCASCADES; i++)
vShadowPos[i] = GetShadowPos(i, vNormal, projWorldPos);
#endif
#ifdef SPOTLIGHT
// Spotlight projection: transform from world space to projector texture coordinates
vSpotPos = projWorldPos * cLightMatrices[0];
#endif
#ifdef POINTLIGHT
vCubeMaskVec = (worldPos - cLightPos.xyz) * mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz);
#endif
#else
// Ambient & per-vertex lighting
#if defined(LIGHTMAP) || defined(AO)
// If using lightmap, disregard zone ambient light
// If using AO, calculate ambient in the PS
vVertexLight = vec3(0.0, 0.0, 0.0);
vTexCoord2 = iTexCoord1;
#else
vVertexLight = GetAmbient(GetZonePos(worldPos));
#endif
#ifdef NUMVERTEXLIGHTS
for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights[i * 3].rgb;
#endif
vScreenPos = GetScreenPos(gl_Position);
#ifdef ENVCUBEMAP
vReflectionVec = worldPos - cCameraPos;
#endif
#endif
}
/*void PS()
{
// Get material diffuse albedo
#ifdef DIFFMAP
vec4 diffInput = texture2D(sDiffMap, vTexCoord.xy);
#ifdef ALPHAMASK
if (diffInput.a < 0.5)
discard;
#endif
vec4 diffColor = cMatDiffColor * diffInput;
#else
vec4 diffColor = cMatDiffColor;
#endif
#ifdef VERTEXCOLOR
diffColor *= vColor;
#endif
// Get material specular albedo
#ifdef SPECMAP
vec3 specColor = cMatSpecColor.rgb * texture2D(sSpecMap, vTexCoord.xy).rgb;
#else
vec3 specColor = cMatSpecColor.rgb;
#endif
// Get normal
#ifdef NORMALMAP
mat3 tbn = mat3(vTangent.xyz, vec3(vTexCoord.zw, vTangent.w), vNormal);
vec3 normal = normalize(tbn * DecodeNormal(texture2D(sNormalMap, vTexCoord.xy)));
#else
vec3 normal = normalize(vNormal);
#endif
// Get fog factor
#ifdef HEIGHTFOG
float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
#else
float fogFactor = GetFogFactor(vWorldPos.w);
#endif
#if defined(PERPIXEL)
// Per-pixel forward lighting
vec3 lightColor;
vec3 lightDir;
vec3 finalColor;
float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir);
#ifdef SHADOW
diff *= GetShadow(vShadowPos, vWorldPos.w);
#endif
#if defined(SPOTLIGHT)
lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
#elif defined(CUBEMASK)
lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb;
#else
lightColor = cLightColor.rgb;
#endif
#ifdef SPECULAR
float spec = GetSpecular(normal, cCameraPosPS - vWorldPos.xyz, lightDir, cMatSpecColor.a);
finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);
#else
finalColor = diff * lightColor * diffColor.rgb;
#endif
#ifdef AMBIENT
finalColor += cAmbientColor.rgb * diffColor.rgb;
finalColor += cMatEmissiveColor;
gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
#else
gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a);
#endif
#elif defined(PREPASS)
// Fill light pre-pass G-Buffer
float specPower = cMatSpecColor.a / 255.0;
gl_FragData[0] = vec4(normal * 0.5 + 0.5, specPower);
gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);
#elif defined(DEFERRED)
// Fill deferred G-buffer
float specIntensity = specColor.g;
float specPower = cMatSpecColor.a / 255.0;
vec3 finalColor = vVertexLight * diffColor.rgb;
#ifdef AO
// If using AO, the vertex light ambient is black, calculate occluded ambient here
finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * cAmbientColor.rgb * diffColor.rgb;
#endif
#ifdef ENVCUBEMAP
finalColor += cMatEnvMapColor * textureCube(sEnvCubeMap, reflect(vReflectionVec, normal)).rgb;
#endif
#ifdef LIGHTMAP
finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * diffColor.rgb;
#endif
#ifdef EMISSIVEMAP
finalColor += cMatEmissiveColor * texture2D(sEmissiveMap, vTexCoord.xy).rgb;
#else
finalColor += cMatEmissiveColor;
#endif
gl_FragData[0] = vec4(GetFog(finalColor, fogFactor), 1.0);
gl_FragData[1] = fogFactor * vec4(diffColor.rgb, specIntensity);
gl_FragData[2] = vec4(normal * 0.5 + 0.5, specPower);
gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);
#else
// Ambient & per-vertex lighting
vec3 finalColor = vVertexLight * diffColor.rgb;
#ifdef AO
// If using AO, the vertex light ambient is black, calculate occluded ambient here
finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * cAmbientColor.rgb * diffColor.rgb;
#endif
#ifdef MATERIAL
// Add light pre-pass accumulation result
// Lights are accumulated at half intensity. Bring back to full intensity now
vec4 lightInput = 2.0 * texture2DProj(sLightBuffer, vScreenPos);
vec3 lightSpecColor = lightInput.a * lightInput.rgb / max(GetIntensity(lightInput.rgb), 0.001);
finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;
#endif
#ifdef ENVCUBEMAP
finalColor += cMatEnvMapColor * textureCube(sEnvCubeMap, reflect(vReflectionVec, normal)).rgb;
#endif
#ifdef LIGHTMAP
finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * diffColor.rgb;
#endif
#ifdef EMISSIVEMAP
finalColor += cMatEmissiveColor * texture2D(sEmissiveMap, vTexCoord.xy).rgb;
#else
finalColor += cMatEmissiveColor;
#endif
gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
#endif
}*/
ps
#version 150
#define COMPILEPS
#define MAXBONES 128
#define AMBIENT
#define DIRLIGHT
#define PCF_SHADOW
#define PERPIXEL
#define SHADOW
#define GL3
// Use of constant buffers on OpenGL 3 commented out for now as it seems to be slower in practice
//#define USE_CBUFFERS
#if !defined(GL3) || !defined(USE_CBUFFERS)
// OpenGL 2 uniforms (no constant buffers)
#ifdef COMPILEVS
// Vertex shader uniforms
uniform vec3 cAmbientStartColor;
uniform vec3 cAmbientEndColor;
uniform mat3 cBillboardRot;
uniform vec3 cCameraPos;
uniform float cNearClip;
uniform float cFarClip;
uniform vec4 cDepthMode;
uniform vec3 cFrustumSize;
uniform float cDeltaTime;
uniform float cElapsedTime;
uniform vec4 cGBufferOffsets;
uniform vec4 cLightPos;
uniform vec3 cLightDir;
uniform vec4 cNormalOffsetScale;
uniform mat4 cModel;
uniform mat4 cView;
uniform mat4 cViewInv;
uniform mat4 cViewProj;
uniform vec4 cUOffset;
uniform vec4 cVOffset;
uniform mat4 cZone;
#if !defined(GL_ES) || defined(WEBGL)
uniform mat4 cLightMatrices[4];
#else
uniform highp mat4 cLightMatrices[2];
#endif
#ifdef SKINNED
uniform vec4 cSkinMatrices[MAXBONES*3];
#endif
#ifdef NUMVERTEXLIGHTS
uniform vec4 cVertexLights[4*3];
#endif
#ifdef GL3
uniform vec4 cClipPlane;
#endif
#endif
#ifdef COMPILEPS
// Fragment shader uniforms
#ifdef GL_ES
precision mediump float;
#endif
uniform vec4 cAmbientColor;
uniform vec3 cCameraPosPS;
uniform float cDeltaTimePS;
uniform vec4 cDepthReconstruct;
uniform float cElapsedTimePS;
uniform vec4 cFogParams;
uniform vec3 cFogColor;
uniform vec2 cGBufferInvSize;
uniform vec4 cLightColor;
uniform vec4 cLightPosPS;
uniform vec3 cLightDirPS;
uniform vec4 cNormalOffsetScalePS;
uniform vec4 cMatDiffColor;
uniform vec3 cMatEmissiveColor;
uniform vec3 cMatEnvMapColor;
uniform vec4 cMatSpecColor;
#ifdef PBR
uniform float cRoughness;
uniform float cMetallic;
uniform float cLightRad;
uniform float cLightLength;
#endif
uniform vec3 cZoneMin;
uniform vec3 cZoneMax;
uniform float cNearClipPS;
uniform float cFarClipPS;
uniform vec4 cShadowCubeAdjust;
uniform vec4 cShadowDepthFade;
uniform vec2 cShadowIntensity;
uniform vec2 cShadowMapInvSize;
uniform vec4 cShadowSplits;
uniform mat4 cLightMatricesPS[4];
#ifdef VSM_SHADOW
uniform vec2 cVSMShadowParams;
#endif
#endif
#else
// OpenGL 3 uniforms (using constant buffers)
#ifdef COMPILEVS
uniform FrameVS
{
float cDeltaTime;
float cElapsedTime;
};
uniform CameraVS
{
vec3 cCameraPos;
float cNearClip;
float cFarClip;
vec4 cDepthMode;
vec3 cFrustumSize;
vec4 cGBufferOffsets;
mat4 cView;
mat4 cViewInv;
mat4 cViewProj;
vec4 cClipPlane;
};
uniform ZoneVS
{
vec3 cAmbientStartColor;
vec3 cAmbientEndColor;
mat4 cZone;
};
uniform LightVS
{
vec4 cLightPos;
vec3 cLightDir;
vec4 cNormalOffsetScale;
#ifdef NUMVERTEXLIGHTS
vec4 cVertexLights[4 * 3];
#else
mat4 cLightMatrices[4];
#endif
};
#ifndef CUSTOM_MATERIAL_CBUFFER
uniform MaterialVS
{
vec4 cUOffset;
vec4 cVOffset;
};
#endif
uniform ObjectVS
{
mat4 cModel;
#ifdef BILLBOARD
mat3 cBillboardRot;
#endif
#ifdef SKINNED
uniform vec4 cSkinMatrices[MAXBONES*3];
#endif
};
#endif
#ifdef COMPILEPS
// Pixel shader uniforms
uniform FramePS
{
float cDeltaTimePS;
float cElapsedTimePS;
};
uniform CameraPS
{
vec3 cCameraPosPS;
vec4 cDepthReconstruct;
vec2 cGBufferInvSize;
float cNearClipPS;
float cFarClipPS;
};
uniform ZonePS
{
vec4 cAmbientColor;
vec4 cFogParams;
vec3 cFogColor;
vec3 cZoneMin;
vec3 cZoneMax;
};
uniform LightPS
{
vec4 cLightColor;
vec4 cLightPosPS;
vec3 cLightDirPS;
vec4 cNormalOffsetScalePS;
vec4 cShadowCubeAdjust;
vec4 cShadowDepthFade;
vec2 cShadowIntensity;
vec2 cShadowMapInvSize;
vec4 cShadowSplits;
mat4 cLightMatricesPS[4];
#ifdef VSM_SHADOW
vec2 cVSMShadowParams;
#endif
#ifdef PBR
float cLightRad;
float cLightLength;
#endif
};
#ifndef CUSTOM_MATERIAL_CBUFFER
uniform MaterialPS
{
vec4 cMatDiffColor;
vec3 cMatEmissiveColor;
vec3 cMatEnvMapColor;
vec4 cMatSpecColor;
#ifdef PBR
float cRoughness;
float cMetallic;
#endif
};
#endif
#endif
#endif
#ifdef COMPILEPS
uniform sampler2D sDiffMap;
uniform samplerCube sDiffCubeMap;
uniform sampler2D sNormalMap;
uniform sampler2D sSpecMap;
uniform sampler2D sEmissiveMap;
uniform sampler2D sEnvMap;
uniform samplerCube sEnvCubeMap;
uniform sampler2D sLightRampMap;
uniform sampler2D sLightSpotMap;
uniform samplerCube sLightCubeMap;
#ifndef GL_ES
uniform sampler3D sVolumeMap;
uniform sampler2D sAlbedoBuffer;
uniform sampler2D sNormalBuffer;
uniform sampler2D sDepthBuffer;
uniform sampler2D sLightBuffer;
#ifdef VSM_SHADOW
uniform sampler2D sShadowMap;
#else
uniform sampler2DShadow sShadowMap;
#endif
uniform samplerCube sFaceSelectCubeMap;
uniform samplerCube sIndirectionCubeMap;
uniform samplerCube sZoneCubeMap;
uniform sampler3D sZoneVolumeMap;
#else
uniform highp sampler2D sShadowMap;
#endif
#ifdef GL3
#define texture2D texture
#define texture2DProj textureProj
#define texture3D texture
#define textureCube texture
#define texture2DLod textureLod
#define texture2DLodOffset textureLodOffset
#endif
vec3 DecodeNormal(vec4 normalInput)
{
#ifdef PACKEDNORMAL
vec3 normal;
normal.xy = normalInput.ag * 2.0 - 1.0;
normal.z = sqrt(max(1.0 - dot(normal.xy, normal.xy), 0.0));
return normal;
#else
return normalize(normalInput.rgb * 2.0 - 1.0);
#endif
}
vec3 EncodeDepth(float depth)
{
#ifndef GL3
vec3 ret;
depth *= 255.0;
ret.x = floor(depth);
depth = (depth - ret.x) * 255.0;
ret.y = floor(depth);
ret.z = (depth - ret.y);
ret.xy *= 1.0 / 255.0;
return ret;
#else
// OpenGL 3 can use different MRT formats, so no need for encoding
return vec3(depth, 0.0, 0.0);
#endif
}
float DecodeDepth(vec3 depth)
{
#ifndef GL3
const vec3 dotValues = vec3(1.0, 1.0 / 255.0, 1.0 / (255.0 * 255.0));
return dot(depth, dotValues);
#else
// OpenGL 3 can use different MRT formats, so no need for encoding
return depth.r;
#endif
}
float ReconstructDepth(float hwDepth)
{
return dot(vec2(hwDepth, cDepthReconstruct.y / (hwDepth - cDepthReconstruct.x)), cDepthReconstruct.zw);
}
#endif
#ifdef COMPILEVS
// Silence WARNING: Shader ... does not use the define NOUV
#ifdef NOUV
#endif
// Silence GLSL 150 deprecation warnings
#ifdef GL3
#define attribute in
#define varying out
#endif
attribute vec4 iPos;
attribute vec3 iNormal;
attribute vec4 iColor;
attribute vec2 iTexCoord;
attribute vec2 iTexCoord1;
attribute vec4 iTangent;
attribute vec4 iBlendWeights;
attribute vec4 iBlendIndices;
attribute vec3 iCubeTexCoord;
attribute vec4 iCubeTexCoord1;
#ifdef INSTANCED
attribute vec4 iTexCoord4;
attribute vec4 iTexCoord5;
attribute vec4 iTexCoord6;
#endif
attribute float iObjectIndex;
#ifdef SKINNED
mat4 GetSkinMatrix(vec4 blendWeights, vec4 blendIndices)
{
ivec4 idx = ivec4(blendIndices) * 3;
const vec4 lastColumn = vec4(0.0, 0.0, 0.0, 1.0);
return mat4(cSkinMatrices[idx.x], cSkinMatrices[idx.x + 1], cSkinMatrices[idx.x + 2], lastColumn) * blendWeights.x +
mat4(cSkinMatrices[idx.y], cSkinMatrices[idx.y + 1], cSkinMatrices[idx.y + 2], lastColumn) * blendWeights.y +
mat4(cSkinMatrices[idx.z], cSkinMatrices[idx.z + 1], cSkinMatrices[idx.z + 2], lastColumn) * blendWeights.z +
mat4(cSkinMatrices[idx.w], cSkinMatrices[idx.w + 1], cSkinMatrices[idx.w + 2], lastColumn) * blendWeights.w;
}
#endif
#ifdef INSTANCED
mat4 GetInstanceMatrix()
{
const vec4 lastColumn = vec4(0.0, 0.0, 0.0, 1.0);
return mat4(iTexCoord4, iTexCoord5, iTexCoord6, lastColumn);
}
#endif
mat3 GetNormalMatrix(mat4 modelMatrix)
{
return mat3(modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz);
}
vec2 GetTexCoord(vec2 texCoord)
{
return vec2(dot(texCoord, cUOffset.xy) + cUOffset.w, dot(texCoord, cVOffset.xy) + cVOffset.w);
}
vec4 GetClipPos(vec3 worldPos)
{
vec4 ret = vec4(worldPos, 1.0) * cViewProj;
// While getting the clip coordinate, also automatically set gl_ClipVertex for user clip planes
#if !defined(GL_ES) && !defined(GL3)
gl_ClipVertex = ret;
#elif defined(GL3)
gl_ClipDistance[0] = dot(cClipPlane, ret);
#endif
return ret;
}
float GetZonePos(vec3 worldPos)
{
return clamp((vec4(worldPos, 1.0) * cZone).z, 0.0, 1.0);
}
float GetDepth(vec4 clipPos)
{
return dot(clipPos.zw, cDepthMode.zw);
}
#ifdef BILLBOARD
vec3 GetBillboardPos(vec4 iPos, vec2 iSize, mat4 modelMatrix)
{
return (iPos * modelMatrix).xyz + vec3(iSize.x, iSize.y, 0.0) * cBillboardRot;
}
vec3 GetBillboardNormal()
{
return vec3(-cBillboardRot[0][2], -cBillboardRot[1][2], -cBillboardRot[2][2]);
}
#endif
#ifdef DIRBILLBOARD
mat3 GetFaceCameraRotation(vec3 position, vec3 direction)
{
vec3 cameraDir = normalize(position - cCameraPos);
vec3 front = normalize(direction);
vec3 right = normalize(cross(front, cameraDir));
vec3 up = normalize(cross(front, right));
return mat3(
right.x, up.x, front.x,
right.y, up.y, front.y,
right.z, up.z, front.z
);
}
vec3 GetBillboardPos(vec4 iPos, vec3 iDirection, mat4 modelMatrix)
{
vec3 worldPos = (iPos * modelMatrix).xyz;
return worldPos + vec3(iTexCoord1.x, 0.0, iTexCoord1.y) * GetFaceCameraRotation(worldPos, iDirection);
}
vec3 GetBillboardNormal(vec4 iPos, vec3 iDirection, mat4 modelMatrix)
{
vec3 worldPos = (iPos * modelMatrix).xyz;
return vec3(0.0, 1.0, 0.0) * GetFaceCameraRotation(worldPos, iDirection);
}
#endif
#ifdef TRAILFACECAM
vec3 GetTrailPos(vec4 iPos, vec3 iFront, float iScale, mat4 modelMatrix)
{
vec3 up = normalize(cCameraPos - iPos.xyz);
vec3 right = normalize(cross(iFront, up));
return (vec4((iPos.xyz + right * iScale), 1.0) * modelMatrix).xyz;
}
vec3 GetTrailNormal(vec4 iPos)
{
return normalize(cCameraPos - iPos.xyz);
}
#endif
#ifdef TRAILBONE
vec3 GetTrailPos(vec4 iPos, vec3 iParentPos, float iScale, mat4 modelMatrix)
{
vec3 right = iParentPos - iPos.xyz;
return (vec4((iPos.xyz + right * iScale), 1.0) * modelMatrix).xyz;
}
vec3 GetTrailNormal(vec4 iPos, vec3 iParentPos, vec3 iForward)
{
vec3 left = normalize(iPos.xyz - iParentPos);
vec3 up = normalize(cross(normalize(iForward), left));
return up;
}
#endif
#if defined(SKINNED)
#define iModelMatrix GetSkinMatrix(iBlendWeights, iBlendIndices)
#elif defined(INSTANCED)
#define iModelMatrix GetInstanceMatrix()
#else
#define iModelMatrix cModel
#endif
vec3 GetWorldPos(mat4 modelMatrix)
{
#if defined(BILLBOARD)
return GetBillboardPos(iPos, iTexCoord1, modelMatrix);
#elif defined(DIRBILLBOARD)
return GetBillboardPos(iPos, iNormal, modelMatrix);
#elif defined(TRAILFACECAM)
return GetTrailPos(iPos, iTangent.xyz, iTangent.w, modelMatrix);
#elif defined(TRAILBONE)
return GetTrailPos(iPos, iTangent.xyz, iTangent.w, modelMatrix);
#else
return (iPos * modelMatrix).xyz;
#endif
}
vec3 GetWorldNormal(mat4 modelMatrix)
{
#if defined(BILLBOARD)
return GetBillboardNormal();
#elif defined(DIRBILLBOARD)
return GetBillboardNormal(iPos, iNormal, modelMatrix);
#elif defined(TRAILFACECAM)
return GetTrailNormal(iPos);
#elif defined(TRAILBONE)
return GetTrailNormal(iPos, iTangent.xyz, iNormal);
#else
return normalize(iNormal * GetNormalMatrix(modelMatrix));
#endif
}
vec4 GetWorldTangent(mat4 modelMatrix)
{
#if defined(BILLBOARD)
return vec4(normalize(vec3(1.0, 0.0, 0.0) * cBillboardRot), 1.0);
#elif defined(DIRBILLBOARD)
return vec4(normalize(vec3(1.0, 0.0, 0.0) * GetNormalMatrix(modelMatrix)), 1.0);
#else
return vec4(normalize(iTangent.xyz * GetNormalMatrix(modelMatrix)), iTangent.w);
#endif
}
#else
// Silence GLSL 150 deprecation warnings
#ifdef GL3
#define varying in
#ifndef MRT_COUNT
#if defined(DEFERRED)
#define MRT_COUNT 4
#elif defined(PREPASS)
#define MRT_COUNT 2
#else
#define MRT_COUNT 1
#endif
#endif
out vec4 fragData[MRT_COUNT];
#define gl_FragColor fragData[0]
#define gl_FragData fragData
#endif
#endif
#ifdef COMPILEVS
mat3 GetCameraRot()
{
return mat3(cViewInv[0][0], cViewInv[0][1], cViewInv[0][2],
cViewInv[1][0], cViewInv[1][1], cViewInv[1][2],
cViewInv[2][0], cViewInv[2][1], cViewInv[2][2]);
}
vec4 GetScreenPos(vec4 clipPos)
{
return vec4(
clipPos.x * cGBufferOffsets.z + cGBufferOffsets.x * clipPos.w,
clipPos.y * cGBufferOffsets.w + cGBufferOffsets.y * clipPos.w,
0.0,
clipPos.w);
}
vec2 GetScreenPosPreDiv(vec4 clipPos)
{
return vec2(
clipPos.x / clipPos.w * cGBufferOffsets.z + cGBufferOffsets.x,
clipPos.y / clipPos.w * cGBufferOffsets.w + cGBufferOffsets.y);
}
vec2 GetQuadTexCoord(vec4 clipPos)
{
return vec2(
clipPos.x / clipPos.w * 0.5 + 0.5,
clipPos.y / clipPos.w * 0.5 + 0.5);
}
vec2 GetQuadTexCoordNoFlip(vec3 worldPos)
{
return vec2(
worldPos.x * 0.5 + 0.5,
-worldPos.y * 0.5 + 0.5);
}
vec3 GetFarRay(vec4 clipPos)
{
vec3 viewRay = vec3(
clipPos.x / clipPos.w * cFrustumSize.x,
clipPos.y / clipPos.w * cFrustumSize.y,
cFrustumSize.z);
return viewRay * GetCameraRot();
}
vec3 GetNearRay(vec4 clipPos)
{
vec3 viewRay = vec3(
clipPos.x / clipPos.w * cFrustumSize.x,
clipPos.y / clipPos.w * cFrustumSize.y,
0.0);
return (viewRay * GetCameraRot()) * cDepthMode.x;
}
#endif
#ifdef COMPILEVS
vec3 GetAmbient(float zonePos)
{
return cAmbientStartColor + zonePos * cAmbientEndColor;
}
#ifdef NUMVERTEXLIGHTS
float GetVertexLight(int index, vec3 worldPos, vec3 normal)
{
vec3 lightDir = cVertexLights[index * 3 + 1].xyz;
vec3 lightPos = cVertexLights[index * 3 + 2].xyz;
float invRange = cVertexLights[index * 3].w;
float cutoff = cVertexLights[index * 3 + 1].w;
float invCutoff = cVertexLights[index * 3 + 2].w;
// Directional light
if (invRange == 0.0)
{
#ifdef TRANSLUCENT
float NdotL = abs(dot(normal, lightDir));
#else
float NdotL = max(dot(normal, lightDir), 0.0);
#endif
return NdotL;
}
// Point/spot light
else
{
vec3 lightVec = (lightPos - worldPos) * invRange;
float lightDist = length(lightVec);
vec3 localDir = lightVec / lightDist;
#ifdef TRANSLUCENT
float NdotL = abs(dot(normal, localDir));
#else
float NdotL = max(dot(normal, localDir), 0.0);
#endif
float atten = clamp(1.0 - lightDist * lightDist, 0.0, 1.0);
float spotEffect = dot(localDir, lightDir);
float spotAtten = clamp((spotEffect - cutoff) * invCutoff, 0.0, 1.0);
return NdotL * atten * spotAtten;
}
}
float GetVertexLightVolumetric(int index, vec3 worldPos)
{
vec3 lightDir = cVertexLights[index * 3 + 1].xyz;
vec3 lightPos = cVertexLights[index * 3 + 2].xyz;
float invRange = cVertexLights[index * 3].w;
float cutoff = cVertexLights[index * 3 + 1].w;
float invCutoff = cVertexLights[index * 3 + 2].w;
// Directional light
if (invRange == 0.0)
return 1.0;
// Point/spot light
else
{
vec3 lightVec = (lightPos - worldPos) * invRange;
float lightDist = length(lightVec);
vec3 localDir = lightVec / lightDist;
float atten = clamp(1.0 - lightDist * lightDist, 0.0, 1.0);
float spotEffect = dot(localDir, lightDir);
float spotAtten = clamp((spotEffect - cutoff) * invCutoff, 0.0, 1.0);
return atten * spotAtten;
}
}
#endif
#ifdef SHADOW
#if defined(DIRLIGHT) && (!defined(GL_ES) || defined(WEBGL))
#define NUMCASCADES 4
#else
#define NUMCASCADES 1
#endif
vec4 GetShadowPos(int index, vec3 normal, vec4 projWorldPos)
{
#ifdef NORMALOFFSET
float normalOffsetScale[4];
normalOffsetScale[0] = cNormalOffsetScale.x;
normalOffsetScale[1] = cNormalOffsetScale.y;
normalOffsetScale[2] = cNormalOffsetScale.z;
normalOffsetScale[3] = cNormalOffsetScale.w;
#ifdef DIRLIGHT
float cosAngle = clamp(1.0 - dot(normal, cLightDir), 0.0, 1.0);
#else
float cosAngle = clamp(1.0 - dot(normal, normalize(cLightPos.xyz - projWorldPos.xyz)), 0.0, 1.0);
#endif
projWorldPos.xyz += cosAngle * normalOffsetScale[index] * normal;
#endif
#if defined(DIRLIGHT)
return projWorldPos * cLightMatrices[index];
#elif defined(SPOTLIGHT)
return projWorldPos * cLightMatrices[1];
#else
return vec4(projWorldPos.xyz - cLightPos.xyz, 1.0);
#endif
}
#endif
#endif
#ifdef COMPILEPS
float GetDiffuse(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
#ifdef DIRLIGHT
lightDir = cLightDirPS;
#ifdef TRANSLUCENT
return abs(dot(normal, lightDir));
#else
return max(dot(normal, lightDir), 0.0);
#endif
#else
vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
float lightDist = length(lightVec);
lightDir = lightVec / lightDist;
#ifdef TRANSLUCENT
return abs(dot(normal, lightDir)) * texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
#else
return max(dot(normal, lightDir), 0.0) * texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
#endif
#endif
}
float GetAtten(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
lightDir = cLightDirPS;
return clamp(dot(normal, lightDir), 0.0, 1.0);
}
float GetAttenPoint(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
float lightDist = length(lightVec);
float falloff = pow(clamp(1.0 - pow(lightDist / 1.0, 4.0), 0.0, 1.0), 2.0) * 3.14159265358979323846 / (4.0 * 3.14159265358979323846)*(pow(lightDist, 2.0) + 1.0);
lightDir = lightVec / lightDist;
return clamp(dot(normal, lightDir), 0.0, 1.0) * falloff;
}
float GetAttenSpot(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
float lightDist = length(lightVec);
float falloff = pow(clamp(1.0 - pow(lightDist / 1.0, 4.0), 0.0, 1.0), 2.0) / (pow(lightDist, 2.0) + 1.0);
lightDir = lightVec / lightDist;
return clamp(dot(normal, lightDir), 0.0, 1.0) * falloff;
}
float GetDiffuseVolumetric(vec3 worldPos)
{
#ifdef DIRLIGHT
return 1.0;
#else
vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
float lightDist = length(lightVec);
return texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
#endif
}
float GetSpecular(vec3 normal, vec3 eyeVec, vec3 lightDir, float specularPower)
{
vec3 halfVec = normalize(normalize(eyeVec) + lightDir);
return pow(max(dot(normal, halfVec), 0.0), specularPower);
}
float GetIntensity(vec3 color)
{
return dot(color, vec3(0.299, 0.587, 0.114));
}
#ifdef SHADOW
#if defined(DIRLIGHT) && (!defined(GL_ES) || defined(WEBGL))
#define NUMCASCADES 4
#else
#define NUMCASCADES 1
#endif
#ifdef VSM_SHADOW
float ReduceLightBleeding(float min, float p_max)
{
return clamp((p_max - min) / (1.0 - min), 0.0, 1.0);
}
float Chebyshev(vec2 Moments, float depth)
{
//One-tailed inequality valid if depth > Moments.x
float p = float(depth <= Moments.x);
//Compute variance.
float Variance = Moments.y - (Moments.x * Moments.x);
float minVariance = cVSMShadowParams.x;
Variance = max(Variance, minVariance);
//Compute probabilistic upper bound.
float d = depth - Moments.x;
float p_max = Variance / (Variance + d*d);
// Prevent light bleeding
p_max = ReduceLightBleeding(cVSMShadowParams.y, p_max);
return max(p, p_max);
}
#endif
#ifndef GL_ES
float GetShadow(vec4 shadowPos)
{
#if defined(SIMPLE_SHADOW)
// Take one sample
#ifndef GL3
float inLight = shadow2DProj(sShadowMap, shadowPos).r;
#else
float inLight = textureProj(sShadowMap, shadowPos);
#endif
return cShadowIntensity.y + cShadowIntensity.x * inLight;
#elif defined(PCF_SHADOW)
// Take four samples and average them
// Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
#ifndef POINTLIGHT
vec2 offsets = cShadowMapInvSize * shadowPos.w;
#else
vec2 offsets = cShadowMapInvSize;
#endif
#ifndef GL3
return cShadowIntensity.y + cShadowIntensity.x * (shadow2DProj(sShadowMap, shadowPos).r +
shadow2DProj(sShadowMap, vec4(shadowPos.x + offsets.x, shadowPos.yzw)).r +
shadow2DProj(sShadowMap, vec4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r +
shadow2DProj(sShadowMap, vec4(shadowPos.xy + offsets.xy, shadowPos.zw)).r);
#else
return cShadowIntensity.y + cShadowIntensity.x * (textureProj(sShadowMap, shadowPos) +
textureProj(sShadowMap, vec4(shadowPos.x + offsets.x, shadowPos.yzw)) +
textureProj(sShadowMap, vec4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)) +
textureProj(sShadowMap, vec4(shadowPos.xy + offsets.xy, shadowPos.zw)));
#endif
#elif defined(VSM_SHADOW)
vec2 samples = texture2D(sShadowMap, shadowPos.xy / shadowPos.w).rg;
return cShadowIntensity.y + cShadowIntensity.x * Chebyshev(samples, shadowPos.z / shadowPos.w);
#endif
}
#else
float GetShadow(highp vec4 shadowPos)
{
#if defined(SIMPLE_SHADOW)
// Take one sample
return cShadowIntensity.y + (texture2DProj(sShadowMap, shadowPos).r * shadowPos.w > shadowPos.z ? cShadowIntensity.x : 0.0);
#elif defined(PCF_SHADOW)
// Take four samples and average them
vec2 offsets = cShadowMapInvSize * shadowPos.w;
vec4 inLight = vec4(
texture2DProj(sShadowMap, shadowPos).r * shadowPos.w > shadowPos.z,
texture2DProj(sShadowMap, vec4(shadowPos.x + offsets.x, shadowPos.yzw)).r * shadowPos.w > shadowPos.z,
texture2DProj(sShadowMap, vec4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r * shadowPos.w > shadowPos.z,
texture2DProj(sShadowMap, vec4(shadowPos.xy + offsets.xy, shadowPos.zw)).r * shadowPos.w > shadowPos.z
);
return cShadowIntensity.y + dot(inLight, vec4(cShadowIntensity.x));
#elif defined(VSM_SHADOW)
vec2 samples = texture2D(sShadowMap, shadowPos.xy / shadowPos.w).rg;
return cShadowIntensity.y + cShadowIntensity.x * Chebyshev(samples, shadowPos.z / shadowPos.w);
#endif
}
#endif
#ifdef POINTLIGHT
float GetPointShadow(vec3 lightVec)
{
vec3 axis = textureCube(sFaceSelectCubeMap, lightVec).rgb;
float depth = abs(dot(lightVec, axis));
// Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
// and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
// case filtering across faces is wrong
const vec3 factor = vec3(1.0 / 256.0);
lightVec += factor * axis * lightVec;
// Read the 2D UV coordinates, adjust according to shadow map size and add face offset
vec4 indirectPos = textureCube(sIndirectionCubeMap, lightVec);
indirectPos.xy *= cShadowCubeAdjust.xy;
indirectPos.xy += vec2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
vec4 shadowPos = vec4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
return GetShadow(shadowPos);
}
#endif
#ifdef DIRLIGHT
float GetDirShadowFade(float inLight, float depth)
{
return min(inLight + max((depth - cShadowDepthFade.z) * cShadowDepthFade.w, 0.0), 1.0);
}
#if !defined(GL_ES) || defined(WEBGL)
float GetDirShadow(const vec4 iShadowPos[NUMCASCADES], float depth)
{
vec4 shadowPos;
if (depth < cShadowSplits.x)
shadowPos = iShadowPos[0];
else if (depth < cShadowSplits.y)
shadowPos = iShadowPos[1];
else if (depth < cShadowSplits.z)
shadowPos = iShadowPos[2];
else
shadowPos = iShadowPos[3];
return GetDirShadowFade(GetShadow(shadowPos), depth);
}
#else
float GetDirShadow(const highp vec4 iShadowPos[NUMCASCADES], float depth)
{
return GetDirShadowFade(GetShadow(iShadowPos[0]), depth);
}
#endif
#ifndef GL_ES
float GetDirShadowDeferred(vec4 projWorldPos, vec3 normal, float depth)
{
vec4 shadowPos;
#ifdef NORMALOFFSET
float cosAngle = clamp(1.0 - dot(normal, cLightDirPS), 0.0, 1.0);
if (depth < cShadowSplits.x)
shadowPos = vec4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.x * normal, 1.0) * cLightMatricesPS[0];
else if (depth < cShadowSplits.y)
shadowPos = vec4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.y * normal, 1.0) * cLightMatricesPS[1];
else if (depth < cShadowSplits.z)
shadowPos = vec4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.z * normal, 1.0) * cLightMatricesPS[2];
else
shadowPos = vec4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.w * normal, 1.0) * cLightMatricesPS[3];
#else
if (depth < cShadowSplits.x)
shadowPos = projWorldPos * cLightMatricesPS[0];
else if (depth < cShadowSplits.y)
shadowPos = projWorldPos * cLightMatricesPS[1];
else if (depth < cShadowSplits.z)
shadowPos = projWorldPos * cLightMatricesPS[2];
else
shadowPos = projWorldPos * cLightMatricesPS[3];
#endif
return GetDirShadowFade(GetShadow(shadowPos), depth);
}
#endif
#endif
#ifndef GL_ES
float GetShadow(const vec4 iShadowPos[NUMCASCADES], float depth)
#else
float GetShadow(const highp vec4 iShadowPos[NUMCASCADES], float depth)
#endif
{
#if defined(DIRLIGHT)
return GetDirShadow(iShadowPos, depth);
#elif defined(SPOTLIGHT)
return GetShadow(iShadowPos[0]);
#else
return GetPointShadow(iShadowPos[0].xyz);
#endif
}
#ifndef GL_ES
float GetShadowDeferred(vec4 projWorldPos, vec3 normal, float depth)
{
#ifdef DIRLIGHT
return GetDirShadowDeferred(projWorldPos, normal, depth);
#else
#ifdef NORMALOFFSET
float cosAngle = clamp(1.0 - dot(normal, normalize(cLightPosPS.xyz - projWorldPos.xyz)), 0.0, 1.0);
projWorldPos.xyz += cosAngle * cNormalOffsetScalePS.x * normal;
#endif
#ifdef SPOTLIGHT
vec4 shadowPos = projWorldPos * cLightMatricesPS[1];
return GetShadow(shadowPos);
#else
vec3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
return GetPointShadow(shadowPos);
#endif
#endif
}
#endif
#endif
#endif
#ifdef COMPILEPS
vec3 GetFog(vec3 color, float fogFactor)
{
return mix(cFogColor, color, fogFactor);
}
vec3 GetLitFog(vec3 color, float fogFactor)
{
return color * fogFactor;
}
float GetFogFactor(float depth)
{
return clamp((cFogParams.x - depth) * cFogParams.y, 0.0, 1.0);
}
float GetHeightFogFactor(float depth, float height)
{
float fogFactor = GetFogFactor(depth);
float heightFogFactor = (height - cFogParams.z) * cFogParams.w;
heightFogFactor = 1.0 - clamp(exp(-(heightFogFactor * heightFogFactor)), 0.0, 1.0);
return min(heightFogFactor, fogFactor);
}
#endif
#ifdef NORMALMAP
varying vec4 vTexCoord;
varying vec4 vTangent;
#else
varying vec2 vTexCoord;
#endif
varying vec3 vNormal;
varying vec4 vWorldPos;
#ifdef VERTEXCOLOR
varying vec4 vColor;
#endif
#ifdef PERPIXEL
#ifdef SHADOW
#ifndef GL_ES
varying vec4 vShadowPos[NUMCASCADES];
#else
varying highp vec4 vShadowPos[NUMCASCADES];
#endif
#endif
#ifdef SPOTLIGHT
varying vec4 vSpotPos;
#endif
#ifdef POINTLIGHT
varying vec3 vCubeMaskVec;
#endif
#else
varying vec3 vVertexLight;
varying vec4 vScreenPos;
#ifdef ENVCUBEMAP
varying vec3 vReflectionVec;
#endif
#if defined(LIGHTMAP) || defined(AO)
varying vec2 vTexCoord2;
#endif
#endif
/*void VS()
{
mat4 modelMatrix = iModelMatrix;
vec3 worldPos = GetWorldPos(modelMatrix);
gl_Position = GetClipPos(worldPos);
vNormal = GetWorldNormal(modelMatrix);
vWorldPos = vec4(worldPos, GetDepth(gl_Position));
#ifdef VERTEXCOLOR
vColor = iColor;
#endif
#ifdef NORMALMAP
vec4 tangent = GetWorldTangent(modelMatrix);
vec3 bitangent = cross(tangent.xyz, vNormal) * tangent.w;
vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
vTangent = vec4(tangent.xyz, bitangent.z);
#else
vTexCoord = GetTexCoord(iTexCoord);
#endif
#ifdef PERPIXEL
// Per-pixel forward lighting
vec4 projWorldPos = vec4(worldPos, 1.0);
#ifdef SHADOW
// Shadow projection: transform from world space to shadow space
for (int i = 0; i < NUMCASCADES; i++)
vShadowPos[i] = GetShadowPos(i, vNormal, projWorldPos);
#endif
#ifdef SPOTLIGHT
// Spotlight projection: transform from world space to projector texture coordinates
vSpotPos = projWorldPos * cLightMatrices[0];
#endif
#ifdef POINTLIGHT
vCubeMaskVec = (worldPos - cLightPos.xyz) * mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz);
#endif
#else
// Ambient & per-vertex lighting
#if defined(LIGHTMAP) || defined(AO)
// If using lightmap, disregard zone ambient light
// If using AO, calculate ambient in the PS
vVertexLight = vec3(0.0, 0.0, 0.0);
vTexCoord2 = iTexCoord1;
#else
vVertexLight = GetAmbient(GetZonePos(worldPos));
#endif
#ifdef NUMVERTEXLIGHTS
for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights[i * 3].rgb;
#endif
vScreenPos = GetScreenPos(gl_Position);
#ifdef ENVCUBEMAP
vReflectionVec = worldPos - cCameraPos;
#endif
#endif
}*/
void main()
{
// Get material diffuse albedo
#ifdef DIFFMAP
vec4 diffInput = texture2D(sDiffMap, vTexCoord.xy);
#ifdef ALPHAMASK
if (diffInput.a < 0.5)
discard;
#endif
vec4 diffColor = cMatDiffColor * diffInput;
#else
vec4 diffColor = cMatDiffColor;
#endif
#ifdef VERTEXCOLOR
diffColor *= vColor;
#endif
// Get material specular albedo
#ifdef SPECMAP
vec3 specColor = cMatSpecColor.rgb * texture2D(sSpecMap, vTexCoord.xy).rgb;
#else
vec3 specColor = cMatSpecColor.rgb;
#endif
// Get normal
#ifdef NORMALMAP
mat3 tbn = mat3(vTangent.xyz, vec3(vTexCoord.zw, vTangent.w), vNormal);
vec3 normal = normalize(tbn * DecodeNormal(texture2D(sNormalMap, vTexCoord.xy)));
#else
vec3 normal = normalize(vNormal);
#endif
// Get fog factor
#ifdef HEIGHTFOG
float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
#else
float fogFactor = GetFogFactor(vWorldPos.w);
#endif
#if defined(PERPIXEL)
// Per-pixel forward lighting
vec3 lightColor;
vec3 lightDir;
vec3 finalColor;
float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir);
#ifdef SHADOW
diff *= GetShadow(vShadowPos, vWorldPos.w);
#endif
#if defined(SPOTLIGHT)
lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
#elif defined(CUBEMASK)
lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb;
#else
lightColor = cLightColor.rgb;
#endif
#ifdef SPECULAR
float spec = GetSpecular(normal, cCameraPosPS - vWorldPos.xyz, lightDir, cMatSpecColor.a);
finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);
#else
finalColor = diff * lightColor * diffColor.rgb;
#endif
#ifdef AMBIENT
finalColor += cAmbientColor.rgb * diffColor.rgb;
finalColor += cMatEmissiveColor;
gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
#else
gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a);
#endif
#elif defined(PREPASS)
// Fill light pre-pass G-Buffer
float specPower = cMatSpecColor.a / 255.0;
gl_FragData[0] = vec4(normal * 0.5 + 0.5, specPower);
gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);
#elif defined(DEFERRED)
// Fill deferred G-buffer
float specIntensity = specColor.g;
float specPower = cMatSpecColor.a / 255.0;
vec3 finalColor = vVertexLight * diffColor.rgb;
#ifdef AO
// If using AO, the vertex light ambient is black, calculate occluded ambient here
finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * cAmbientColor.rgb * diffColor.rgb;
#endif
#ifdef ENVCUBEMAP
finalColor += cMatEnvMapColor * textureCube(sEnvCubeMap, reflect(vReflectionVec, normal)).rgb;
#endif
#ifdef LIGHTMAP
finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * diffColor.rgb;
#endif
#ifdef EMISSIVEMAP
finalColor += cMatEmissiveColor * texture2D(sEmissiveMap, vTexCoord.xy).rgb;
#else
finalColor += cMatEmissiveColor;
#endif
gl_FragData[0] = vec4(GetFog(finalColor, fogFactor), 1.0);
gl_FragData[1] = fogFactor * vec4(diffColor.rgb, specIntensity);
gl_FragData[2] = vec4(normal * 0.5 + 0.5, specPower);
gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);
#else
// Ambient & per-vertex lighting
vec3 finalColor = vVertexLight * diffColor.rgb;
#ifdef AO
// If using AO, the vertex light ambient is black, calculate occluded ambient here
finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * cAmbientColor.rgb * diffColor.rgb;
#endif
#ifdef MATERIAL
// Add light pre-pass accumulation result
// Lights are accumulated at half intensity. Bring back to full intensity now
vec4 lightInput = 2.0 * texture2DProj(sLightBuffer, vScreenPos);
vec3 lightSpecColor = lightInput.a * lightInput.rgb / max(GetIntensity(lightInput.rgb), 0.001);
finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;
#endif
#ifdef ENVCUBEMAP
finalColor += cMatEnvMapColor * textureCube(sEnvCubeMap, reflect(vReflectionVec, normal)).rgb;
#endif
#ifdef LIGHTMAP
finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * diffColor.rgb;
#endif
#ifdef EMISSIVEMAP
finalColor += cMatEmissiveColor * texture2D(sEmissiveMap, vTexCoord.xy).rgb;
#else
finalColor += cMatEmissiveColor;
#endif
gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
#endif
}