- Add specular and normal map handling to main.fp

This commit is contained in:
Magnus Norddahl 2018-01-23 23:10:28 +01:00
parent e045fb57c9
commit 81c6808d2a
2 changed files with 137 additions and 29 deletions

View file

@ -468,13 +468,37 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
}
else
{
if (tx->gl_info.Normal && tx->gl_info.Specular)
{
for (auto &texture : { tx->gl_info.Normal, tx->gl_info.Specular })
{
ValidateSysTexture(texture, expanded);
mTextureLayers.Push({ texture, false });
}
mShaderIndex = SHADER_Specular;
}
else if (tx->gl_info.Normal && tx->gl_info.Metallic && tx->gl_info.Roughness && tx->gl_info.AmbientOcclusion)
{
for (auto &texture : { tx->gl_info.Normal, tx->gl_info.Metallic, tx->gl_info.Roughness, tx->gl_info.AmbientOcclusion })
{
ValidateSysTexture(texture, expanded);
mTextureLayers.Push({ texture, false });
}
mShaderIndex = SHADER_PBR;
}
tx->CreateDefaultBrightmap();
if (tx->gl_info.Brightmap != NULL)
{
ValidateSysTexture(tx->gl_info.Brightmap, expanded);
FTextureLayer layer = {tx->gl_info.Brightmap, false};
mTextureLayers.Push(layer);
mShaderIndex = SHADER_Brightmap;
if (mShaderIndex == SHADER_Specular)
mShaderIndex = SHADER_SpecularBrightmap;
else if (mShaderIndex == SHADER_PBR)
mShaderIndex = SHADER_PBRBrightmap;
else
mShaderIndex = SHADER_Brightmap;
}
}
}

View file

@ -268,29 +268,112 @@ float diffuseContribution(vec3 lightDirection, vec3 normal)
//===========================================================================
//
// Calculates the brightness of a dynamic point light
// Todo: Find a better way to define which lighting model to use.
// (Specular mode has been removed for now.)
// Blinn specular light calculation
//
//===========================================================================
float pointLightAttenuation(vec4 lightpos, float lightcolorA)
float blinnSpecularContribution(float diffuseContribution, vec3 lightDirection, vec3 faceNormal, float glossiness, float specularLevel)
{
if (diffuseContribution > 0.0f)
{
vec3 viewDir = normalize(uCameraPos.xyz - pixelpos.xyz);
vec3 halfDir = normalize(lightDirection + viewDir);
float specAngle = max(dot(halfDir, faceNormal), 0.0f);
float phExp = glossiness * 4.0f;
return specularLevel * pow(specAngle, phExp);
}
else
{
return 0.0f;
}
}
//===========================================================================
//
// Adjust normal vector according to the normal map
//
//===========================================================================
#if defined(SPECULAR) || defined(PBR)
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()
{
#define WITH_NORMALMAP_UNSIGNED
#define WITH_NORMALMAP_GREEN_UP
//#define WITH_NORMALMAP_2CHANNEL
vec3 interpolatedNormal = normalize(gl_FrontFacing ? -vWorldNormal.xyz : vWorldNormal.xyz);
vec3 map = texture(normaltexture, vTexCoord.st).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()
{
return normalize(vWorldNormal.xyz);
}
#endif
//===========================================================================
//
// Calculates the brightness of a dynamic point light
//
//===========================================================================
vec2 pointLightAttenuation(vec4 lightpos, float lightcolorA)
{
float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w;
if (attenuation == 0.0) return 0.0;
if (attenuation == 0.0) return vec2(0.0);
#ifdef SUPPORTS_SHADOWMAPS
float shadowIndex = abs(lightcolorA) - 1.0;
attenuation *= shadowmapAttenuation(lightpos, shadowIndex);
#endif
if (lightcolorA >= 0.0) // Sign bit is the attenuated light flag
{
return attenuation;
return vec2(attenuation, 0.0);
}
else
{
vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz);
float diffuseAmount = diffuseContribution(lightDirection, normalize(vWorldNormal.xyz));
return attenuation * diffuseAmount;
vec3 pixelnormal = ApplyNormalMap();
float diffuseAmount = diffuseContribution(lightDirection, pixelnormal);
#if defined(SPECULAR)
float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelnormal, 10.0, 0.12);
return vec2(diffuseAmount, specularAmount) * attenuation;
#else
return vec2(attenuation * diffuseAmount, 0.0);
#endif
}
}
@ -315,7 +398,7 @@ float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle
//
//===========================================================================
vec4 getLightColor(float fogdist, float fogfactor)
vec4 getLightColor(vec4 material, vec4 materialSpec, float fogdist, float fogfactor)
{
vec4 color = vColor;
@ -361,6 +444,7 @@ vec4 getLightColor(float fogdist, float fogfactor)
//
vec4 dynlight = uDynLightColor;
vec4 specular = vec4(0.0, 0.0, 0.0, 1.0);
#if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS
if (uLightIndex >= 0)
@ -378,11 +462,11 @@ vec4 getLightColor(float fogdist, float fogfactor)
vec4 lightspot1 = lights[i+2];
vec4 lightspot2 = lights[i+3];
float attenuation = pointLightAttenuation(lightpos, lightcolor.a);
vec2 attenuation = pointLightAttenuation(lightpos, lightcolor.a);
if (lightspot1.w == 1.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
lightcolor.rgb *= attenuation;
dynlight.rgb += lightcolor.rgb;
attenuation.xy *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
dynlight.rgb += lightcolor.rgb * attenuation.x;
specular.rgb += lightcolor.rgb * attenuation.y;
}
//
// subtractive lights
@ -394,19 +478,20 @@ vec4 getLightColor(float fogdist, float fogfactor)
vec4 lightspot1 = lights[i+2];
vec4 lightspot2 = lights[i+3];
float attenuation = pointLightAttenuation(lightpos, lightcolor.a);
vec2 attenuation = pointLightAttenuation(lightpos, lightcolor.a);
if (lightspot1.w == 1.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
lightcolor.rgb *= attenuation;
dynlight.rgb -= lightcolor.rgb;
attenuation.xy *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
dynlight.rgb -= lightcolor.rgb * attenuation.x;
specular.rgb -= lightcolor.rgb * attenuation.y;
}
}
}
#endif
color.rgb = clamp(color.rgb + desaturate(dynlight).rgb, 0.0, 1.4);
specular.rgb = clamp(specular.rgb + desaturate(specular).rgb, 0.0, 1.4);
// prevent any unintentional messing around with the alpha.
return vec4(color.rgb, vColor.a);
return vec4(material.rgb * color.rgb + materialSpec.rgb * specular.rgb, material.a * vColor.a);
}
//===========================================================================
@ -457,12 +542,6 @@ void main()
{
vec4 frag = ProcessTexel();
#if defined(SPECULAR)
frag = texture(speculartexture, vTexCoord.st);
#elif defined(PBR)
frag = texture(metallictexture, vTexCoord.st);
#endif
#ifndef NO_ALPHATEST
if (frag.a <= uAlphaThreshold) discard;
#endif
@ -492,8 +571,13 @@ void main()
fogfactor = exp2 (uFogDensity * fogdist);
}
frag *= getLightColor(fogdist, fogfactor);
#if defined(SPECULAR)
vec4 materialSpec = texture(speculartexture, vTexCoord.st);
#else
vec4 materialSpec = vec4(0.0);
#endif
frag = getLightColor(frag, materialSpec, fogdist, fogfactor);
#if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS
if (uLightIndex >= 0)
@ -513,7 +597,7 @@ void main()
vec4 lightspot1 = lights[i+2];
vec4 lightspot2 = lights[i+3];
float attenuation = pointLightAttenuation(lightpos, lightcolor.a);
float attenuation = pointLightAttenuation(lightpos, lightcolor.a).x;
if (lightspot1.w == 1.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
lightcolor.rgb *= attenuation;