332 lines
13 KiB
Plaintext
332 lines
13 KiB
Plaintext
#version 120
|
|
const int nLightCount = 2;
|
|
const float pi = 3.14159265358;
|
|
|
|
uniform sampler2D diffuse, normalAOlights, shield, masks;
|
|
uniform samplerCube skybox;
|
|
uniform vec4 ownerColor;
|
|
uniform vec3 glowColor;
|
|
uniform float thrust;
|
|
uniform float camDist;
|
|
uniform float time, nodeScale;
|
|
|
|
float teamNumber = 5;
|
|
|
|
//varying vec4 shadowCoord[nLightCount];
|
|
varying vec3 forward, right;
|
|
varying vec3 normal, binormal, tangent;
|
|
varying vec3 npos;
|
|
varying vec2 uv, uv2, uv3;
|
|
varying vec4 vertPaint;
|
|
|
|
vec3 light[nLightCount];
|
|
float dist[nLightCount];
|
|
/*
|
|
//Skybox sampling call
|
|
vec2 skyboxSample(vec3 dir) {
|
|
float x = dot(dir, forward);
|
|
float z = dot(dir, right);
|
|
float y = dot(dir, cross(forward,right));
|
|
|
|
return vec2(atan(-x,z) / 6.28318530718, (y + 1.0) * 0.5);
|
|
}
|
|
*/
|
|
//Engine heat color call
|
|
float mixRange(float x, float low, float hi) {
|
|
return clamp((x - low) / (hi - low), 0.0, 1.0);
|
|
}
|
|
|
|
vec3 blackBody(float temp) {
|
|
vec3 c;
|
|
c.r = mix(1.0, 0.6234, mixRange(temp, 6400.0, 29800.0));
|
|
c.b = mix(0.0, 1.0, mixRange(temp, 2800.0, 7600.0));
|
|
if(temp < 6600.0)
|
|
c.g = mix(0.22, 0.976, mixRange(temp, 1000.0, 6600.0));
|
|
else
|
|
c.g = mix(0.976, 0.75, mixRange(temp, 6600.0, 29800.0));
|
|
return c;
|
|
}
|
|
|
|
float D_GGX(float HdotN, float Roughness)
|
|
{
|
|
float m = Roughness * Roughness;
|
|
float m2 = m * m;
|
|
float denominator = HdotN * HdotN * (m2 - 1.0) + 1.0;
|
|
float D = m2 /( pi * denominator * denominator);
|
|
return D;
|
|
}
|
|
|
|
// Schlick GGX approximation
|
|
float V_SchlickforGGX(float Roughness, float NdotV, float NdotL)
|
|
{
|
|
float k = Roughness * Roughness * 0.5f;
|
|
float G1V = NdotV * (1.0 - k) + k;
|
|
float G1L = NdotL * (1.0 - k) + k;
|
|
return 0.25f / (G1V * G1L);
|
|
}
|
|
|
|
vec3 Fresnel(vec3 substance, vec3 l, vec3 h)
|
|
{
|
|
return substance + (1.0 - substance) * pow(1.0 - clamp((dot(l, h)), 0.0, 1.0), 5.0);
|
|
}
|
|
|
|
vec3 Fresnel2(vec3 substance, float dotProduct, float roughness)
|
|
{
|
|
return substance + (1.0 - substance) * pow((1.0 - dotProduct), 5.0) / (6.0 - 5.0 * roughness);
|
|
}
|
|
|
|
float RoughToSPow(float fRoughness)
|
|
{
|
|
return (2.0 / (fRoughness * fRoughness)) - 2.0;
|
|
}
|
|
|
|
const float k0 = 0.00098f, k1 = 0.9921f;
|
|
const float g_fMaxT = (exp2(-10.0 / sqrt((2.0 / (0.0014f * 0.0014f)) - 2.0)) - 0.00098f) / 0.9921f;
|
|
|
|
float GetSpecPowToMip(float fSpecPow, int nMips)
|
|
{
|
|
float fSmulMaxT = (exp2( -10.0 / sqrt(fSpecPow)) - k0) / k1;
|
|
|
|
return float(nMips - 1) * (1.0 - clamp(fSmulMaxT / g_fMaxT, 0.0, 1.0 ));
|
|
}
|
|
|
|
void main() {
|
|
vec4 diffuse = texture2D(diffuse, uv.xy);
|
|
vec4 normAO = texture2D(normalAOlights, uv.xy);
|
|
vec3 maskSamp = texture2D(masks, uv.xy).rgb;
|
|
float paintSamp = texture2D(masks, uv2.xy).w;
|
|
float flagSamp = texture2D(masks, uv2.xy + vec2((1.0/32.0) * teamNumber, 0.0)).w;
|
|
vec3 vertMasksPrimary = vertPaint.rgb; // .a unused
|
|
//float texSamp7 = texture2D(shield, uv2.xy * 10);
|
|
//float texSamp8 = texture2D(shield, uv2.xy - time * 80.0);
|
|
float texSamp5 = texture2D(shield, uv2.xy - 8.0 * 24.0).r;
|
|
float texSamp6 = texture2D(shield, uv2.xy + time * 24.0).g;
|
|
|
|
// Normal map setup
|
|
vec3 normMap = normAO.xyz * 2.0 - vec3(1.0);
|
|
|
|
// Vertex masks setup
|
|
vec3 vertMasksSecondary = (clamp(vertMasksPrimary, 0.5, 1.0) - 0.5) * 2.0; // shield r, windows g, engine b
|
|
vertMasksPrimary = clamp(((1.0 - vertMasksPrimary) - 0.5)* 2.0, 0.0, 1.0); // flags g, warp b, transparency on r
|
|
|
|
// Texture masks setup
|
|
float paintMask = (flagSamp * vertMasksPrimary.g + paintSamp * (1.0-vertMasksPrimary.g)) * maskSamp.b;
|
|
float plateMask = maskSamp.b * (1.0-paintMask);
|
|
float roughnessTweakMask = plateMask * (1.0-paintMask);
|
|
|
|
float lightsOne = (clamp(1.0 - normAO.w, 0.5, 1.0) - 0.5) * 2.0;
|
|
float lightsTwo = (clamp(normAO.w, 0.5, 1.0) - 0.5) * 2.0;
|
|
|
|
// Emissive lights setup
|
|
vec3 lights = vec3(0.0);
|
|
|
|
float lightMask = 1.0 - vertMasksSecondary.r - vertMasksSecondary.g - vertMasksSecondary.b - vertMasksPrimary.b; // filter for no-special lights
|
|
|
|
// Primary and secondary lights are added - should be selectable, as owner and inverted owner is not always nice
|
|
lights += vec3(lightsOne * lightMask * ownerColor.rgb * 2.0);
|
|
lights += vec3(lightsTwo * lightMask * (1.0 - ownerColor.rgb) * 2.0);
|
|
|
|
// Warp drive is added - currently no models contains the mask.
|
|
float engineGlow = texSamp5 * texSamp6;
|
|
// lights += vec3(2.0, 0.0, 2.0) * (1.0 + engineGlow) * lightsTwo * vertMasksPrimary.b;
|
|
|
|
// Windows are added
|
|
lights += glowColor * vertMasksSecondary.g * lightsOne;
|
|
|
|
// Engine animation is created
|
|
engineGlow = lightsOne * (/*lightsOne * 2.0 + */engineGlow * 2.0) * vertMasksSecondary.b;
|
|
|
|
// Gives nice intensity and falloff transitions.
|
|
lights = pow(lights + (lightsOne + lightsTwo) * 1.0, vec3(1.5)) * (1.0 - vertMasksPrimary.r);
|
|
|
|
// Transparency setup
|
|
float transparency = min(clamp((clamp(diffuse.w,0.25, 0.5) - 0.25), 0.0, 0.25) * 4 + 0.25, 1.0-vertMasksPrimary.r);
|
|
|
|
// Transparency and ao extractionsetup
|
|
float ao = (1.0-((1.0-transparency) * 0.5 + diffuse.w))*2.0;
|
|
|
|
// Engine setup
|
|
float thrustIntensity = pow(thrust * 1.0, 2.0) * engineGlow;
|
|
lights += (blackBody(1000.0 + 5000.0 * thrustIntensity) * thrustIntensity);
|
|
|
|
|
|
// Player color setup - move the PBR values to external source!
|
|
// float playerMetal = 0.01; //PBR gold
|
|
// vec3 playerMetalCol = vec3(1.0, 0.77, 0.33); //PBR gold
|
|
// float playerMetal = 0.25; //PBR bronze
|
|
// vec3 playerMetalCol = vec3(0.99, 0.64, 0.34); //PBR bronze
|
|
// float playerMetal = 0.13; //PBR brass
|
|
// vec3 playerMetalCol = vec3(0.98, 0.87, 0.41); //PBR brass
|
|
// float playerMetal = 0.35; //PBR Copper
|
|
// vec3 playerMetalCol = vec3(0.98, 0.60, 0.52); //PBR Copper
|
|
// float playerMetal = 0.10; //PBR Silver
|
|
// vec3 playerMetalCol = vec3(0.97, 0.96, 0.91); //PBR Silver
|
|
// float playerMetal = 0.01; //PBR Chrome
|
|
// vec3 playerMetalCol = vec3(0.91, 0.95, 0.97); //PBR Chrome
|
|
// float playerMetal = 0.45; //PBR Titanium
|
|
// vec3 playerMetalCol = vec3(0.54, 0.49, 0.46); //PBR Titanium
|
|
// float playerMetal = 0.15; //PBR Bright Steel
|
|
// vec3 playerMetalCol = vec3(0.84, 0.85, 0.90); //PBR Bright Steel
|
|
// float playerMetal = 0.75; //PBR Dull Steel
|
|
// vec3 playerMetalCol = vec3(0.56, 0.57, 0.58); //PBR Dull Steel
|
|
// float playerMetal = 0.25; //PBR Dark Steel
|
|
// vec3 playerMetalCol = vec3(0.48, 0.45, 0.42) ; //PBR Dark Steel
|
|
// float playerMetal = 0.27; //PBR Gallium
|
|
// vec3 playerMetalCol = vec3(0.88, 0.93, 0.56); //PBR Gallium
|
|
// float playerMetal = 0.35; //PBR Molybdenum
|
|
// vec3 playerMetalCol = vec3(0.16, 0.22, 0.15); //PBR Molybdenum
|
|
// float playerMetal = 0.33; //PBR Niobium
|
|
// vec3 playerMetalCol = vec3(0.38, 0.34, 0.62); //PBR Niobium
|
|
// float playerMetal = 0.35; //PBR Vanadium
|
|
// vec3 playerMetalCol = vec3(0.08, 0.10, 0.09); //PBR Vanadium
|
|
// float playerMetal = 0.25; //PBR Adamantium
|
|
// vec3 playerMetalCol = vec3(0.26, 0.18, 0.25); //PBR Adamantium
|
|
// float playerMetal = 0.07; //PBR Tritinium
|
|
// vec3 playerMetalCol = vec3(0.54, 0.49, 0.62); //PBR Tritinium
|
|
// float playerMetal = 0.03; //PBR Zentronium
|
|
// vec3 playerMetalCol = vec3(0.96, 0.48, 0.43); //PBR Zentronium
|
|
// float playerMetal = 0.16; //PBR Xintinium
|
|
// vec3 playerMetalCol = vec3(0.48, 0.96, 0.96); //PBR Xintinium
|
|
// float playerMetal = 0.15; //PBR Duranium
|
|
// vec3 playerMetalCol = vec3(0.94, 0.24, 0.02); //PBR Duranium
|
|
// float playerMetal = 1.0; //PBR Carbon Fibre Complimentary
|
|
// vec3 playerMetalCol = vec3(1.0 - ownerColor) * 0.25; //PBR Carbon Fibre Complimentary
|
|
// float playerMetal = 0.9; //PBR Ceramic Complimentary
|
|
// vec3 playerMetalCol = vec3(1.0 - ownerColor) * 0.64 + vec3(0.32); //PBR Ceramic Complimentary
|
|
// float playerMetal = 1.0; //PBR Paint Complimentary
|
|
// vec3 playerMetalCol = vec3(1.0 - ownerColor); //PBR Paint Complimentary
|
|
float playerMetal = 0.15; //PBR Metal Complimentary
|
|
vec3 playerMetalCol = vec3(1.0 - ownerColor) * 0.5 + vec3(0.5); //PBR Metal Complimentary
|
|
|
|
vec4 playerPlateProfile = vec4(playerMetalCol, playerMetal);
|
|
|
|
// PBR mixer
|
|
playerMetal = clamp(playerMetal, 0.001, 1.0) * plateMask;
|
|
vec3 paintColor = ownerColor.rgb * (1.0-paintMask);
|
|
float metalness = clamp(maskSamp.g * max(0.5, 1.0-paintMask), 0.0, 1.0);
|
|
|
|
// Roughness setup
|
|
float orgRoughness = maskSamp.r * (1.0-plateMask) + plateMask * (plateMask * playerPlateProfile.w);
|
|
|
|
|
|
// Albedo setup
|
|
vec3 albedo = mix(diffuse.rgb * plateMask * playerMetalCol, ownerColor.rgb * diffuse.rgb, paintMask);
|
|
albedo = mix(diffuse.rgb, albedo, maskSamp.b);
|
|
|
|
// Shield setup.
|
|
lights *= (1.0 - vertMasksSecondary.r);
|
|
//vertMasksSecondary.r * (1.0 - abs(texSamp5 * texSamp6 * 2.0 - 1.0)) * vec3(0.33, 0.99, 2.0);
|
|
// transparency *= vertMasksSecondary.r * (1.0 - abs(texSamp5 * texSamp6 * 2.0 - 1.0)) * 0.66;
|
|
transparency *= clamp(1.0 - vertMasksSecondary.r * 0.5, 0.0, 1.0);
|
|
transparency += (texSamp5 * texSamp6);// * vertMasksSecondary.r;
|
|
lights += transparency * vec3(0.33, 0.99, 2.0) * vertMasksSecondary.r;
|
|
//Adjust all other PBR textures accordingly
|
|
ao *= 1.0 - vertMasksSecondary.r;
|
|
orgRoughness *= 1.0 - vertMasksSecondary.r;
|
|
metalness *= 1.0 - vertMasksSecondary.r;
|
|
albedo *= 1.0-vertMasksSecondary.r;
|
|
normMap = normalize(mix(normMap, vec3(0.0,0.0,1.0), vertMasksSecondary.r));
|
|
|
|
// Normal setup
|
|
vec3 n = normalize(normal) * normMap.z;
|
|
n += normalize(binormal) * normMap.y;
|
|
n += normalize(tangent) * normMap.x;
|
|
n = normalize(n);
|
|
vec3 v = normalize(npos);
|
|
vec3 r = normalize(reflect(-v, n));
|
|
|
|
// Substance setup and Albedo adjust
|
|
vec3 substance = clamp((0.04 - 0.04 * metalness) + albedo * metalness,0.0, 1.0);
|
|
albedo -= substance;
|
|
|
|
// Light model specials setup
|
|
float NdotV = clamp(dot(n, v), 0.0, 1.0);
|
|
float roughnessV = (orgRoughness + 1.0)/2.0; // roughness remapping
|
|
|
|
if(nLightCount > 0) {
|
|
const int i = 0;
|
|
light[i] = gl_LightSource[i].position.xyz + npos;
|
|
dist[i] = length(light[i]);
|
|
light[i] = light[i] / dist[i];
|
|
}
|
|
|
|
if(nLightCount > 1) {
|
|
const int i = 1;
|
|
light[i] = gl_LightSource[i].position.xyz + npos;
|
|
dist[i] = length(light[i]);
|
|
light[i] = light[i] / dist[i];
|
|
}
|
|
|
|
//Zoom-out highlight setup
|
|
float highlight = 0.0;
|
|
if(camDist > 1.0)
|
|
highlight += smoothstep(0.0, 500.0, camDist / sqrt(nodeScale)) * 0.2;
|
|
vec3 color = vec3(highlight);
|
|
|
|
// Ambient reflections
|
|
float fakeLysSpecularPower=RoughToSPow(orgRoughness);
|
|
float lysMipMap = GetSpecPowToMip(fakeLysSpecularPower,8);
|
|
color += textureCube(skybox, r, lysMipMap).rgb * Fresnel2(substance,NdotV,orgRoughness);
|
|
|
|
// use this if you want a cheaper reflection cubemap calculation. If so, remember to remove the GetSpecPowToMip() and RoughToSPow()
|
|
// color += textureCube(skybox, r,8.0 - (8.0*(1.0-orgRoughness))).rgb * reflectionFresnel;
|
|
|
|
// Ambient light
|
|
color += textureCube(skybox, n, 7.0).rgb * albedo * (1.0 - Fresnel2(substance,NdotV,orgRoughness));
|
|
|
|
if(nLightCount > 0) {
|
|
//light
|
|
const int i = 0;
|
|
// float falloff = 1.0 / (1.0 + (gl_LightSource[i].quadraticAttenuation * dist[i] * dist[i]));
|
|
// float NdotL = clamp(dot(n,light[i]) + 0.2,0.0, 1.0);
|
|
// fakes disc lights up close to a star.
|
|
float falloff = 1.0 / (0.25 + (gl_LightSource[i].quadraticAttenuation * dist[i] * dist[i]));
|
|
float NdotL = clamp(dot(n,light[i]) + 0.2,0.0, 1.0);
|
|
|
|
float intensity = falloff * NdotL;
|
|
|
|
vec3 L=light[i];
|
|
L = normalize(L);
|
|
|
|
vec3 VplusL = L + v;
|
|
vec3 halfVec = normalize(VplusL);
|
|
|
|
float HdotN = clamp(dot(halfVec,n), 0.0, 0.98);
|
|
|
|
vec3 F = Fresnel(substance, L, halfVec);
|
|
float D = D_GGX(HdotN, roughnessV);
|
|
float V = V_SchlickforGGX(roughnessV, NdotV, NdotL);
|
|
|
|
color += ao * ((D * V * F) + (1.0 - F) * NdotL * albedo) * gl_LightSource[i].diffuse.rgb * intensity;
|
|
|
|
}
|
|
|
|
if(nLightCount > 1) {
|
|
//light
|
|
const int i = 1;
|
|
// float falloff = 1.0 / (1.0 + (gl_LightSource[i].quadraticAttenuation * dist[i] * dist[i]));
|
|
// float NdotL = clamp(dot(n,light[i]) + 0.2,0.0, 1.0);
|
|
// fakes disc lights up close to a star.
|
|
float falloff = 1.0 / (0.25 + (gl_LightSource[i].quadraticAttenuation * dist[i] * dist[i]));
|
|
float NdotL = clamp(dot(n,light[i]) + 0.2,0.0, 1.0);
|
|
|
|
float intensity = falloff * NdotL;
|
|
|
|
vec3 L=light[i];
|
|
L = normalize(L);
|
|
|
|
vec3 VplusL = L + v;
|
|
vec3 halfVec = normalize(VplusL);
|
|
|
|
float HdotN = clamp(dot(halfVec,n), 0.0, 1.0);
|
|
|
|
vec3 F = Fresnel(substance, L, halfVec);
|
|
float D = D_GGX(HdotN, roughnessV);
|
|
float V = V_SchlickforGGX(roughnessV, NdotV, NdotL);
|
|
|
|
color += ao * ((D * V * F) + (1.0 - F) * NdotL * albedo) * gl_LightSource[i].diffuse.rgb * intensity;
|
|
}
|
|
gl_FragColor.rgb = color + lights;
|
|
gl_FragColor.a = transparency + 1.0;
|
|
}
|