mirror of
https://github.com/lettier/3d-game-shaders-for-beginners.git
synced 2025-10-03 16:01:57 +02:00
339 lines
8.9 KiB
GLSL
339 lines
8.9 KiB
GLSL
/*
|
|
(C) 2019 David Lettier
|
|
lettier.com
|
|
*/
|
|
|
|
#version 150
|
|
|
|
#define NUMBER_OF_LIGHTS 4
|
|
#define MAX_SHININESS 127.75
|
|
#define MAX_FRESNEL_POWER 5.0
|
|
|
|
uniform float osg_FrameTime;
|
|
|
|
uniform vec2 pi;
|
|
uniform vec2 gamma;
|
|
|
|
uniform mat4 trans_world_to_view;
|
|
uniform mat4 trans_view_to_world;
|
|
|
|
uniform sampler2D p3d_Texture0;
|
|
uniform sampler2D p3d_Texture1;
|
|
uniform sampler2D p3d_Texture2;
|
|
uniform sampler2D flowTexture;
|
|
uniform sampler2D ssaoBlurTexture;
|
|
|
|
uniform struct
|
|
{ vec4 ambient
|
|
; vec4 diffuse
|
|
; vec4 emission
|
|
; vec3 specular
|
|
; float shininess
|
|
;
|
|
} p3d_Material;
|
|
|
|
uniform struct
|
|
{ vec4 ambient
|
|
;
|
|
} p3d_LightModel;
|
|
|
|
uniform struct p3d_LightSourceParameters
|
|
{ vec4 color
|
|
|
|
; vec4 ambient
|
|
; vec4 diffuse
|
|
; vec4 specular
|
|
|
|
; vec4 position
|
|
|
|
; vec3 spotDirection
|
|
; float spotExponent
|
|
; float spotCutoff
|
|
; float spotCosCutoff
|
|
|
|
; float constantAttenuation
|
|
; float linearAttenuation
|
|
; float quadraticAttenuation
|
|
|
|
; vec3 attenuation
|
|
|
|
; sampler2DShadow shadowMap
|
|
|
|
; mat4 shadowViewMatrix
|
|
;
|
|
} p3d_LightSource[NUMBER_OF_LIGHTS];
|
|
|
|
uniform vec2 normalMapsEnabled;
|
|
uniform vec2 fresnelEnabled;
|
|
uniform vec2 rimLightEnabled;
|
|
uniform vec2 blinnPhongEnabled;
|
|
uniform vec2 celShadingEnabled;
|
|
uniform vec2 flowMapsEnabled;
|
|
uniform vec2 specularOnly;
|
|
uniform vec2 isParticle;
|
|
uniform vec2 isWater;
|
|
uniform vec2 sunPosition;
|
|
|
|
in vec4 vertexColor;
|
|
|
|
in vec4 vertexInShadowSpaces[NUMBER_OF_LIGHTS];
|
|
|
|
in vec4 vertexPosition;
|
|
|
|
in vec3 vertexNormal;
|
|
in vec3 binormal;
|
|
in vec3 tangent;
|
|
|
|
in vec2 diffuseCoord;
|
|
in vec2 normalCoord;
|
|
|
|
out vec4 out0;
|
|
out vec4 out1;
|
|
|
|
void main() {
|
|
vec3 shadowColor = pow(vec3(0.149, 0.220, 0.227), vec3(gamma.x));
|
|
int shadowSamples = 2;
|
|
|
|
vec4 diffuseColor;
|
|
if (isParticle.x == 1) {
|
|
diffuseColor = texture(p3d_Texture0, diffuseCoord) * vertexColor;
|
|
} else {
|
|
diffuseColor = texture(p3d_Texture0, diffuseCoord);
|
|
}
|
|
diffuseColor.rgb = pow(diffuseColor.rgb, vec3(gamma.x));
|
|
|
|
vec3 materialSpecularColor = p3d_Material.specular;
|
|
|
|
vec2 flow = texture(flowTexture, normalCoord).xy;
|
|
flow = (flow - 0.5) * 2.0;
|
|
flow.x = abs(flow.x) <= 0.02 ? 0.0 : flow.x;
|
|
flow.y = abs(flow.y) <= 0.02 ? 0.0 : flow.y;
|
|
|
|
vec4 normalTex =
|
|
texture
|
|
( p3d_Texture1
|
|
, vec2
|
|
( normalCoord.x + flowMapsEnabled.x * flow.x * osg_FrameTime
|
|
, normalCoord.y + flowMapsEnabled.y * flow.y * osg_FrameTime
|
|
)
|
|
);
|
|
|
|
vec3 normal;
|
|
|
|
if (isParticle.x == 1) {
|
|
normal = normalize((trans_world_to_view * vec4(0.0, 0.0, 1.0, 0.0)).xyz);
|
|
} else if (normalMapsEnabled.x == 1) {
|
|
vec3 normalRaw =
|
|
normalize
|
|
( normalTex.rgb
|
|
* 2.0
|
|
- 1.0
|
|
);
|
|
normal =
|
|
normalize
|
|
( mat3
|
|
( tangent
|
|
, binormal
|
|
, vertexNormal
|
|
)
|
|
* normalRaw
|
|
);
|
|
} else {
|
|
normal =
|
|
normalize(vertexNormal);
|
|
}
|
|
|
|
vec4 specularMap = texture(p3d_Texture2, diffuseCoord);
|
|
|
|
vec4 diffuse = vec4(0.0, 0.0, 0.0, diffuseColor.a);
|
|
vec4 specular = vec4(0.0, 0.0, 0.0, diffuseColor.a);
|
|
|
|
for (int i = 0; i < p3d_LightSource.length(); ++i) {
|
|
vec3 lightDirection =
|
|
p3d_LightSource[i].position.xyz
|
|
- vertexPosition.xyz
|
|
* p3d_LightSource[i].position.w;
|
|
|
|
vec3 unitLightDirection = normalize(lightDirection);
|
|
vec3 eyeDirection = normalize(-vertexPosition.xyz);
|
|
vec3 reflectedDirection = normalize(-reflect(unitLightDirection, normal));
|
|
vec3 halfwayDirection = normalize(unitLightDirection + eyeDirection);
|
|
|
|
float lightDistance = length(lightDirection);
|
|
|
|
float attenuation =
|
|
1.0
|
|
/ ( p3d_LightSource[i].constantAttenuation
|
|
+ p3d_LightSource[i].linearAttenuation
|
|
* lightDistance
|
|
+ p3d_LightSource[i].quadraticAttenuation
|
|
* (lightDistance * lightDistance)
|
|
);
|
|
|
|
if (attenuation <= 0.0) { continue; }
|
|
|
|
float diffuseIntensity = dot(normal, unitLightDirection);
|
|
|
|
if (diffuseIntensity < 0.0) { continue; }
|
|
|
|
diffuseIntensity =
|
|
celShadingEnabled.x == 1
|
|
? smoothstep(0.1, 0.2, diffuseIntensity)
|
|
: diffuseIntensity;
|
|
|
|
vec4 lightDiffuseColor = p3d_LightSource[i].diffuse;
|
|
lightDiffuseColor.rgb = pow(lightDiffuseColor.rgb, vec3(gamma.x));
|
|
|
|
vec4 diffuseTemp =
|
|
vec4
|
|
( clamp
|
|
( diffuseColor.rgb
|
|
* lightDiffuseColor.rgb
|
|
* diffuseIntensity
|
|
, 0.0
|
|
, 1.0
|
|
)
|
|
, diffuseColor.a
|
|
);
|
|
|
|
float specularIntensity =
|
|
( blinnPhongEnabled.x == 1
|
|
? clamp(dot(normal, halfwayDirection), 0.0, 1.0)
|
|
: clamp(dot(eyeDirection, reflectedDirection), 0.0, 1.0)
|
|
);
|
|
|
|
specularIntensity =
|
|
( celShadingEnabled.x == 1
|
|
? smoothstep(0.9, 1.0, specularIntensity)
|
|
: specularIntensity
|
|
);
|
|
|
|
vec4 lightSpecularColor = p3d_LightSource[i].specular;
|
|
lightSpecularColor.rgb = pow(lightSpecularColor.rgb, vec3(gamma.x));
|
|
|
|
vec4 materialSpecularColor = vec4(vec3(specularMap.r), diffuseColor.a);
|
|
if (fresnelEnabled.x == 1) {
|
|
float fresnelFactor = dot((blinnPhongEnabled.x == 1 ? halfwayDirection : normal), eyeDirection);
|
|
fresnelFactor = max(fresnelFactor, 0.0);
|
|
fresnelFactor = 1.0 - fresnelFactor;
|
|
fresnelFactor = pow(fresnelFactor, specularMap.b * MAX_FRESNEL_POWER);
|
|
materialSpecularColor.rgb = mix(materialSpecularColor.rgb, vec3(1.0), clamp(fresnelFactor, 0.0, 1.0));
|
|
}
|
|
|
|
vec4 specularTemp = vec4(vec3(0.0), diffuseColor.a);
|
|
specularTemp.rgb = lightSpecularColor.rgb * pow(specularIntensity, specularMap.g * MAX_SHININESS);
|
|
specularTemp.rgb *= materialSpecularColor.rgb;
|
|
specularTemp.rgb *= (1 - isParticle.x);
|
|
specularTemp.rgb = clamp(specularTemp.rgb, 0.0, 1.0);
|
|
|
|
float unitLightDirectionDelta =
|
|
dot
|
|
( normalize(p3d_LightSource[i].spotDirection)
|
|
, -unitLightDirection
|
|
);
|
|
|
|
if (unitLightDirectionDelta < p3d_LightSource[i].spotCosCutoff) { continue; }
|
|
|
|
float spotExponent = p3d_LightSource[i].spotExponent;
|
|
|
|
diffuseTemp.rgb *= (spotExponent <= 0.0 ? 1.0 : pow(unitLightDirectionDelta, spotExponent));
|
|
|
|
vec2 shadowMapSize = textureSize(p3d_LightSource[i].shadowMap, 0);
|
|
float inShadow = 0.0;
|
|
float count = 0.0;
|
|
|
|
for ( int si = -shadowSamples; si <= shadowSamples; ++si) {
|
|
for (int sj = -shadowSamples; sj <= shadowSamples; ++sj) {
|
|
inShadow +=
|
|
( 1.0
|
|
- textureProj
|
|
( p3d_LightSource[i].shadowMap
|
|
, vertexInShadowSpaces[i] + vec4(vec2(si, sj) / shadowMapSize, vec2(0.0))
|
|
)
|
|
);
|
|
|
|
count += 1.0;
|
|
}
|
|
}
|
|
|
|
inShadow /= count;
|
|
|
|
vec3 shadow =
|
|
mix
|
|
( vec3(1.0)
|
|
, shadowColor
|
|
, inShadow
|
|
);
|
|
|
|
diffuseTemp.rgb *= mix(shadow, vec3(1.0), isParticle.x);
|
|
specularTemp.rgb *= mix(shadow, vec3(1.0), isParticle.x);
|
|
|
|
diffuseTemp.rgb *= attenuation;
|
|
specularTemp.rgb *= attenuation;
|
|
|
|
diffuse.rgb += diffuseTemp.rgb;
|
|
specular.rgb += specularTemp.rgb;
|
|
}
|
|
|
|
vec4 rimLight = vec4(vec3(0.0), diffuseColor.a);
|
|
if (rimLightEnabled.x == 1) {
|
|
rimLight.rgb =
|
|
vec3
|
|
( 1.0
|
|
- max
|
|
( 0.0
|
|
, dot(normalize(-vertexPosition.xyz), normalize(normal))
|
|
)
|
|
);
|
|
rimLight.rgb =
|
|
( celShadingEnabled.x == 1
|
|
? smoothstep(0.3, 0.4, rimLight.rgb)
|
|
: pow(rimLight.rgb, vec3(2.0)) * 1.2
|
|
);
|
|
rimLight.rgb *= diffuse.rgb;
|
|
}
|
|
|
|
vec2 ssaoBlurTexSize = textureSize(ssaoBlurTexture, 0).xy;
|
|
vec2 ssaoBlurTexCoord = gl_FragCoord.xy / ssaoBlurTexSize;
|
|
vec3 ssao = texture(ssaoBlurTexture, ssaoBlurTexCoord).rgb;
|
|
ssao = mix(shadowColor, vec3(1.0), clamp(ssao.r, 0.0, 1.0));
|
|
|
|
float sunPosition = sin(sunPosition.x * pi.y);
|
|
float sunMixFactor = 1.0 - (sunPosition / 2.0 + 0.5);
|
|
|
|
vec3 ambientCool = pow(vec3(0.302, 0.451, 0.471), vec3(gamma.x)) * max(0.5, sunMixFactor);
|
|
vec3 ambientWarm = pow(vec3(0.765, 0.573, 0.400), vec3(gamma.x)) * max(0.5, sunMixFactor);
|
|
|
|
vec3 skyLight = mix(ambientCool, ambientWarm, sunMixFactor);
|
|
vec3 groundLight = mix(ambientWarm, ambientCool, sunMixFactor);
|
|
|
|
vec3 worldNormal = normalize((trans_view_to_world * vec4(normal, 0.0)).xyz);
|
|
|
|
vec3 ambientLight =
|
|
mix
|
|
( groundLight
|
|
, skyLight
|
|
, 0.5 * (1.0 + dot(worldNormal, vec3(0, 0, 1)))
|
|
);
|
|
|
|
vec3 ambient =
|
|
ambientLight.rgb
|
|
* diffuseColor.rgb
|
|
* ssao;
|
|
|
|
vec3 emission = p3d_Material.emission.rgb * max(0.1, pow(sunPosition, 0.4));
|
|
|
|
out0.a = diffuseColor.a;
|
|
out0.rgb = ambient.rgb
|
|
+ diffuse.rgb
|
|
+ rimLight.rgb
|
|
+ emission.rgb;
|
|
|
|
if (isWater.x == 1) { out0.a = 0.0; }
|
|
|
|
out1.a = diffuseColor.a;
|
|
out1.rgb = specular.rgb;
|
|
|
|
if (isParticle.x == 1) { out1.rgb = vec3(0.0); }
|
|
}
|