mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-09 11:03:12 +00:00
Remove the old shaders
This commit is contained in:
parent
ee00ce86cc
commit
cfa3f8ecc4
29 changed files with 0 additions and 1895 deletions
|
@ -1,14 +0,0 @@
|
|||
|
||||
layout(location=0) in vec4 vTexCoord;
|
||||
layout(location=1) in vec4 vColor;
|
||||
layout(location=0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 frag = vColor;
|
||||
|
||||
vec4 t1 = texture(tex, vTexCoord.xy);
|
||||
vec4 t2 = texture(texture2, vec2(vTexCoord.x, 1.0-vTexCoord.y));
|
||||
|
||||
FragColor = frag * vec4(t1.r, t1.g, t1.b, t2.a);
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
layout(location=2) in vec4 pixelpos;
|
||||
layout(location=0) out vec4 FragColor;
|
||||
#ifdef GBUFFER_PASS
|
||||
layout(location=1) out vec4 FragFog;
|
||||
layout(location=2) out vec4 FragNormal;
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Main shader routine
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void main()
|
||||
{
|
||||
float fogdist;
|
||||
float fogfactor;
|
||||
|
||||
//
|
||||
// calculate fog factor
|
||||
//
|
||||
if (uFogEnabled == -1)
|
||||
{
|
||||
fogdist = pixelpos.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz));
|
||||
}
|
||||
fogfactor = exp2 (uFogDensity * fogdist);
|
||||
FragColor = vec4(uFogColor.rgb, 1.0 - fogfactor);
|
||||
#ifdef GBUFFER_PASS
|
||||
FragFog = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
FragNormal = vec4(0.5, 0.5, 0.5, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
vec4 ProcessLight(Material material, vec4 color)
|
||||
{
|
||||
return color;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
void SetupMaterial(inout Material material)
|
||||
{
|
||||
material.Base = ProcessTexel();
|
||||
material.Normal = ApplyNormalMap(vTexCoord.st);
|
||||
material.Bright = texture(brighttexture, vTexCoord.st);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
void SetupMaterial(inout Material material)
|
||||
{
|
||||
vec2 texCoord = GetTexCoord();
|
||||
SetMaterialProps(material, texCoord);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
void SetupMaterial(inout Material material)
|
||||
{
|
||||
SetMaterialProps(material, vTexCoord.st);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
return desaturate(uObjectColor);
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
float index = getTexel(vTexCoord.st).r;
|
||||
index = ((index * 255.0) + 0.5) / 256.0;
|
||||
vec4 tex = texture(texture2, vec2(index, 0.5));
|
||||
tex.a = 1.0;
|
||||
return tex;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
void SetupMaterial(inout Material material)
|
||||
{
|
||||
SetMaterialProps(material, vTexCoord.st);
|
||||
material.Metallic = texture(metallictexture, vTexCoord.st).r;
|
||||
material.Roughness = texture(roughnesstexture, vTexCoord.st).r;
|
||||
material.AO = texture(aotexture, vTexCoord.st).r;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
void SetupMaterial(inout Material material)
|
||||
{
|
||||
SetMaterialProps(material, vTexCoord.st);
|
||||
material.Specular = texture(speculartexture, vTexCoord.st).rgb;
|
||||
material.Glossiness = uSpecularMaterial.x;
|
||||
material.SpecularLevel = uSpecularMaterial.y;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
|
||||
vec2 GetTexCoord()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
|
||||
const float pi = 3.14159265358979323846;
|
||||
vec2 offset = vec2(0,0);
|
||||
|
||||
offset.y = sin(pi * 2.0 * (texCoord.x + timer * 0.125)) * 0.1;
|
||||
offset.x = sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1;
|
||||
|
||||
return texCoord + offset;
|
||||
}
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
return getTexel(GetTexCoord());
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
|
||||
vec2 GetTexCoord()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
|
||||
const float pi = 3.14159265358979323846;
|
||||
vec2 offset = vec2(0.0,0.0);
|
||||
|
||||
offset.y = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.61 + 900.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.36 + 300.0/8192.0));
|
||||
offset.x = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.49 + 700.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.49 + 1200.0/8192.0));
|
||||
|
||||
return texCoord + offset * 0.025;
|
||||
}
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
return getTexel(GetTexCoord());
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
|
||||
vec2 GetTexCoord()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
|
||||
const float pi = 3.14159265358979323846;
|
||||
vec2 offset = vec2(0.0,0.0);
|
||||
|
||||
float siny = sin(pi * 2.0 * (texCoord.y * 2.0 + timer * 0.75)) * 0.03;
|
||||
offset.y = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.75)) * 0.03;
|
||||
offset.x = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.45)) * 0.02;
|
||||
|
||||
return texCoord + offset;
|
||||
}
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
return getTexel(GetTexCoord());
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
vec2 GetTexCoord()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
|
||||
const float pi = 3.14159265358979323846;
|
||||
|
||||
texCoord.x += sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1;
|
||||
|
||||
return texCoord;
|
||||
}
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
return getTexel(GetTexCoord());
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
//created by Evil Space Tomato
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
|
||||
vec2 texSplat;
|
||||
const float pi = 3.14159265358979323846;
|
||||
texSplat.x = texCoord.x + mod(sin(pi * 2.0 * (texCoord.y + timer * 2.0)),0.1) * 0.1;
|
||||
texSplat.y = texCoord.y + mod(cos(pi * 2.0 * (texCoord.x + timer * 2.0)),0.1) * 0.1;
|
||||
|
||||
vec4 basicColor = getTexel(texSplat);
|
||||
|
||||
float texX = sin(texCoord.x * 100.0 + timer*5.0);
|
||||
float texY = cos(texCoord.x * 100.0 + timer*5.0);
|
||||
float vX = (texX/texY)*21.0;
|
||||
float vY = (texY/texX)*13.0;
|
||||
|
||||
float test = mod(timer*2.0+(vX + vY), 0.5);
|
||||
|
||||
basicColor.a = basicColor.a * test;
|
||||
|
||||
return basicColor;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
//created by Evil Space Tomato
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
vec4 basicColor = getTexel(texCoord);
|
||||
vec2 texSize = vec2(textureSize(tex, 0));
|
||||
|
||||
texCoord.x = float( int(texCoord.x * texSize.x) ) / texSize.x;
|
||||
texCoord.y = float( int(texCoord.y * texSize.y) ) / texSize.y;
|
||||
|
||||
float texX = sin(mod(texCoord.x * 100.0 + timer*5.0, 3.489)) + texCoord.x / 4.0;
|
||||
float texY = cos(mod(texCoord.y * 100.0 + timer*5.0, 3.489)) + texCoord.y / 4.0;
|
||||
float vX = (texX/texY)*21.0;
|
||||
float vY = (texY/texX)*13.0;
|
||||
|
||||
float test = mod(timer*2.0+(vX + vY), 0.5);
|
||||
basicColor.a = basicColor.a * test;
|
||||
basicColor.rgb = vec3(0.0,0.0,0.0);
|
||||
return basicColor;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
//created by Evil Space Tomato
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
vec4 basicColor = getTexel(texCoord);
|
||||
|
||||
float texX = texCoord.x / 3.0 + 0.66;
|
||||
float texY = 0.34 - texCoord.y / 3.0;
|
||||
float vX = (texX/texY)*21.0;
|
||||
float vY = (texY/texX)*13.0;
|
||||
float test = mod(timer*2.0+(vX + vY), 0.5);
|
||||
|
||||
basicColor.a = basicColor.a * test;
|
||||
basicColor.r = basicColor.g = basicColor.b = 0.0;
|
||||
|
||||
return basicColor;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
//created by Evil Space Tomato
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
vec4 basicColor = getTexel(texCoord);
|
||||
|
||||
float texX = sin(mod(texCoord.x * 100.0 + timer*5.0, 3.489)) + texCoord.x / 4.0;
|
||||
float texY = cos(mod(texCoord.y * 100.0 + timer*5.0, 3.489)) + texCoord.y / 4.0;
|
||||
float vX = (texX/texY)*21.0;
|
||||
float vY = (texY/texX)*13.0;
|
||||
|
||||
|
||||
float test = mod(timer*2.0+(vX + vY), 0.5);
|
||||
basicColor.a = basicColor.a * test;
|
||||
|
||||
basicColor.rgb = vec3(0.0,0.0,0.0);
|
||||
return basicColor;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
//created by Evil Space Tomato
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
vec4 basicColor = getTexel(texCoord);
|
||||
|
||||
float texX = sin(texCoord.x * 100.0 + timer*5.0);
|
||||
float texY = cos(texCoord.x * 100.0 + timer*5.0);
|
||||
float vX = (texX/texY)*21.0;
|
||||
float vY = (texY/texX)*13.0;
|
||||
|
||||
float test = mod(timer*2.0+(vX + vY), 0.5);
|
||||
|
||||
basicColor.a = basicColor.a * test;
|
||||
|
||||
return basicColor;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Fuzz effect as rendered by the software renderer
|
||||
|
||||
#define FUZZTABLE 50
|
||||
#define FUZZ_RANDOM_X_SIZE 100
|
||||
#define FRACBITS 16
|
||||
#define fixed_t int
|
||||
|
||||
int fuzz_random_x_offset[FUZZ_RANDOM_X_SIZE] = int[]
|
||||
(
|
||||
75, 76, 21, 91, 56, 33, 62, 99, 61, 79,
|
||||
95, 54, 41, 18, 69, 43, 49, 59, 10, 84,
|
||||
94, 17, 57, 46, 9, 39, 55, 34,100, 81,
|
||||
73, 88, 92, 3, 63, 36, 7, 28, 13, 80,
|
||||
16, 96, 78, 29, 71, 58, 89, 24, 1, 35,
|
||||
52, 82, 4, 14, 22, 53, 38, 66, 12, 72,
|
||||
90, 44, 77, 83, 6, 27, 48, 30, 42, 32,
|
||||
65, 15, 97, 20, 67, 74, 98, 85, 60, 68,
|
||||
19, 26, 8, 87, 86, 64, 11, 37, 31, 47,
|
||||
25, 5, 50, 51, 23, 2, 93, 70, 40, 45
|
||||
);
|
||||
|
||||
int fuzzoffset[FUZZTABLE] = int[]
|
||||
(
|
||||
6, 11, 6, 11, 6, 6, 11, 6, 6, 11,
|
||||
6, 6, 6, 11, 6, 6, 6, 11, 15, 18,
|
||||
21, 6, 11, 15, 6, 6, 6, 6, 11, 6,
|
||||
11, 6, 6, 11, 15, 6, 6, 11, 15, 18,
|
||||
21, 6, 6, 6, 6, 11, 6, 6, 11, 6
|
||||
);
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
vec4 basicColor = getTexel(texCoord);
|
||||
|
||||
// Ideally fuzzpos would be an uniform and differ from each sprite so that overlapping demons won't get the same shade for the same pixel
|
||||
int next_random = int(abs(mod(timer * 35.0, float(FUZZ_RANDOM_X_SIZE))));
|
||||
int fuzzpos = (/*fuzzpos +*/ fuzz_random_x_offset[next_random] * FUZZTABLE / 100) % FUZZTABLE;
|
||||
|
||||
int x = int(gl_FragCoord.x);
|
||||
int y = int(gl_FragCoord.y);
|
||||
|
||||
fixed_t fuzzscale = (200 << FRACBITS) / uViewHeight;
|
||||
int scaled_x = (x * fuzzscale) >> FRACBITS;
|
||||
int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos;
|
||||
fixed_t fuzzcount = FUZZTABLE << FRACBITS;
|
||||
fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount;
|
||||
float alpha = float(fuzzoffset[fuzz >> FRACBITS]) / 32.0;
|
||||
|
||||
return vec4(0.0, 0.0, 0.0, basicColor.a * alpha);
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
//created by Evil Space Tomato
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
vec4 basicColor = getTexel(texCoord);
|
||||
vec2 texSize = vec2(textureSize(tex, 0));
|
||||
|
||||
texCoord.x = float( int(texCoord.x * texSize.x) ) / texSize.x;
|
||||
texCoord.y = float( int(texCoord.y * texSize.y) ) / texSize.y;
|
||||
|
||||
float texX = texCoord.x / 3.0 + 0.66;
|
||||
float texY = 0.34 - texCoord.y / 3.0;
|
||||
float vX = (texX/texY)*21.0;
|
||||
float vY = (texY/texX)*13.0;
|
||||
float test = mod(timer*2.0+(vX + vY), 0.5);
|
||||
|
||||
basicColor.a = basicColor.a * test;
|
||||
basicColor.r = basicColor.g = basicColor.b = 0.0;
|
||||
|
||||
return basicColor;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
//created by Evil Space Tomato
|
||||
|
||||
vec4 ProcessTexel()
|
||||
{
|
||||
vec2 texCoord = vTexCoord.st;
|
||||
vec4 basicColor = getTexel(texCoord);
|
||||
|
||||
float texX = sin(texCoord.x * 100.0 + timer*5.0);
|
||||
float texY = cos(texCoord.x * 100.0 + timer*5.0);
|
||||
float vX = (texX/texY)*21.0;
|
||||
float vY = (texY/texX)*13.0;
|
||||
float test = mod(timer*2.0+(vX + vY), 0.5);
|
||||
|
||||
basicColor.a = basicColor.a * test;
|
||||
basicColor.r = basicColor.g = basicColor.b = 0.0;
|
||||
|
||||
return basicColor;
|
||||
}
|
|
@ -1,883 +0,0 @@
|
|||
|
||||
|
||||
layout(location = 0) in vec4 vTexCoord;
|
||||
layout(location = 1) in vec4 vColor;
|
||||
layout(location = 2) in vec4 pixelpos;
|
||||
layout(location = 3) in vec3 glowdist;
|
||||
layout(location = 4) in vec3 gradientdist;
|
||||
layout(location = 5) in vec4 vWorldNormal;
|
||||
layout(location = 6) in vec4 vEyeNormal;
|
||||
layout(location = 9) in vec3 vLightmap;
|
||||
|
||||
#ifdef NO_CLIPDISTANCE_SUPPORT
|
||||
layout(location = 7) in vec4 ClipDistanceA;
|
||||
layout(location = 8) in vec4 ClipDistanceB;
|
||||
#endif
|
||||
|
||||
layout(location=0) out vec4 FragColor;
|
||||
#ifdef GBUFFER_PASS
|
||||
layout(location=1) out vec4 FragFog;
|
||||
layout(location=2) out vec4 FragNormal;
|
||||
#endif
|
||||
|
||||
struct Material
|
||||
{
|
||||
vec4 Base;
|
||||
vec4 Bright;
|
||||
vec4 Glow;
|
||||
vec3 Normal;
|
||||
vec3 Specular;
|
||||
float Glossiness;
|
||||
float SpecularLevel;
|
||||
float Metallic;
|
||||
float Roughness;
|
||||
float AO;
|
||||
};
|
||||
|
||||
vec4 Process(vec4 color);
|
||||
vec4 ProcessTexel();
|
||||
Material ProcessMaterial(); // note that this is deprecated. Use SetupMaterial!
|
||||
void SetupMaterial(inout Material mat);
|
||||
vec4 ProcessLight(Material mat, vec4 color);
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color);
|
||||
vec2 GetTexCoord();
|
||||
|
||||
// These get Or'ed into uTextureMode because it only uses its 3 lowermost bits.
|
||||
const int TEXF_Brightmap = 0x10000;
|
||||
const int TEXF_Detailmap = 0x20000;
|
||||
const int TEXF_Glowmap = 0x40000;
|
||||
const int TEXF_ClampY = 0x80000;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Color to grayscale
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
float grayscale(vec4 color)
|
||||
{
|
||||
return dot(color.rgb, vec3(0.3, 0.56, 0.14));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Desaturate a color
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
vec4 dodesaturate(vec4 texel, float factor)
|
||||
{
|
||||
if (factor != 0.0)
|
||||
{
|
||||
float gray = grayscale(texel);
|
||||
return mix (texel, vec4(gray,gray,gray,texel.a), factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return texel;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Desaturate a color
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
vec4 desaturate(vec4 texel)
|
||||
{
|
||||
return dodesaturate(texel, uDesaturationFactor);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Texture tinting code originally from JFDuke but with a few more options
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
const int Tex_Blend_Alpha = 1;
|
||||
const int Tex_Blend_Screen = 2;
|
||||
const int Tex_Blend_Overlay = 3;
|
||||
const int Tex_Blend_Hardlight = 4;
|
||||
|
||||
vec4 ApplyTextureManipulation(vec4 texel, int blendflags)
|
||||
{
|
||||
// Step 1: desaturate according to the material's desaturation factor.
|
||||
texel = dodesaturate(texel, uTextureModulateColor.a);
|
||||
|
||||
// Step 2: Invert if requested
|
||||
if ((blendflags & 8) != 0)
|
||||
{
|
||||
texel.rgb = vec3(1.0 - texel.r, 1.0 - texel.g, 1.0 - texel.b);
|
||||
}
|
||||
|
||||
// Step 3: Apply additive color
|
||||
texel.rgb += uTextureAddColor.rgb;
|
||||
|
||||
// Step 4: Colorization, including gradient if set.
|
||||
texel.rgb *= uTextureModulateColor.rgb;
|
||||
|
||||
// Before applying the blend the value needs to be clamped to [0..1] range.
|
||||
texel.rgb = clamp(texel.rgb, 0.0, 1.0);
|
||||
|
||||
// Step 5: Apply a blend. This may just be a translucent overlay or one of the blend modes present in current Build engines.
|
||||
if ((blendflags & 7) != 0)
|
||||
{
|
||||
vec3 tcol = texel.rgb * 255.0; // * 255.0 to make it easier to reuse the integer math.
|
||||
vec4 tint = uTextureBlendColor * 255.0;
|
||||
|
||||
switch (blendflags & 7)
|
||||
{
|
||||
default:
|
||||
tcol.b = tcol.b * (1.0 - uTextureBlendColor.a) + tint.b * uTextureBlendColor.a;
|
||||
tcol.g = tcol.g * (1.0 - uTextureBlendColor.a) + tint.g * uTextureBlendColor.a;
|
||||
tcol.r = tcol.r * (1.0 - uTextureBlendColor.a) + tint.r * uTextureBlendColor.a;
|
||||
break;
|
||||
// The following 3 are taken 1:1 from the Build engine
|
||||
case Tex_Blend_Screen:
|
||||
tcol.b = 255.0 - (((255.0 - tcol.b) * (255.0 - tint.r)) / 256.0);
|
||||
tcol.g = 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 256.0);
|
||||
tcol.r = 255.0 - (((255.0 - tcol.r) * (255.0 - tint.b)) / 256.0);
|
||||
break;
|
||||
case Tex_Blend_Overlay:
|
||||
tcol.b = tcol.b < 128.0? (tcol.b * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.b)) / 128.0);
|
||||
tcol.g = tcol.g < 128.0? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0);
|
||||
tcol.r = tcol.r < 128.0? (tcol.r * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.r)) / 128.0);
|
||||
break;
|
||||
case Tex_Blend_Hardlight:
|
||||
tcol.b = tint.b < 128.0 ? (tcol.b * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.b)) / 128.0);
|
||||
tcol.g = tint.g < 128.0 ? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0);
|
||||
tcol.r = tint.r < 128.0 ? (tcol.r * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.r)) / 128.0);
|
||||
break;
|
||||
}
|
||||
texel.rgb = tcol / 255.0;
|
||||
}
|
||||
return texel;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// This function is common for all (non-special-effect) fragment shaders
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
vec4 getTexel(vec2 st)
|
||||
{
|
||||
vec4 texel = texture(tex, st);
|
||||
|
||||
//
|
||||
// Apply texture modes
|
||||
//
|
||||
switch (uTextureMode & 0xffff)
|
||||
{
|
||||
case 1: // TM_STENCIL
|
||||
texel.rgb = vec3(1.0,1.0,1.0);
|
||||
break;
|
||||
|
||||
case 2: // TM_OPAQUE
|
||||
texel.a = 1.0;
|
||||
break;
|
||||
|
||||
case 3: // TM_INVERSE
|
||||
texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, texel.a);
|
||||
break;
|
||||
|
||||
case 4: // TM_ALPHATEXTURE
|
||||
{
|
||||
float gray = grayscale(texel);
|
||||
texel = vec4(1.0, 1.0, 1.0, gray*texel.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // TM_CLAMPY
|
||||
if (st.t < 0.0 || st.t > 1.0)
|
||||
{
|
||||
texel.a = 0.0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: // TM_OPAQUEINVERSE
|
||||
texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, 1.0);
|
||||
break;
|
||||
|
||||
case 7: //TM_FOGLAYER
|
||||
return texel;
|
||||
|
||||
}
|
||||
|
||||
if ((uTextureMode & TEXF_ClampY) != 0)
|
||||
{
|
||||
if (st.t < 0.0 || st.t > 1.0)
|
||||
{
|
||||
texel.a = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the texture modification colors.
|
||||
int blendflags = int(uTextureAddColor.a); // this alpha is unused otherwise
|
||||
if (blendflags != 0)
|
||||
{
|
||||
// only apply the texture manipulation if it contains something.
|
||||
texel = ApplyTextureManipulation(texel, blendflags);
|
||||
}
|
||||
|
||||
// Apply the Doom64 style material colors on top of everything from the texture modification settings.
|
||||
// This may be a bit redundant in terms of features but the data comes from different sources so this is unavoidable.
|
||||
texel.rgb += uAddColor.rgb;
|
||||
if (uObjectColor2.a == 0.0) texel *= uObjectColor;
|
||||
else texel *= mix(uObjectColor, uObjectColor2, gradientdist.z);
|
||||
|
||||
// Last but not least apply the desaturation from the sector's light.
|
||||
return desaturate(texel);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Vanilla Doom wall colormap equation
|
||||
//
|
||||
//===========================================================================
|
||||
float R_WallColormap(float lightnum, float z, vec3 normal)
|
||||
{
|
||||
// R_ScaleFromGlobalAngle calculation
|
||||
float projection = 160.0; // projection depends on SCREENBLOCKS!! 160 is the fullscreen value
|
||||
vec2 line_v1 = pixelpos.xz; // in vanilla this is the first curline vertex
|
||||
vec2 line_normal = normal.xz;
|
||||
float texscale = projection * clamp(dot(normalize(uCameraPos.xz - line_v1), line_normal), 0.0, 1.0) / z;
|
||||
|
||||
float lightz = clamp(16.0 * texscale, 0.0, 47.0);
|
||||
|
||||
// scalelight[lightnum][lightz] lookup
|
||||
float startmap = (15.0 - lightnum) * 4.0;
|
||||
return startmap - lightz * 0.5;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Vanilla Doom plane colormap equation
|
||||
//
|
||||
//===========================================================================
|
||||
float R_PlaneColormap(float lightnum, float z)
|
||||
{
|
||||
float lightz = clamp(z / 16.0f, 0.0, 127.0);
|
||||
|
||||
// zlight[lightnum][lightz] lookup
|
||||
float startmap = (15.0 - lightnum) * 4.0;
|
||||
float scale = 160.0 / (lightz + 1.0);
|
||||
return startmap - scale * 0.5;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// zdoom colormap equation
|
||||
//
|
||||
//===========================================================================
|
||||
float R_ZDoomColormap(float light, float z)
|
||||
{
|
||||
float L = light * 255.0;
|
||||
float vis = min(uGlobVis / z, 24.0 / 32.0);
|
||||
float shade = 2.0 - (L + 12.0) / 128.0;
|
||||
float lightscale = shade - vis;
|
||||
return lightscale * 31.0;
|
||||
}
|
||||
|
||||
float R_DoomColormap(float light, float z)
|
||||
{
|
||||
if ((uPalLightLevels >> 16) == 16) // gl_lightmode 16
|
||||
{
|
||||
float lightnum = clamp(light * 15.0, 0.0, 15.0);
|
||||
|
||||
if (dot(vWorldNormal.xyz, vWorldNormal.xyz) > 0.5)
|
||||
{
|
||||
vec3 normal = normalize(vWorldNormal.xyz);
|
||||
return mix(R_WallColormap(lightnum, z, normal), R_PlaneColormap(lightnum, z), abs(normal.y));
|
||||
}
|
||||
else // vWorldNormal is not set on sprites
|
||||
{
|
||||
return R_PlaneColormap(lightnum, z);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return R_ZDoomColormap(light, z);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Doom software lighting equation
|
||||
//
|
||||
//===========================================================================
|
||||
float R_DoomLightingEquation(float light)
|
||||
{
|
||||
// z is the depth in view space, positive going into the screen
|
||||
float z;
|
||||
if (((uPalLightLevels >> 8) & 0xff) == 2)
|
||||
{
|
||||
z = distance(pixelpos.xyz, uCameraPos.xyz);
|
||||
}
|
||||
else
|
||||
{
|
||||
z = pixelpos.w;
|
||||
}
|
||||
|
||||
if ((uPalLightLevels >> 16) == 5) // gl_lightmode 5: Build software lighting emulation.
|
||||
{
|
||||
// This is a lot more primitive than Doom's lighting...
|
||||
float numShades = float(uPalLightLevels & 255);
|
||||
float curshade = (1.0 - light) * (numShades - 1.0);
|
||||
float visibility = max(uGlobVis * uLightFactor * z, 0.0);
|
||||
float shade = clamp((curshade + visibility), 0.0, numShades - 1.0);
|
||||
return clamp(shade * uLightDist, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float colormap = R_DoomColormap(light, z);
|
||||
|
||||
if ((uPalLightLevels & 0xff) != 0)
|
||||
colormap = floor(colormap) + 0.5;
|
||||
|
||||
// Result is the normalized colormap index (0 bright .. 1 dark)
|
||||
return clamp(colormap, 0.0, 31.0) / 32.0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Check if light is in shadow
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
#ifdef SUPPORTS_RAYTRACING
|
||||
|
||||
bool traceHit(vec3 origin, vec3 direction, float dist)
|
||||
{
|
||||
rayQueryEXT rayQuery;
|
||||
rayQueryInitializeEXT(rayQuery, TopLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, 0.01f, direction, dist);
|
||||
while(rayQueryProceedEXT(rayQuery)) { }
|
||||
return rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT;
|
||||
}
|
||||
|
||||
vec2 softshadow[9 * 3] = vec2[](
|
||||
vec2( 0.0, 0.0),
|
||||
vec2(-2.0,-2.0),
|
||||
vec2( 2.0, 2.0),
|
||||
vec2( 2.0,-2.0),
|
||||
vec2(-2.0, 2.0),
|
||||
vec2(-1.0,-1.0),
|
||||
vec2( 1.0, 1.0),
|
||||
vec2( 1.0,-1.0),
|
||||
vec2(-1.0, 1.0),
|
||||
|
||||
vec2( 0.0, 0.0),
|
||||
vec2(-1.5,-1.5),
|
||||
vec2( 1.5, 1.5),
|
||||
vec2( 1.5,-1.5),
|
||||
vec2(-1.5, 1.5),
|
||||
vec2(-0.5,-0.5),
|
||||
vec2( 0.5, 0.5),
|
||||
vec2( 0.5,-0.5),
|
||||
vec2(-0.5, 0.5),
|
||||
|
||||
vec2( 0.0, 0.0),
|
||||
vec2(-1.25,-1.75),
|
||||
vec2( 1.75, 1.25),
|
||||
vec2( 1.25,-1.75),
|
||||
vec2(-1.75, 1.75),
|
||||
vec2(-0.75,-0.25),
|
||||
vec2( 0.25, 0.75),
|
||||
vec2( 0.75,-0.25),
|
||||
vec2(-0.25, 0.75)
|
||||
);
|
||||
|
||||
float traceShadow(vec4 lightpos, int quality)
|
||||
{
|
||||
vec3 origin = pixelpos.xzy;
|
||||
vec3 target = lightpos.xzy + 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes
|
||||
|
||||
vec3 direction = normalize(target - origin);
|
||||
float dist = distance(origin, target);
|
||||
|
||||
if (quality == 0)
|
||||
{
|
||||
return traceHit(origin, direction, dist) ? 0.0 : 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec3 v = (abs(direction.x) > abs(direction.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 xdir = normalize(cross(direction, v));
|
||||
vec3 ydir = cross(direction, xdir);
|
||||
|
||||
float sum = 0.0;
|
||||
int step_count = quality * 9;
|
||||
for (int i = 0; i <= step_count; i++)
|
||||
{
|
||||
vec3 pos = target + xdir * softshadow[i].x + ydir * softshadow[i].y;
|
||||
sum += traceHit(origin, normalize(pos - origin), dist) ? 0.0 : 1.0;
|
||||
}
|
||||
return sum / step_count;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float traceShadow(vec4 lightpos, int quality)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORTS_SHADOWMAPS
|
||||
|
||||
float shadowDirToU(vec2 dir)
|
||||
{
|
||||
if (abs(dir.y) > abs(dir.x))
|
||||
{
|
||||
float x = dir.x / dir.y * 0.125;
|
||||
if (dir.y >= 0.0)
|
||||
return 0.125 + x;
|
||||
else
|
||||
return (0.50 + 0.125) + x;
|
||||
}
|
||||
else
|
||||
{
|
||||
float y = dir.y / dir.x * 0.125;
|
||||
if (dir.x >= 0.0)
|
||||
return (0.25 + 0.125) - y;
|
||||
else
|
||||
return (0.75 + 0.125) - y;
|
||||
}
|
||||
}
|
||||
|
||||
vec2 shadowUToDir(float u)
|
||||
{
|
||||
u *= 4.0;
|
||||
vec2 raydir;
|
||||
switch (int(u))
|
||||
{
|
||||
case 0: raydir = vec2(u * 2.0 - 1.0, 1.0); break;
|
||||
case 1: raydir = vec2(1.0, 1.0 - (u - 1.0) * 2.0); break;
|
||||
case 2: raydir = vec2(1.0 - (u - 2.0) * 2.0, -1.0); break;
|
||||
case 3: raydir = vec2(-1.0, (u - 3.0) * 2.0 - 1.0); break;
|
||||
}
|
||||
return raydir;
|
||||
}
|
||||
|
||||
float sampleShadowmap(vec3 planePoint, float v)
|
||||
{
|
||||
float bias = 1.0;
|
||||
float negD = dot(vWorldNormal.xyz, planePoint);
|
||||
|
||||
vec3 ray = planePoint;
|
||||
|
||||
vec2 isize = textureSize(ShadowMap, 0);
|
||||
float scale = float(isize.x) * 0.25;
|
||||
|
||||
// Snap to shadow map texel grid
|
||||
if (abs(ray.z) > abs(ray.x))
|
||||
{
|
||||
ray.y = ray.y / abs(ray.z);
|
||||
ray.x = ray.x / abs(ray.z);
|
||||
ray.x = (floor((ray.x + 1.0) * 0.5 * scale) + 0.5) / scale * 2.0 - 1.0;
|
||||
ray.z = sign(ray.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
ray.y = ray.y / abs(ray.x);
|
||||
ray.z = ray.z / abs(ray.x);
|
||||
ray.z = (floor((ray.z + 1.0) * 0.5 * scale) + 0.5) / scale * 2.0 - 1.0;
|
||||
ray.x = sign(ray.x);
|
||||
}
|
||||
|
||||
float t = negD / dot(vWorldNormal.xyz, ray) - bias;
|
||||
vec2 dir = ray.xz * t;
|
||||
|
||||
float u = shadowDirToU(dir);
|
||||
float dist2 = dot(dir, dir);
|
||||
return step(dist2, texture(ShadowMap, vec2(u, v)).x);
|
||||
}
|
||||
|
||||
float sampleShadowmapPCF(vec3 planePoint, float v)
|
||||
{
|
||||
float bias = 1.0;
|
||||
float negD = dot(vWorldNormal.xyz, planePoint);
|
||||
|
||||
vec3 ray = planePoint;
|
||||
|
||||
if (abs(ray.z) > abs(ray.x))
|
||||
ray.y = ray.y / abs(ray.z);
|
||||
else
|
||||
ray.y = ray.y / abs(ray.x);
|
||||
|
||||
vec2 isize = textureSize(ShadowMap, 0);
|
||||
float scale = float(isize.x);
|
||||
float texelPos = floor(shadowDirToU(ray.xz) * scale);
|
||||
|
||||
float sum = 0.0;
|
||||
float step_count = uShadowmapFilter;
|
||||
|
||||
texelPos -= step_count + 0.5;
|
||||
for (float x = -step_count; x <= step_count; x++)
|
||||
{
|
||||
float u = fract(texelPos / scale);
|
||||
vec2 dir = shadowUToDir(u);
|
||||
|
||||
ray.x = dir.x;
|
||||
ray.z = dir.y;
|
||||
float t = negD / dot(vWorldNormal.xyz, ray) - bias;
|
||||
dir = ray.xz * t;
|
||||
|
||||
float dist2 = dot(dir, dir);
|
||||
sum += step(dist2, texture(ShadowMap, vec2(u, v)).x);
|
||||
texelPos++;
|
||||
}
|
||||
return sum / (uShadowmapFilter * 2.0 + 1.0);
|
||||
}
|
||||
|
||||
float shadowmapAttenuation(vec4 lightpos, float shadowIndex)
|
||||
{
|
||||
vec3 planePoint = pixelpos.xyz - lightpos.xyz;
|
||||
planePoint += 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes
|
||||
|
||||
if (dot(planePoint.xz, planePoint.xz) < 1.0)
|
||||
return 1.0; // Light is too close
|
||||
|
||||
float v = (shadowIndex + 0.5) / 1024.0;
|
||||
|
||||
if (uShadowmapFilter == 0)
|
||||
{
|
||||
return sampleShadowmap(planePoint, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
return sampleShadowmapPCF(planePoint, v);
|
||||
}
|
||||
}
|
||||
|
||||
float shadowAttenuation(vec4 lightpos, float lightcolorA)
|
||||
{
|
||||
float shadowIndex = abs(lightcolorA) - 1.0;
|
||||
if (shadowIndex >= 1024.0)
|
||||
return 1.0; // No shadowmap available for this light
|
||||
|
||||
if (uShadowmapFilter < 0)
|
||||
return traceShadow(lightpos, 1 - uShadowmapFilter);
|
||||
|
||||
return shadowmapAttenuation(lightpos, shadowIndex);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float shadowAttenuation(vec4 lightpos, float lightcolorA)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle)
|
||||
{
|
||||
vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz);
|
||||
float cosDir = dot(lightDirection, spotdir);
|
||||
return smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Adjust normal vector according to the normal map
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
#if defined(NORMALMAP)
|
||||
mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv)
|
||||
{
|
||||
// get edge vectors of the pixel triangle
|
||||
vec3 dp1 = dFdx(p);
|
||||
vec3 dp2 = dFdy(p);
|
||||
vec2 duv1 = dFdx(uv);
|
||||
vec2 duv2 = dFdy(uv);
|
||||
|
||||
// solve the linear system
|
||||
vec3 dp2perp = cross(n, dp2); // cross(dp2, n);
|
||||
vec3 dp1perp = cross(dp1, n); // cross(n, dp1);
|
||||
vec3 t = dp2perp * duv1.x + dp1perp * duv2.x;
|
||||
vec3 b = dp2perp * duv1.y + dp1perp * duv2.y;
|
||||
|
||||
// construct a scale-invariant frame
|
||||
float invmax = inversesqrt(max(dot(t,t), dot(b,b)));
|
||||
return mat3(t * invmax, b * invmax, n);
|
||||
}
|
||||
|
||||
vec3 ApplyNormalMap(vec2 texcoord)
|
||||
{
|
||||
#define WITH_NORMALMAP_UNSIGNED
|
||||
#define WITH_NORMALMAP_GREEN_UP
|
||||
//#define WITH_NORMALMAP_2CHANNEL
|
||||
|
||||
vec3 interpolatedNormal = normalize(vWorldNormal.xyz);
|
||||
|
||||
vec3 map = texture(normaltexture, texcoord).xyz;
|
||||
#if defined(WITH_NORMALMAP_UNSIGNED)
|
||||
map = map * 255./127. - 128./127.; // Math so "odd" because 0.5 cannot be precisely described in an unsigned format
|
||||
#endif
|
||||
#if defined(WITH_NORMALMAP_2CHANNEL)
|
||||
map.z = sqrt(1 - dot(map.xy, map.xy));
|
||||
#endif
|
||||
#if defined(WITH_NORMALMAP_GREEN_UP)
|
||||
map.y = -map.y;
|
||||
#endif
|
||||
|
||||
mat3 tbn = cotangent_frame(interpolatedNormal, pixelpos.xyz, vTexCoord.st);
|
||||
vec3 bumpedNormal = normalize(tbn * map);
|
||||
return bumpedNormal;
|
||||
}
|
||||
#else
|
||||
vec3 ApplyNormalMap(vec2 texcoord)
|
||||
{
|
||||
return normalize(vWorldNormal.xyz);
|
||||
}
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Sets the common material properties.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void SetMaterialProps(inout Material material, vec2 texCoord)
|
||||
{
|
||||
#ifdef NPOT_EMULATION
|
||||
if (uNpotEmulation.y != 0.0)
|
||||
{
|
||||
float period = floor(texCoord.t / uNpotEmulation.y);
|
||||
texCoord.s += uNpotEmulation.x * floor(mod(texCoord.t, uNpotEmulation.y));
|
||||
texCoord.t = period + mod(texCoord.t, uNpotEmulation.y);
|
||||
}
|
||||
#endif
|
||||
material.Base = getTexel(texCoord.st);
|
||||
material.Normal = ApplyNormalMap(texCoord.st);
|
||||
|
||||
// OpenGL doesn't care, but Vulkan pukes all over the place if these texture samplings are included in no-texture shaders, even though never called.
|
||||
#ifndef NO_LAYERS
|
||||
if ((uTextureMode & TEXF_Brightmap) != 0)
|
||||
material.Bright = desaturate(texture(brighttexture, texCoord.st));
|
||||
|
||||
if ((uTextureMode & TEXF_Detailmap) != 0)
|
||||
{
|
||||
vec4 Detail = texture(detailtexture, texCoord.st * uDetailParms.xy) * uDetailParms.z;
|
||||
material.Base.rgb *= Detail.rgb;
|
||||
}
|
||||
|
||||
if ((uTextureMode & TEXF_Glowmap) != 0)
|
||||
material.Glow = desaturate(texture(glowtexture, texCoord.st));
|
||||
#endif
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Calculate light
|
||||
//
|
||||
// It is important to note that the light color is not desaturated
|
||||
// due to ZDoom's implementation weirdness. Everything that's added
|
||||
// on top of it, e.g. dynamic lights and glows are, though, because
|
||||
// the objects emitting these lights are also.
|
||||
//
|
||||
// This is making this a bit more complicated than it needs to
|
||||
// because we can't just desaturate the final fragment color.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
vec4 getLightColor(Material material, float fogdist, float fogfactor)
|
||||
{
|
||||
vec4 color = vColor;
|
||||
|
||||
if (uLightLevel >= 0.0)
|
||||
{
|
||||
float newlightlevel = 1.0 - R_DoomLightingEquation(uLightLevel);
|
||||
color.rgb *= newlightlevel;
|
||||
}
|
||||
else if (uFogEnabled > 0)
|
||||
{
|
||||
// brightening around the player for light mode 2
|
||||
if (fogdist < uLightDist)
|
||||
{
|
||||
color.rgb *= uLightFactor - (fogdist / uLightDist) * (uLightFactor - 1.0);
|
||||
}
|
||||
|
||||
//
|
||||
// apply light diminishing through fog equation
|
||||
//
|
||||
color.rgb = mix(vec3(0.0, 0.0, 0.0), color.rgb, fogfactor);
|
||||
}
|
||||
|
||||
//
|
||||
// handle glowing walls
|
||||
//
|
||||
if (uGlowTopColor.a > 0.0 && glowdist.x < uGlowTopColor.a)
|
||||
{
|
||||
color.rgb += desaturate(uGlowTopColor * (1.0 - glowdist.x / uGlowTopColor.a)).rgb;
|
||||
}
|
||||
if (uGlowBottomColor.a > 0.0 && glowdist.y < uGlowBottomColor.a)
|
||||
{
|
||||
color.rgb += desaturate(uGlowBottomColor * (1.0 - glowdist.y / uGlowBottomColor.a)).rgb;
|
||||
}
|
||||
color = min(color, 1.0);
|
||||
|
||||
// these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set.
|
||||
#if !defined LEGACY_USER_SHADER && !defined NO_LAYERS
|
||||
//
|
||||
// apply glow
|
||||
//
|
||||
color.rgb = mix(color.rgb, material.Glow.rgb, material.Glow.a);
|
||||
|
||||
//
|
||||
// apply brightmaps
|
||||
//
|
||||
color.rgb = min(color.rgb + material.Bright.rgb, 1.0);
|
||||
#endif
|
||||
|
||||
//
|
||||
// apply other light manipulation by custom shaders, default is a NOP.
|
||||
//
|
||||
color = ProcessLight(material, color);
|
||||
|
||||
//
|
||||
// apply lightmaps
|
||||
//
|
||||
if (vLightmap.z >= 0.0)
|
||||
{
|
||||
color.rgb += texture(LightMap, vLightmap).rgb;
|
||||
}
|
||||
|
||||
//
|
||||
// apply dynamic lights
|
||||
//
|
||||
return vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Applies colored fog
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
vec4 applyFog(vec4 frag, float fogfactor)
|
||||
{
|
||||
return vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// The color of the fragment if it is fully occluded by ambient lighting
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
vec3 AmbientOcclusionColor()
|
||||
{
|
||||
float fogdist;
|
||||
float fogfactor;
|
||||
|
||||
//
|
||||
// calculate fog factor
|
||||
//
|
||||
if (uFogEnabled == -1)
|
||||
{
|
||||
fogdist = max(16.0, pixelpos.w);
|
||||
}
|
||||
else
|
||||
{
|
||||
fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz));
|
||||
}
|
||||
fogfactor = exp2 (uFogDensity * fogdist);
|
||||
|
||||
return mix(uFogColor.rgb, vec3(0.0), fogfactor);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Main shader routine
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef NO_CLIPDISTANCE_SUPPORT
|
||||
if (ClipDistanceA.x < 0 || ClipDistanceA.y < 0 || ClipDistanceA.z < 0 || ClipDistanceA.w < 0 || ClipDistanceB.x < 0) discard;
|
||||
#endif
|
||||
|
||||
#ifndef LEGACY_USER_SHADER
|
||||
Material material;
|
||||
|
||||
material.Base = vec4(0.0);
|
||||
material.Bright = vec4(0.0);
|
||||
material.Glow = vec4(0.0);
|
||||
material.Normal = vec3(0.0);
|
||||
material.Specular = vec3(0.0);
|
||||
material.Glossiness = 0.0;
|
||||
material.SpecularLevel = 0.0;
|
||||
material.Metallic = 0.0;
|
||||
material.Roughness = 0.0;
|
||||
material.AO = 0.0;
|
||||
SetupMaterial(material);
|
||||
#else
|
||||
Material material = ProcessMaterial();
|
||||
#endif
|
||||
vec4 frag = material.Base;
|
||||
|
||||
#ifndef NO_ALPHATEST
|
||||
if (frag.a <= uAlphaThreshold) discard;
|
||||
#endif
|
||||
|
||||
if (uFogEnabled != -3) // check for special 2D 'fog' mode.
|
||||
{
|
||||
float fogdist = 0.0;
|
||||
float fogfactor = 0.0;
|
||||
|
||||
//
|
||||
// calculate fog factor
|
||||
//
|
||||
if (uFogEnabled != 0)
|
||||
{
|
||||
if (uFogEnabled == 1 || uFogEnabled == -1)
|
||||
{
|
||||
fogdist = max(16.0, pixelpos.w);
|
||||
}
|
||||
else
|
||||
{
|
||||
fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz));
|
||||
}
|
||||
fogfactor = exp2 (uFogDensity * fogdist);
|
||||
}
|
||||
|
||||
if ((uTextureMode & 0xffff) != 7)
|
||||
{
|
||||
frag = getLightColor(material, fogdist, fogfactor);
|
||||
|
||||
//
|
||||
// colored fog
|
||||
//
|
||||
if (uFogEnabled < 0)
|
||||
{
|
||||
frag = applyFog(frag, fogfactor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frag = vec4(uFogColor.rgb, (1.0 - fogfactor) * frag.a * 0.75 * vColor.a);
|
||||
}
|
||||
}
|
||||
else // simple 2D (uses the fog color to add a color overlay)
|
||||
{
|
||||
if ((uTextureMode & 0xffff) == 7)
|
||||
{
|
||||
float gray = grayscale(frag);
|
||||
vec4 cm = (uObjectColor + gray * (uAddColor - uObjectColor)) * 2;
|
||||
frag = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a);
|
||||
}
|
||||
frag = frag * ProcessLight(material, vColor);
|
||||
frag.rgb = frag.rgb + uFogColor.rgb;
|
||||
}
|
||||
FragColor = frag;
|
||||
#ifdef GBUFFER_PASS
|
||||
FragFog = vec4(AmbientOcclusionColor(), 1.0);
|
||||
FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0);
|
||||
#endif
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
|
||||
layout(location = 0) in vec4 aPosition;
|
||||
layout(location = 1) in vec2 aTexCoord;
|
||||
layout(location = 2) in vec4 aColor;
|
||||
|
||||
layout(location = 0) out vec4 vTexCoord;
|
||||
layout(location = 1) out vec4 vColor;
|
||||
layout(location = 9) out vec3 vLightmap;
|
||||
|
||||
#ifndef SIMPLE // we do not need these for simple shaders
|
||||
layout(location = 3) in vec4 aVertex2;
|
||||
layout(location = 4) in vec4 aNormal;
|
||||
layout(location = 5) in vec4 aNormal2;
|
||||
layout(location = 6) in vec3 aLightmap;
|
||||
layout(location = 7) in vec4 aBoneWeight;
|
||||
layout(location = 8) in uvec4 aBoneSelector;
|
||||
|
||||
layout(location = 2) out vec4 pixelpos;
|
||||
layout(location = 3) out vec3 glowdist;
|
||||
layout(location = 4) out vec3 gradientdist;
|
||||
layout(location = 5) out vec4 vWorldNormal;
|
||||
layout(location = 6) out vec4 vEyeNormal;
|
||||
#endif
|
||||
|
||||
#ifdef NO_CLIPDISTANCE_SUPPORT
|
||||
layout(location = 7) out vec4 ClipDistanceA;
|
||||
layout(location = 8) out vec4 ClipDistanceB;
|
||||
#endif
|
||||
|
||||
struct BonesResult
|
||||
{
|
||||
vec3 Normal;
|
||||
vec4 Position;
|
||||
};
|
||||
|
||||
BonesResult ApplyBones();
|
||||
|
||||
void main()
|
||||
{
|
||||
float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4;
|
||||
|
||||
vec2 parmTexCoord;
|
||||
vec4 parmPosition;
|
||||
|
||||
BonesResult bones = ApplyBones();
|
||||
|
||||
parmTexCoord = aTexCoord;
|
||||
parmPosition = bones.Position;
|
||||
|
||||
#ifndef SIMPLE
|
||||
vec4 worldcoord = ModelMatrix * mix(parmPosition, aVertex2, uInterpolationFactor);
|
||||
#else
|
||||
vec4 worldcoord = ModelMatrix * parmPosition;
|
||||
#endif
|
||||
|
||||
vec4 eyeCoordPos = ViewMatrix * worldcoord;
|
||||
|
||||
#ifdef HAS_UNIFORM_VERTEX_DATA
|
||||
if ((useVertexData & 1) == 0)
|
||||
vColor = uVertexColor;
|
||||
else
|
||||
vColor = aColor;
|
||||
#else
|
||||
vColor = aColor;
|
||||
#endif
|
||||
|
||||
#ifndef SIMPLE
|
||||
vLightmap = aLightmap;
|
||||
|
||||
pixelpos.xyz = worldcoord.xyz;
|
||||
pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w;
|
||||
|
||||
if (uGlowTopColor.a > 0 || uGlowBottomColor.a > 0)
|
||||
{
|
||||
float topatpoint = (uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z;
|
||||
float bottomatpoint = (uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z;
|
||||
glowdist.x = topatpoint - worldcoord.y;
|
||||
glowdist.y = worldcoord.y - bottomatpoint;
|
||||
glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0);
|
||||
}
|
||||
|
||||
if (uObjectColor2.a != 0)
|
||||
{
|
||||
float topatpoint = (uGradientTopPlane.w + uGradientTopPlane.x * worldcoord.x + uGradientTopPlane.y * worldcoord.z) * uGradientTopPlane.z;
|
||||
float bottomatpoint = (uGradientBottomPlane.w + uGradientBottomPlane.x * worldcoord.x + uGradientBottomPlane.y * worldcoord.z) * uGradientBottomPlane.z;
|
||||
gradientdist.x = topatpoint - worldcoord.y;
|
||||
gradientdist.y = worldcoord.y - bottomatpoint;
|
||||
gradientdist.z = clamp(gradientdist.x / (topatpoint - bottomatpoint), 0.0, 1.0);
|
||||
}
|
||||
|
||||
if (uSplitBottomPlane.z != 0.0)
|
||||
{
|
||||
ClipDistance3 = ((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y;
|
||||
ClipDistance4 = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z);
|
||||
}
|
||||
|
||||
vWorldNormal = NormalModelMatrix * vec4(normalize(bones.Normal), 1.0);
|
||||
vEyeNormal = NormalViewMatrix * vec4(normalize(vWorldNormal.xyz), 1.0);
|
||||
#endif
|
||||
|
||||
#ifdef SPHEREMAP
|
||||
vec3 u = normalize(eyeCoordPos.xyz);
|
||||
vec4 n = normalize(NormalViewMatrix * vec4(parmTexCoord.x, 0.0, parmTexCoord.y, 0.0));
|
||||
vec3 r = reflect(u, n.xyz);
|
||||
float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) );
|
||||
vec2 sst = vec2(r.x/m + 0.5, r.y/m + 0.5);
|
||||
vTexCoord.xy = sst;
|
||||
#else
|
||||
vTexCoord = TextureMatrix * vec4(parmTexCoord, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
gl_Position = ProjectionMatrix * eyeCoordPos;
|
||||
|
||||
#ifdef VULKAN_COORDINATE_SYSTEM
|
||||
gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0;
|
||||
#endif
|
||||
|
||||
if (uClipHeightDirection != 0.0) // clip planes used for reflective flats
|
||||
{
|
||||
ClipDistance0 = (worldcoord.y - uClipHeight) * uClipHeightDirection;
|
||||
}
|
||||
else if (uClipLine.x > -1000000.0) // and for line portals - this will never be active at the same time as the reflective planes clipping so it can use the same hardware clip plane.
|
||||
{
|
||||
ClipDistance0 = -( (worldcoord.z - uClipLine.y) * uClipLine.z + (uClipLine.x - worldcoord.x) * uClipLine.w ) + 1.0/32768.0; // allow a tiny bit of imprecisions for colinear linedefs.
|
||||
}
|
||||
else
|
||||
{
|
||||
ClipDistance0 = 1;
|
||||
}
|
||||
|
||||
// clip planes used for translucency splitting
|
||||
ClipDistance1 = worldcoord.y - uClipSplit.x;
|
||||
ClipDistance2 = uClipSplit.y - worldcoord.y;
|
||||
|
||||
if (uSplitTopPlane == vec4(0.0))
|
||||
{
|
||||
ClipDistance3 = 1.0;
|
||||
ClipDistance4 = 1.0;
|
||||
}
|
||||
|
||||
#ifdef NO_CLIPDISTANCE_SUPPORT
|
||||
ClipDistanceA = vec4(ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3);
|
||||
ClipDistanceB = vec4(ClipDistance4, 0.0, 0.0, 0.0);
|
||||
#else
|
||||
gl_ClipDistance[0] = ClipDistance0;
|
||||
gl_ClipDistance[1] = ClipDistance1;
|
||||
gl_ClipDistance[2] = ClipDistance2;
|
||||
gl_ClipDistance[3] = ClipDistance3;
|
||||
gl_ClipDistance[4] = ClipDistance4;
|
||||
#endif
|
||||
|
||||
gl_PointSize = 1.0;
|
||||
}
|
||||
|
||||
#if !defined(SIMPLE)
|
||||
vec3 GetAttrNormal()
|
||||
{
|
||||
#ifdef HAS_UNIFORM_VERTEX_DATA
|
||||
if ((useVertexData & 2) == 0)
|
||||
return uVertexNormal.xyz;
|
||||
else
|
||||
return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor);
|
||||
#else
|
||||
return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AddWeightedBone(uint boneIndex, float weight, inout vec4 position, inout vec3 normal)
|
||||
{
|
||||
if (weight != 0.0)
|
||||
{
|
||||
mat4 transform = bones[uBoneIndexBase + int(boneIndex)];
|
||||
mat3 rotation = mat3(transform);
|
||||
position += (transform * aPosition) * weight;
|
||||
normal += (rotation * aNormal.xyz) * weight;
|
||||
}
|
||||
}
|
||||
|
||||
BonesResult ApplyBones()
|
||||
{
|
||||
BonesResult result;
|
||||
if (uBoneIndexBase >= 0 && aBoneWeight != vec4(0.0))
|
||||
{
|
||||
result.Position = vec4(0.0);
|
||||
result.Normal = vec3(0.0);
|
||||
|
||||
// We use low precision input for our bone weights. Rescale so the sum still is 1.0
|
||||
float totalWeight = aBoneWeight.x + aBoneWeight.y + aBoneWeight.z + aBoneWeight.w;
|
||||
float weightMultiplier = 1.0 / totalWeight;
|
||||
vec4 boneWeight = aBoneWeight * weightMultiplier;
|
||||
|
||||
AddWeightedBone(aBoneSelector.x, boneWeight.x, result.Position, result.Normal);
|
||||
AddWeightedBone(aBoneSelector.y, boneWeight.y, result.Position, result.Normal);
|
||||
AddWeightedBone(aBoneSelector.z, boneWeight.z, result.Position, result.Normal);
|
||||
AddWeightedBone(aBoneSelector.w, boneWeight.w, result.Position, result.Normal);
|
||||
|
||||
result.Position.w = 1.0; // For numerical stability
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Position = aPosition;
|
||||
result.Normal = GetAttrNormal();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
BonesResult ApplyBones()
|
||||
{
|
||||
BonesResult result;
|
||||
result.Position = aPosition;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color)
|
||||
{
|
||||
return material.Base.rgb * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4);
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
|
||||
vec3 lightContribution(int i, vec3 normal)
|
||||
{
|
||||
vec4 lightpos = lights[i];
|
||||
vec4 lightcolor = lights[i+1];
|
||||
vec4 lightspot1 = lights[i+2];
|
||||
vec4 lightspot2 = lights[i+3];
|
||||
|
||||
float lightdistance = distance(lightpos.xyz, pixelpos.xyz);
|
||||
if (lightpos.w < lightdistance)
|
||||
return vec3(0.0); // Early out lights touching surface but not this fragment
|
||||
|
||||
vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz);
|
||||
float dotprod = dot(normal, lightdir);
|
||||
if (dotprod < -0.0001) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. Note that this can cause precision issues.
|
||||
|
||||
float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0);
|
||||
|
||||
if (lightspot1.w == 1.0)
|
||||
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
|
||||
|
||||
if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag
|
||||
{
|
||||
attenuation *= clamp(dotprod, 0.0, 1.0);
|
||||
}
|
||||
|
||||
if (attenuation > 0.0) // Skip shadow map test if possible
|
||||
{
|
||||
attenuation *= shadowAttenuation(lightpos, lightcolor.a);
|
||||
return lightcolor.rgb * attenuation;
|
||||
}
|
||||
else
|
||||
{
|
||||
return vec3(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color)
|
||||
{
|
||||
vec4 dynlight = uDynLightColor;
|
||||
vec3 normal = material.Normal;
|
||||
|
||||
if (uLightIndex >= 0)
|
||||
{
|
||||
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
|
||||
if (lightRange.z > lightRange.x)
|
||||
{
|
||||
// modulated lights
|
||||
for(int i=lightRange.x; i<lightRange.y; i+=4)
|
||||
{
|
||||
dynlight.rgb += lightContribution(i, normal);
|
||||
}
|
||||
|
||||
// subtractive lights
|
||||
for(int i=lightRange.y; i<lightRange.z; i+=4)
|
||||
{
|
||||
dynlight.rgb -= lightContribution(i, normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec3 frag;
|
||||
|
||||
if ( uLightBlendMode == 1 )
|
||||
{ // COLOR_CORRECT_CLAMPING
|
||||
vec3 lightcolor = color + desaturate(dynlight).rgb;
|
||||
frag = material.Base.rgb * ((lightcolor / max(max(max(lightcolor.r, lightcolor.g), lightcolor.b), 1.4) * 1.4));
|
||||
}
|
||||
else if ( uLightBlendMode == 2 )
|
||||
{ // UNCLAMPED
|
||||
frag = material.Base.rgb * (color + desaturate(dynlight).rgb);
|
||||
}
|
||||
else
|
||||
{
|
||||
frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
|
||||
}
|
||||
|
||||
if (uLightIndex >= 0)
|
||||
{
|
||||
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
|
||||
if (lightRange.w > lightRange.z)
|
||||
{
|
||||
vec4 addlight = vec4(0.0,0.0,0.0,0.0);
|
||||
|
||||
// additive lights
|
||||
for(int i=lightRange.z; i<lightRange.w; i+=4)
|
||||
{
|
||||
addlight.rgb += lightContribution(i, normal);
|
||||
}
|
||||
|
||||
frag = clamp(frag + desaturate(addlight).rgb, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
return frag;
|
||||
}
|
|
@ -1,195 +0,0 @@
|
|||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH*NdotH;
|
||||
|
||||
float nom = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return nom / denom;
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
|
||||
float nom = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
|
||||
return nom / denom;
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
|
||||
{
|
||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float quadraticDistanceAttenuation(vec4 lightpos)
|
||||
{
|
||||
float strength = (1.0 + lightpos.w * lightpos.w * 0.25) * 0.5;
|
||||
|
||||
vec3 distVec = lightpos.xyz - pixelpos.xyz;
|
||||
float attenuation = strength / (1.0 + dot(distVec, distVec));
|
||||
if (attenuation <= 1.0 / 256.0) return 0.0;
|
||||
|
||||
return attenuation;
|
||||
}
|
||||
|
||||
float linearDistanceAttenuation(vec4 lightpos)
|
||||
{
|
||||
float lightdistance = distance(lightpos.xyz, pixelpos.xyz);
|
||||
return clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec3 ProcessMaterialLight(Material material, vec3 ambientLight)
|
||||
{
|
||||
vec3 worldpos = pixelpos.xyz;
|
||||
|
||||
vec3 albedo = pow(material.Base.rgb, vec3(2.2)); // sRGB to linear
|
||||
ambientLight = pow(ambientLight, vec3(2.2));
|
||||
|
||||
float metallic = material.Metallic;
|
||||
float roughness = material.Roughness;
|
||||
float ao = material.AO;
|
||||
|
||||
vec3 N = material.Normal;
|
||||
vec3 V = normalize(uCameraPos.xyz - worldpos);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
|
||||
vec3 Lo = uDynLightColor.rgb;
|
||||
|
||||
if (uLightIndex >= 0)
|
||||
{
|
||||
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
|
||||
if (lightRange.z > lightRange.x)
|
||||
{
|
||||
//
|
||||
// modulated lights
|
||||
//
|
||||
for(int i=lightRange.x; i<lightRange.y; i+=4)
|
||||
{
|
||||
vec4 lightpos = lights[i];
|
||||
vec4 lightcolor = lights[i+1];
|
||||
vec4 lightspot1 = lights[i+2];
|
||||
vec4 lightspot2 = lights[i+3];
|
||||
|
||||
vec3 L = normalize(lightpos.xyz - worldpos);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
float attenuation = linearDistanceAttenuation(lightpos);
|
||||
if (lightspot1.w == 1.0)
|
||||
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
|
||||
if (lightcolor.a < 0.0)
|
||||
attenuation *= clamp(dot(N, L), 0.0, 1.0); // Sign bit is the attenuated light flag
|
||||
|
||||
if (attenuation > 0.0)
|
||||
{
|
||||
attenuation *= shadowAttenuation(lightpos, lightcolor.a);
|
||||
|
||||
vec3 radiance = lightcolor.rgb * attenuation;
|
||||
|
||||
// cook-torrance brdf
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic);
|
||||
|
||||
vec3 nominator = NDF * G * F;
|
||||
float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0);
|
||||
vec3 specular = nominator / max(denominator, 0.001);
|
||||
|
||||
Lo += (kD * albedo / PI + specular) * radiance;
|
||||
}
|
||||
}
|
||||
//
|
||||
// subtractive lights
|
||||
//
|
||||
for(int i=lightRange.y; i<lightRange.z; i+=4)
|
||||
{
|
||||
vec4 lightpos = lights[i];
|
||||
vec4 lightcolor = lights[i+1];
|
||||
vec4 lightspot1 = lights[i+2];
|
||||
vec4 lightspot2 = lights[i+3];
|
||||
|
||||
vec3 L = normalize(lightpos.xyz - worldpos);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
float attenuation = linearDistanceAttenuation(lightpos);
|
||||
if (lightspot1.w == 1.0)
|
||||
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
|
||||
if (lightcolor.a < 0.0)
|
||||
attenuation *= clamp(dot(N, L), 0.0, 1.0); // Sign bit is the attenuated light flag
|
||||
|
||||
if (attenuation > 0.0)
|
||||
{
|
||||
attenuation *= shadowAttenuation(lightpos, lightcolor.a);
|
||||
|
||||
vec3 radiance = lightcolor.rgb * attenuation;
|
||||
|
||||
// cook-torrance brdf
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic);
|
||||
|
||||
vec3 nominator = NDF * G * F;
|
||||
float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0);
|
||||
vec3 specular = nominator / max(denominator, 0.001);
|
||||
|
||||
Lo -= (kD * albedo / PI + specular) * radiance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pretend we sampled the sector light level from an irradiance map
|
||||
|
||||
vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = 1.0 - kS;
|
||||
|
||||
vec3 irradiance = ambientLight; // texture(irradianceMap, N).rgb
|
||||
vec3 diffuse = irradiance * albedo;
|
||||
|
||||
//kD *= 1.0 - metallic;
|
||||
//const float MAX_REFLECTION_LOD = 4.0;
|
||||
//vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb;
|
||||
//vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg;
|
||||
//vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y);
|
||||
|
||||
//vec3 ambient = (kD * diffuse + specular) * ao;
|
||||
vec3 ambient = (kD * diffuse) * ao;
|
||||
|
||||
vec3 color = max(ambient + Lo, vec3(0.0));
|
||||
|
||||
// Tonemap (reinhard) and apply sRGB gamma
|
||||
//color = color / (color + vec3(1.0));
|
||||
return pow(color, vec3(1.0 / 2.2));
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
|
||||
vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA)
|
||||
{
|
||||
vec4 lightpos = lights[i];
|
||||
vec4 lightspot1 = lights[i+2];
|
||||
vec4 lightspot2 = lights[i+3];
|
||||
|
||||
float lightdistance = distance(lightpos.xyz, pixelpos.xyz);
|
||||
if (lightpos.w < lightdistance)
|
||||
return vec2(0.0); // Early out lights touching surface but not this fragment
|
||||
|
||||
float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0);
|
||||
|
||||
if (lightspot1.w == 1.0)
|
||||
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
|
||||
|
||||
vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz);
|
||||
|
||||
if (lightcolorA < 0.0) // Sign bit is the attenuated light flag
|
||||
attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0);
|
||||
|
||||
if (attenuation > 0.0) // Skip shadow map test if possible
|
||||
attenuation *= shadowAttenuation(lightpos, lightcolorA);
|
||||
|
||||
if (attenuation <= 0.0)
|
||||
return vec2(0.0);
|
||||
|
||||
float glossiness = uSpecularMaterial.x;
|
||||
float specularLevel = uSpecularMaterial.y;
|
||||
|
||||
vec3 halfdir = normalize(viewdir + lightdir);
|
||||
float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f);
|
||||
float phExp = glossiness * 4.0f;
|
||||
return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp));
|
||||
}
|
||||
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color)
|
||||
{
|
||||
vec4 dynlight = uDynLightColor;
|
||||
vec4 specular = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
vec3 normal = material.Normal;
|
||||
vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz);
|
||||
|
||||
if (uLightIndex >= 0)
|
||||
{
|
||||
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
|
||||
if (lightRange.z > lightRange.x)
|
||||
{
|
||||
// modulated lights
|
||||
for(int i=lightRange.x; i<lightRange.y; i+=4)
|
||||
{
|
||||
vec4 lightcolor = lights[i+1];
|
||||
vec2 attenuation = lightAttenuation(i, normal, viewdir, lightcolor.a);
|
||||
dynlight.rgb += lightcolor.rgb * attenuation.x;
|
||||
specular.rgb += lightcolor.rgb * attenuation.y;
|
||||
}
|
||||
|
||||
// subtractive lights
|
||||
for(int i=lightRange.y; i<lightRange.z; i+=4)
|
||||
{
|
||||
vec4 lightcolor = lights[i+1];
|
||||
vec2 attenuation = lightAttenuation(i, normal, viewdir, lightcolor.a);
|
||||
dynlight.rgb -= lightcolor.rgb * attenuation.x;
|
||||
specular.rgb -= lightcolor.rgb * attenuation.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( uLightBlendMode == 1 )
|
||||
{ // COLOR_CORRECT_CLAMPING
|
||||
dynlight.rgb = color + desaturate(dynlight).rgb;
|
||||
specular.rgb = desaturate(specular).rgb;
|
||||
|
||||
dynlight.rgb = ((dynlight.rgb / max(max(max(dynlight.r, dynlight.g), dynlight.b), 1.4) * 1.4));
|
||||
specular.rgb = ((specular.rgb / max(max(max(specular.r, specular.g), specular.b), 1.4) * 1.4));
|
||||
}
|
||||
else if ( uLightBlendMode == 2 )
|
||||
{ // UNCLAMPED
|
||||
dynlight.rgb = color + desaturate(dynlight).rgb;
|
||||
specular.rgb = desaturate(specular).rgb;
|
||||
}
|
||||
else
|
||||
{
|
||||
dynlight.rgb = clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
|
||||
specular.rgb = clamp(desaturate(specular).rgb, 0.0, 1.4);
|
||||
}
|
||||
|
||||
vec3 frag = material.Base.rgb * dynlight.rgb + material.Specular * specular.rgb;
|
||||
|
||||
if (uLightIndex >= 0)
|
||||
{
|
||||
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
|
||||
if (lightRange.w > lightRange.z)
|
||||
{
|
||||
vec4 addlight = vec4(0.0,0.0,0.0,0.0);
|
||||
|
||||
// additive lights
|
||||
for(int i=lightRange.z; i<lightRange.w; i+=4)
|
||||
{
|
||||
vec4 lightcolor = lights[i+1];
|
||||
vec2 attenuation = lightAttenuation(i, normal, viewdir, lightcolor.a);
|
||||
addlight.rgb += lightcolor.rgb * attenuation.x;
|
||||
}
|
||||
|
||||
frag = clamp(frag + desaturate(addlight).rgb, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
return frag;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
layout(location=0) out vec4 FragColor;
|
||||
#ifdef GBUFFER_PASS
|
||||
layout(location=1) out vec4 FragFog;
|
||||
layout(location=2) out vec4 FragNormal;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(1.0, 1.0, 1.0, 0.0);
|
||||
#ifdef GBUFFER_PASS
|
||||
FragFog = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
FragNormal = vec4(0.5, 0.5, 0.5, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in a new issue