mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 19:59:28 +02:00
Merge pull request #11774 from NissimHadar/hazeOnTransparent
Haze on transparent
This commit is contained in:
commit
88ade87c71
14 changed files with 220 additions and 159 deletions
|
@ -128,7 +128,7 @@ namespace model {
|
||||||
Parameters() {}
|
Parameters() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
UniformBufferView _hazeParametersBuffer;
|
UniformBufferView _hazeParametersBuffer { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
using HazePointer = std::shared_ptr<Haze>;
|
using HazePointer = std::shared_ptr<Haze>;
|
||||||
|
|
|
@ -91,6 +91,7 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
|
<@include Haze.slh@>
|
||||||
|
|
||||||
<@func declareEvalSkyboxGlobalColor(supportScattering)@>
|
<@func declareEvalSkyboxGlobalColor(supportScattering)@>
|
||||||
|
|
||||||
|
@ -101,8 +102,6 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness
|
||||||
<$declareDeferredCurvature()$>
|
<$declareDeferredCurvature()$>
|
||||||
<@endif@>
|
<@endif@>
|
||||||
|
|
||||||
<@include Haze.slh@>
|
|
||||||
|
|
||||||
vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal,
|
vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal,
|
||||||
vec3 albedo, vec3 fresnel, float metallic, float roughness
|
vec3 albedo, vec3 fresnel, float metallic, float roughness
|
||||||
<@if supportScattering@>
|
<@if supportScattering@>
|
||||||
|
@ -122,7 +121,6 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
|
||||||
color += ambientDiffuse;
|
color += ambientDiffuse;
|
||||||
color += ambientSpecular;
|
color += ambientSpecular;
|
||||||
|
|
||||||
// Directional
|
|
||||||
vec3 directionalDiffuse;
|
vec3 directionalDiffuse;
|
||||||
vec3 directionalSpecular;
|
vec3 directionalSpecular;
|
||||||
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation
|
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation
|
||||||
|
@ -135,52 +133,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
|
||||||
|
|
||||||
// Attenuate the light if haze effect selected
|
// Attenuate the light if haze effect selected
|
||||||
if ((hazeParams.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) {
|
if ((hazeParams.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) {
|
||||||
// Directional light attenuation is simulated by assuming the light source is at a fixed height above the
|
color = computeHazeColorKeyLightAttenuation(color, lightDirection, position);
|
||||||
// fragment. This height is where the haze density is reduced by 95% from the haze at the fragment's height
|
|
||||||
//
|
|
||||||
// The distance is computed from the height and the directional light orientation
|
|
||||||
// The distance is limited to height * 1,000, which gives an angle of ~0.057 degrees
|
|
||||||
|
|
||||||
// Get directional light
|
|
||||||
Light light = getLight();
|
|
||||||
vec3 lightDirection = getLightDirection(light);
|
|
||||||
|
|
||||||
// Height at which haze density is reduced by 95% (default set to 2000.0 for safety ,this should never happen)
|
|
||||||
float height_95p = 2000.0;
|
|
||||||
if (hazeParams.hazeKeyLightAltitudeFactor > 0.0f) {
|
|
||||||
height_95p = -log(0.05) / hazeParams.hazeKeyLightAltitudeFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that the sine will always be positive
|
|
||||||
float sin_pitch = sqrt(1.0 - lightDirection.y * lightDirection.y);
|
|
||||||
|
|
||||||
float distance;
|
|
||||||
const float minimumSinPitch = 0.001;
|
|
||||||
if (sin_pitch < minimumSinPitch) {
|
|
||||||
distance = height_95p / minimumSinPitch;
|
|
||||||
} else {
|
|
||||||
distance = height_95p / sin_pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Position of fragment in world coordinates
|
|
||||||
vec4 worldFragPos = invViewMat * vec4(position, 0.0);
|
|
||||||
|
|
||||||
// Integration is from the fragment towards the light source
|
|
||||||
// Note that the haze base reference affects only the haze density as function of altitude
|
|
||||||
float hazeDensityDistribution =
|
|
||||||
hazeParams.hazeKeyLightRangeFactor *
|
|
||||||
exp(-hazeParams.hazeKeyLightAltitudeFactor * (worldFragPos.y - hazeParams.hazeBaseReference));
|
|
||||||
|
|
||||||
float hazeIntegral = hazeDensityDistribution * distance;
|
|
||||||
|
|
||||||
// Note that t is constant and equal to -log(0.05)
|
|
||||||
// float t = hazeParams.hazeAltitudeFactor * height_95p;
|
|
||||||
// hazeIntegral *= (1.0 - exp (-t)) / t;
|
|
||||||
hazeIntegral *= 0.3171178;
|
|
||||||
|
|
||||||
float hazeAmount = 1.0 - exp(-hazeIntegral);
|
|
||||||
|
|
||||||
color = mix(color, vec3(0.0, 0.0, 0.0), hazeAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
|
@ -213,9 +166,6 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur
|
||||||
}
|
}
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<@func declareEvalGlobalLightingAlphaBlended()@>
|
<@func declareEvalGlobalLightingAlphaBlended()@>
|
||||||
|
|
||||||
<$declareLightingAmbient(1, 1, 1)$>
|
<$declareLightingAmbient(1, 1, 1)$>
|
||||||
|
@ -233,7 +183,6 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl
|
||||||
color += ambientDiffuse;
|
color += ambientDiffuse;
|
||||||
color += ambientSpecular / opacity;
|
color += ambientSpecular / opacity;
|
||||||
|
|
||||||
|
|
||||||
// Directional
|
// Directional
|
||||||
vec3 directionalDiffuse;
|
vec3 directionalDiffuse;
|
||||||
vec3 directionalSpecular;
|
vec3 directionalSpecular;
|
||||||
|
@ -244,6 +193,43 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
|
mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal,
|
||||||
|
vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, float roughness, float opacity)
|
||||||
|
{
|
||||||
|
<$prepareGlobalLight()$>
|
||||||
|
|
||||||
|
color += emissive * isEmissiveEnabled();
|
||||||
|
|
||||||
|
// Ambient
|
||||||
|
vec3 ambientDiffuse;
|
||||||
|
vec3 ambientSpecular;
|
||||||
|
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance);
|
||||||
|
color += ambientDiffuse;
|
||||||
|
color += ambientSpecular / opacity;
|
||||||
|
|
||||||
|
// Directional
|
||||||
|
vec3 directionalDiffuse;
|
||||||
|
vec3 directionalSpecular;
|
||||||
|
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation);
|
||||||
|
color += directionalDiffuse;
|
||||||
|
color += directionalSpecular / opacity;
|
||||||
|
|
||||||
|
// Haze
|
||||||
|
if ((hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE) {
|
||||||
|
vec4 colorV4 = computeHazeColor(
|
||||||
|
vec4(color, 1.0), // fragment original color
|
||||||
|
position, // fragment position in eye coordinates
|
||||||
|
fragEyeVector, // fragment position in world coordinates
|
||||||
|
invViewMat[3].y, // eye height in world coordinates
|
||||||
|
lightDirection // keylight direction vector
|
||||||
|
);
|
||||||
|
|
||||||
|
color = colorV4.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
<@include Haze.slh@>
|
<@include Haze.slh@>
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
uniform sampler2D colorMap;
|
||||||
|
uniform sampler2D linearDepthMap;
|
||||||
|
|
||||||
vec4 unpackPositionFromZeye(vec2 texcoord) {
|
vec4 unpackPositionFromZeye(vec2 texcoord) {
|
||||||
float Zeye = -texture(linearDepthMap, texcoord).x;
|
float Zeye = -texture(linearDepthMap, texcoord).x;
|
||||||
|
@ -45,104 +46,15 @@ void main(void) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Distance to fragment
|
|
||||||
vec4 eyeFragPos = unpackPositionFromZeye(varTexCoord0);
|
|
||||||
float distance = length(eyeFragPos.xyz);
|
|
||||||
|
|
||||||
vec4 fragColor = texture(colorMap, varTexCoord0);
|
vec4 fragColor = texture(colorMap, varTexCoord0);
|
||||||
vec4 hazeColor = vec4(hazeParams.hazeColor, 1.0);
|
vec4 eyeFragPos = unpackPositionFromZeye(varTexCoord0);
|
||||||
|
|
||||||
// Directional light component is a function of the angle from the eye, between the fragment and the sun
|
mat4 viewInverse = getViewInverse();
|
||||||
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
|
vec4 worldFragPos = viewInverse * eyeFragPos;
|
||||||
vec4 worldFragPos = getViewInverse() * eyeFragPos;
|
vec4 worldEyePos = viewInverse[3];
|
||||||
vec3 eyeFragDir = normalize(worldFragPos.xyz);
|
|
||||||
|
|
||||||
Light light = getLight();
|
Light light = getLight();
|
||||||
vec3 lightDirection = getLightDirection(light);
|
vec3 lightDirection = getLightDirection(light);
|
||||||
|
|
||||||
float glareComponent = max(0.0, dot(eyeFragDir, -lightDirection));
|
outFragColor = computeHazeColor(fragColor, eyeFragPos.xyz, worldFragPos.xyz, worldEyePos.y, lightDirection);
|
||||||
float power = min(1.0, pow(glareComponent, hazeParams.hazeGlareBlend));
|
|
||||||
|
|
||||||
vec4 glareColor = vec4(hazeParams.hazeGlareColor, 1.0);
|
|
||||||
|
|
||||||
// Use the haze colour for the glare colour, if blend is not enabled
|
|
||||||
vec4 blendedHazeColor;
|
|
||||||
if ((hazeParams.hazeMode & HAZE_MODE_IS_ENABLE_LIGHT_BLEND) == HAZE_MODE_IS_ENABLE_LIGHT_BLEND) {
|
|
||||||
blendedHazeColor = mix(hazeColor, glareColor, power);
|
|
||||||
} else {
|
|
||||||
blendedHazeColor = hazeColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 potentialFragColor;
|
|
||||||
|
|
||||||
if ((hazeParams.hazeMode & HAZE_MODE_IS_MODULATE_COLOR) == HAZE_MODE_IS_MODULATE_COLOR) {
|
|
||||||
// Compute separately for each colour
|
|
||||||
// Haze is based on both range and altitude
|
|
||||||
// Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt
|
|
||||||
|
|
||||||
// The eyepoint position is in the last column of the matrix
|
|
||||||
vec3 worldEyePos = getViewInverse()[3].xyz;
|
|
||||||
|
|
||||||
// Note that the haze base reference affects only the haze density as function of altitude
|
|
||||||
vec3 hazeDensityDistribution =
|
|
||||||
hazeParams.colorModulationFactor *
|
|
||||||
exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference));
|
|
||||||
|
|
||||||
vec3 hazeIntegral = hazeDensityDistribution * distance;
|
|
||||||
|
|
||||||
const float slopeThreshold = 0.01;
|
|
||||||
float deltaHeight = worldFragPos.y - worldEyePos.y;
|
|
||||||
if (abs(deltaHeight) > slopeThreshold) {
|
|
||||||
float t = hazeParams.hazeHeightFactor * deltaHeight;
|
|
||||||
hazeIntegral *= (1.0 - exp (-t)) / t;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 hazeAmount = 1.0 - exp(-hazeIntegral);
|
|
||||||
|
|
||||||
// Compute color after haze effect
|
|
||||||
potentialFragColor = mix(fragColor, vec4(1.0, 1.0, 1.0, 1.0), vec4(hazeAmount, 1.0));
|
|
||||||
} else if ((hazeParams.hazeMode & HAZE_MODE_IS_ALTITUDE_BASED) != HAZE_MODE_IS_ALTITUDE_BASED) {
|
|
||||||
// Haze is based only on range
|
|
||||||
float hazeAmount = 1.0 - exp(-distance * hazeParams.hazeRangeFactor);
|
|
||||||
|
|
||||||
// Compute color after haze effect
|
|
||||||
potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount);
|
|
||||||
} else {
|
|
||||||
// Haze is based on both range and altitude
|
|
||||||
// Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt
|
|
||||||
|
|
||||||
// The eyepoint position is in the last column of the matrix
|
|
||||||
vec3 worldEyePos = getViewInverse()[3].xyz;
|
|
||||||
|
|
||||||
// Note that the haze base reference affects only the haze density as function of altitude
|
|
||||||
float hazeDensityDistribution =
|
|
||||||
hazeParams.hazeRangeFactor *
|
|
||||||
exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference));
|
|
||||||
|
|
||||||
float hazeIntegral = hazeDensityDistribution * distance;
|
|
||||||
|
|
||||||
const float slopeThreshold = 0.01;
|
|
||||||
float deltaHeight = worldFragPos.y - worldEyePos.y;
|
|
||||||
if (abs(deltaHeight) > slopeThreshold) {
|
|
||||||
float t = hazeParams.hazeHeightFactor * deltaHeight;
|
|
||||||
// Protect from wild values
|
|
||||||
if (abs(t) > 0.0000001) {
|
|
||||||
hazeIntegral *= (1.0 - exp (-t)) / t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float hazeAmount = 1.0 - exp(-hazeIntegral);
|
|
||||||
|
|
||||||
// Compute color after haze effect
|
|
||||||
potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mix with background at far range
|
|
||||||
const float BLEND_DISTANCE = 27000.0;
|
|
||||||
if (distance > BLEND_DISTANCE) {
|
|
||||||
outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlend);
|
|
||||||
} else {
|
|
||||||
outFragColor = potentialFragColor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,160 @@ layout(std140) uniform hazeBuffer {
|
||||||
HazeParams hazeParams;
|
HazeParams hazeParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform sampler2D linearDepthMap;
|
|
||||||
|
// Input:
|
||||||
|
// color - fragment original color
|
||||||
|
// lightDirection - parameters of the keylight
|
||||||
|
// worldFragPos - fragment position in world coordinates
|
||||||
|
// Output:
|
||||||
|
// fragment colour after haze effect
|
||||||
|
//
|
||||||
|
// General algorithm taken from http://www.iquilezles.org/www/articles/fog/fog.htm, with permission
|
||||||
|
//
|
||||||
|
vec3 computeHazeColorKeyLightAttenuation(vec3 color, vec3 lightDirection, vec3 worldFragPos) {
|
||||||
|
// Directional light attenuation is simulated by assuming the light source is at a fixed height above the
|
||||||
|
// fragment. This height is where the haze density is reduced by 95% from the haze at the fragment's height
|
||||||
|
//
|
||||||
|
// The distance is computed from the height and the directional light orientation
|
||||||
|
// The distance is limited to height * 1,000, which gives an angle of ~0.057 degrees
|
||||||
|
|
||||||
|
// Height at which haze density is reduced by 95% (default set to 2000.0 for safety ,this should never happen)
|
||||||
|
float height_95p = 2000.0;
|
||||||
|
const float log_p_005 = log(0.05);
|
||||||
|
if (hazeParams.hazeKeyLightAltitudeFactor > 0.0f) {
|
||||||
|
height_95p = -log_p_005 / hazeParams.hazeKeyLightAltitudeFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that we need the sine to be positive
|
||||||
|
float sin_pitch = abs(lightDirection.y);
|
||||||
|
|
||||||
|
float distance;
|
||||||
|
const float minimumSinPitch = 0.001;
|
||||||
|
if (sin_pitch < minimumSinPitch) {
|
||||||
|
distance = height_95p / minimumSinPitch;
|
||||||
|
} else {
|
||||||
|
distance = height_95p / sin_pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integration is from the fragment towards the light source
|
||||||
|
// Note that the haze base reference affects only the haze density as function of altitude
|
||||||
|
float hazeDensityDistribution =
|
||||||
|
hazeParams.hazeKeyLightRangeFactor *
|
||||||
|
exp(-hazeParams.hazeKeyLightAltitudeFactor * (worldFragPos.y - hazeParams.hazeBaseReference));
|
||||||
|
|
||||||
|
float hazeIntegral = hazeDensityDistribution * distance;
|
||||||
|
|
||||||
|
// Note that t is constant and equal to -log(0.05)
|
||||||
|
// float t = hazeParams.hazeAltitudeFactor * height_95p;
|
||||||
|
// hazeIntegral *= (1.0 - exp (-t)) / t;
|
||||||
|
hazeIntegral *= 0.3171178;
|
||||||
|
|
||||||
|
return color * exp(-hazeIntegral);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input:
|
||||||
|
// fragColor - fragment original color
|
||||||
|
// eyeFragPos - fragment position in eye coordinates
|
||||||
|
// worldFragPos - fragment position in world coordinates
|
||||||
|
// worldEyeHeight - eye height in world coordinates
|
||||||
|
// Output:
|
||||||
|
// fragment colour after haze effect
|
||||||
|
//
|
||||||
|
// General algorithm taken from http://www.iquilezles.org/www/articles/fog/fog.htm, with permission
|
||||||
|
//
|
||||||
|
vec4 computeHazeColor(vec4 fragColor, vec3 eyeFragPos, vec3 worldFragPos, float worldEyeHeight, vec3 lightDirection) {
|
||||||
|
// Distance to fragment
|
||||||
|
float distance = length(eyeFragPos);
|
||||||
|
|
||||||
|
// Convert haze colour from uniform into a vec4
|
||||||
|
vec4 hazeColor = vec4(hazeParams.hazeColor, 1.0);
|
||||||
|
|
||||||
|
// Directional light component is a function of the angle from the eye, between the fragment and the sun
|
||||||
|
vec3 eyeFragDir = normalize(worldFragPos);
|
||||||
|
|
||||||
|
float glareComponent = max(0.0, dot(eyeFragDir, -lightDirection));
|
||||||
|
float power = min(1.0, pow(glareComponent, hazeParams.hazeGlareBlend));
|
||||||
|
|
||||||
|
vec4 glareColor = vec4(hazeParams.hazeGlareColor, 1.0);
|
||||||
|
|
||||||
|
// Use the haze colour for the glare colour, if blend is not enabled
|
||||||
|
vec4 blendedHazeColor;
|
||||||
|
if ((hazeParams.hazeMode & HAZE_MODE_IS_ENABLE_LIGHT_BLEND) == HAZE_MODE_IS_ENABLE_LIGHT_BLEND) {
|
||||||
|
blendedHazeColor = mix(hazeColor, glareColor, power);
|
||||||
|
} else {
|
||||||
|
blendedHazeColor = hazeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 potentialFragColor;
|
||||||
|
|
||||||
|
if ((hazeParams.hazeMode & HAZE_MODE_IS_MODULATE_COLOR) == HAZE_MODE_IS_MODULATE_COLOR) {
|
||||||
|
// Compute separately for each colour
|
||||||
|
// Haze is based on both range and altitude
|
||||||
|
// Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt
|
||||||
|
|
||||||
|
// Note that the haze base reference affects only the haze density as function of altitude
|
||||||
|
vec3 hazeDensityDistribution =
|
||||||
|
hazeParams.colorModulationFactor *
|
||||||
|
exp(-hazeParams.hazeHeightFactor * (worldEyeHeight - hazeParams.hazeBaseReference));
|
||||||
|
|
||||||
|
vec3 hazeIntegral = hazeDensityDistribution * distance;
|
||||||
|
|
||||||
|
const float slopeThreshold = 0.01;
|
||||||
|
float deltaHeight = worldFragPos.y - worldEyeHeight;
|
||||||
|
if (abs(deltaHeight) > slopeThreshold) {
|
||||||
|
float t = hazeParams.hazeHeightFactor * deltaHeight;
|
||||||
|
hazeIntegral *= (1.0 - exp (-t)) / t;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hazeAmount = 1.0 - exp(-hazeIntegral);
|
||||||
|
|
||||||
|
// Compute color after haze effect
|
||||||
|
potentialFragColor = mix(fragColor, vec4(1.0, 1.0, 1.0, 1.0), vec4(hazeAmount, 1.0));
|
||||||
|
} else if ((hazeParams.hazeMode & HAZE_MODE_IS_ALTITUDE_BASED) != HAZE_MODE_IS_ALTITUDE_BASED) {
|
||||||
|
// Haze is based only on range
|
||||||
|
float hazeAmount = 1.0 - exp(-distance * hazeParams.hazeRangeFactor);
|
||||||
|
|
||||||
|
// Compute color after haze effect
|
||||||
|
potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount);
|
||||||
|
} else {
|
||||||
|
// Haze is based on both range and altitude
|
||||||
|
// Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt
|
||||||
|
|
||||||
|
// Note that the haze base reference affects only the haze density as function of altitude
|
||||||
|
float hazeDensityDistribution =
|
||||||
|
hazeParams.hazeRangeFactor *
|
||||||
|
exp(-hazeParams.hazeHeightFactor * (worldEyeHeight - hazeParams.hazeBaseReference));
|
||||||
|
|
||||||
|
float hazeIntegral = hazeDensityDistribution * distance;
|
||||||
|
|
||||||
|
const float slopeThreshold = 0.01;
|
||||||
|
float deltaHeight = worldFragPos.y - worldEyeHeight;
|
||||||
|
if (abs(deltaHeight) > slopeThreshold) {
|
||||||
|
float t = hazeParams.hazeHeightFactor * deltaHeight;
|
||||||
|
// Protect from wild values
|
||||||
|
const float EPSILON = 0.0000001f;
|
||||||
|
if (abs(t) > EPSILON) {
|
||||||
|
hazeIntegral *= (1.0 - exp (-t)) / t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float hazeAmount = 1.0 - exp(-hazeIntegral);
|
||||||
|
|
||||||
|
// Compute color after haze effect
|
||||||
|
potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mix with background at far range
|
||||||
|
const float BLEND_DISTANCE = 27000.0f;
|
||||||
|
vec4 outFragColor;
|
||||||
|
if (distance > BLEND_DISTANCE) {
|
||||||
|
outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlend);
|
||||||
|
} else {
|
||||||
|
outFragColor = potentialFragColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outFragColor;
|
||||||
|
}
|
||||||
|
|
||||||
<@endif@>
|
<@endif@>
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
// Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job
|
// Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job
|
||||||
task.addJob<DrawBackgroundStage>("DrawBackgroundDeferred", lightingModel);
|
task.addJob<DrawBackgroundStage>("DrawBackgroundDeferred", lightingModel);
|
||||||
|
|
||||||
|
const auto drawHazeInputs = render::Varying(DrawHaze::Inputs(hazeModel, lightingFramebuffer, linearDepthTarget, deferredFrameTransform, lightingFramebuffer));
|
||||||
|
task.addJob<DrawHaze>("DrawHazeDeferred", drawHazeInputs);
|
||||||
|
|
||||||
// Render transparent objects forward in LightingBuffer
|
// Render transparent objects forward in LightingBuffer
|
||||||
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying();
|
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying();
|
||||||
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
||||||
|
@ -173,9 +176,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
task.addJob<DebugLightClusters>("DebugLightClusters", debugLightClustersInputs);
|
task.addJob<DebugLightClusters>("DebugLightClusters", debugLightClustersInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto drawHazeInputs = render::Varying(DrawHaze::Inputs(hazeModel, lightingFramebuffer, linearDepthTarget, deferredFrameTransform, lightingFramebuffer));
|
|
||||||
task.addJob<DrawHaze>("DrawHaze", drawHazeInputs);
|
|
||||||
|
|
||||||
const auto toneAndPostRangeTimer = task.addJob<BeginGPURangeTimer>("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing");
|
const auto toneAndPostRangeTimer = task.addJob<BeginGPURangeTimer>("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing");
|
||||||
|
|
||||||
// Add bloom
|
// Add bloom
|
||||||
|
@ -335,6 +335,13 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs&
|
||||||
// Setup lighting model for all items;
|
// Setup lighting model for all items;
|
||||||
batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer());
|
batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer());
|
||||||
|
|
||||||
|
// Setup haze iff curretn zone has haze
|
||||||
|
auto hazeStage = args->_scene->getStage<HazeStage>();
|
||||||
|
if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) {
|
||||||
|
model::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front());
|
||||||
|
batch.setUniformBuffer(render::ShapePipeline::Slot::HAZE_MODEL, hazePointer->getHazeParametersBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
// From the lighting model define a global shapKey ORED with individiual keys
|
// From the lighting model define a global shapKey ORED with individiual keys
|
||||||
ShapeKey::Builder keyBuilder;
|
ShapeKey::Builder keyBuilder;
|
||||||
if (lightingModel->isWireframeEnabled()) {
|
if (lightingModel->isWireframeEnabled()) {
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <render/RenderFetchCullSortTask.h>
|
#include <render/RenderFetchCullSortTask.h>
|
||||||
#include "LightingModel.h"
|
#include "LightingModel.h"
|
||||||
|
|
||||||
|
|
||||||
class BeginGPURangeTimer {
|
class BeginGPURangeTimer {
|
||||||
public:
|
public:
|
||||||
using JobModel = render::Job::ModelO<BeginGPURangeTimer, gpu::RangeTimerPointer>;
|
using JobModel = render::Job::ModelO<BeginGPURangeTimer, gpu::RangeTimerPointer>;
|
||||||
|
|
|
@ -66,7 +66,7 @@ void main(void) {
|
||||||
|
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
|
||||||
_fragColor = vec4(evalGlobalLightingAlphaBlended(
|
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
cam._viewInverse,
|
cam._viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
occlusionTex,
|
occlusionTex,
|
||||||
|
|
|
@ -66,7 +66,7 @@ void main(void) {
|
||||||
|
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
|
||||||
_fragColor = vec4(evalGlobalLightingAlphaBlended(
|
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
cam._viewInverse,
|
cam._viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
occlusionTex,
|
occlusionTex,
|
||||||
|
|
|
@ -76,7 +76,7 @@ void main(void) {
|
||||||
|
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
|
||||||
_fragColor = vec4(evalGlobalLightingAlphaBlended(
|
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
cam._viewInverse,
|
cam._viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
occlusionTex,
|
occlusionTex,
|
||||||
|
|
|
@ -65,7 +65,7 @@ void main(void) {
|
||||||
vec3 fragNormal;
|
vec3 fragNormal;
|
||||||
<$transformEyeToWorldDir(cam, _normal, fragNormal)$>
|
<$transformEyeToWorldDir(cam, _normal, fragNormal)$>
|
||||||
|
|
||||||
vec4 color = vec4(evalGlobalLightingAlphaBlended(
|
vec4 color = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
cam._viewInverse,
|
cam._viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
occlusionTex,
|
occlusionTex,
|
||||||
|
|
|
@ -45,7 +45,7 @@ void main(void) {
|
||||||
|
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
|
||||||
_fragColor0 = vec4(evalGlobalLightingAlphaBlended(
|
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
cam._viewInverse,
|
cam._viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
1.0,
|
1.0,
|
||||||
|
|
|
@ -57,7 +57,7 @@ void main(void) {
|
||||||
|
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
|
||||||
_fragColor0 = vec4(evalGlobalLightingAlphaBlended(
|
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
cam._viewInverse,
|
cam._viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
1.0,
|
1.0,
|
||||||
|
|
|
@ -87,6 +87,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
|
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
|
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("hazeParametersBuffer"), Slot::BUFFER::HAZE_MODEL));
|
||||||
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
|
@ -107,6 +108,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
||||||
locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap");
|
locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap");
|
||||||
locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap");
|
locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap");
|
||||||
locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer");
|
locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer");
|
||||||
|
locations->hazeParameterBufferUnit = program->getUniformBuffers().findLocation("hazeParametersBuffer");
|
||||||
|
|
||||||
ShapeKey key{filter._flags};
|
ShapeKey key{filter._flags};
|
||||||
auto gpuPipeline = gpu::Pipeline::create(program, state);
|
auto gpuPipeline = gpu::Pipeline::create(program, state);
|
||||||
|
|
|
@ -238,6 +238,7 @@ public:
|
||||||
LIGHT,
|
LIGHT,
|
||||||
LIGHT_AMBIENT_BUFFER,
|
LIGHT_AMBIENT_BUFFER,
|
||||||
FADE_PARAMETERS,
|
FADE_PARAMETERS,
|
||||||
|
HAZE_MODEL
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MAP {
|
enum MAP {
|
||||||
|
@ -270,6 +271,7 @@ public:
|
||||||
int lightAmbientMapUnit;
|
int lightAmbientMapUnit;
|
||||||
int fadeMaskTextureUnit;
|
int fadeMaskTextureUnit;
|
||||||
int fadeParameterBufferUnit;
|
int fadeParameterBufferUnit;
|
||||||
|
int hazeParameterBufferUnit;
|
||||||
};
|
};
|
||||||
using LocationsPointer = std::shared_ptr<Locations>;
|
using LocationsPointer = std::shared_ptr<Locations>;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue