Merge branch 'hazeOnTransparent' of https://github.com/NissimHadar/hifi

This commit is contained in:
Nissim Hadar 2017-12-19 07:59:12 -08:00
commit 73f16b1b2a
14 changed files with 222 additions and 161 deletions

View file

@ -128,7 +128,7 @@ namespace model {
Parameters() {}
};
UniformBufferView _hazeParametersBuffer;
UniformBufferView _hazeParametersBuffer { nullptr };
};
using HazePointer = std::shared_ptr<Haze>;

View file

@ -91,6 +91,7 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness
<@endfunc@>
<@include Haze.slh@>
<@func declareEvalSkyboxGlobalColor(supportScattering)@>
@ -101,8 +102,6 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness
<$declareDeferredCurvature()$>
<@endif@>
<@include Haze.slh@>
vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal,
vec3 albedo, vec3 fresnel, float metallic, float roughness
<@if supportScattering@>
@ -122,7 +121,6 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
color += ambientDiffuse;
color += ambientSpecular;
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
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
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
// 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);
color = computeHazeColorKeyLightAttenuation(color, lightDirection, position);
}
return color;
@ -213,9 +166,6 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur
}
<@endfunc@>
<@func declareEvalGlobalLightingAlphaBlended()@>
<$declareLightingAmbient(1, 1, 1)$>
@ -233,7 +183,6 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl
color += ambientDiffuse;
color += ambientSpecular / opacity;
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
@ -244,6 +193,42 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl
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
);
color = colorV4.rgb;
}
return color;
}
<@endfunc@>

View file

@ -23,6 +23,7 @@
<@include Haze.slh@>
uniform sampler2D colorMap;
uniform sampler2D linearDepthMap;
vec4 unpackPositionFromZeye(vec2 texcoord) {
float Zeye = -texture(linearDepthMap, texcoord).x;
@ -45,104 +46,13 @@ void main(void) {
discard;
}
// Distance to fragment
vec4 eyeFragPos = unpackPositionFromZeye(varTexCoord0);
float distance = length(eyeFragPos.xyz);
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
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
vec4 worldFragPos = getViewInverse() * eyeFragPos;
vec3 eyeFragDir = normalize(worldFragPos.xyz);
mat4 viewInverse = getViewInverse();
vec4 worldFragPos = viewInverse * eyeFragPos;
vec4 worldEyePos = viewInverse[3];
Light light = getLight();
vec3 lightDirection = getLightDirection(light);
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
// 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;
}
outFragColor = computeHazeColor(fragColor, eyeFragPos.xyz, worldFragPos.xyz, worldEyePos.y);
}

View file

@ -40,7 +40,163 @@ layout(std140) uniform hazeBuffer {
HazeParams hazeParams;
};
uniform sampler2D linearDepthMap;
// Input:
// color - fragment original color
// directionalLight - 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) {
// 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);
Light light = getLight();
vec3 lightDirection = getLightDirection(light);
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@>

View file

@ -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
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
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying();
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);
}
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");
// Add bloom
@ -335,6 +335,13 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs&
// Setup lighting model for all items;
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
ShapeKey::Builder keyBuilder;
if (lightingModel->isWireframeEnabled()) {

View file

@ -16,7 +16,6 @@
#include <render/RenderFetchCullSortTask.h>
#include "LightingModel.h"
class BeginGPURangeTimer {
public:
using JobModel = render::Job::ModelO<BeginGPURangeTimer, gpu::RangeTimerPointer>;

View file

@ -66,7 +66,7 @@ void main(void) {
TransformCamera cam = getTransformCamera();
_fragColor = vec4(evalGlobalLightingAlphaBlended(
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
occlusionTex,

View file

@ -66,7 +66,7 @@ void main(void) {
TransformCamera cam = getTransformCamera();
_fragColor = vec4(evalGlobalLightingAlphaBlended(
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
occlusionTex,

View file

@ -76,7 +76,7 @@ void main(void) {
TransformCamera cam = getTransformCamera();
_fragColor = vec4(evalGlobalLightingAlphaBlended(
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
occlusionTex,

View file

@ -65,7 +65,7 @@ void main(void) {
vec3 fragNormal;
<$transformEyeToWorldDir(cam, _normal, fragNormal)$>
vec4 color = vec4(evalGlobalLightingAlphaBlended(
vec4 color = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
occlusionTex,

View file

@ -45,7 +45,7 @@ void main(void) {
TransformCamera cam = getTransformCamera();
_fragColor0 = vec4(evalGlobalLightingAlphaBlended(
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
1.0,

View file

@ -57,7 +57,7 @@ void main(void) {
TransformCamera cam = getTransformCamera();
_fragColor0 = vec4(evalGlobalLightingAlphaBlended(
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
1.0,

View file

@ -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("fadeMaskMap"), Slot::MAP::FADE_MASK));
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);
@ -107,6 +108,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap");
locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap");
locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer");
locations->hazeParameterBufferUnit = program->getUniformBuffers().findLocation("hazeParametersBuffer");
ShapeKey key{filter._flags};
auto gpuPipeline = gpu::Pipeline::create(program, state);

View file

@ -238,6 +238,7 @@ public:
LIGHT,
LIGHT_AMBIENT_BUFFER,
FADE_PARAMETERS,
HAZE_MODEL
};
enum MAP {
@ -270,6 +271,7 @@ public:
int lightAmbientMapUnit;
int fadeMaskTextureUnit;
int fadeParameterBufferUnit;
int hazeParameterBufferUnit;
};
using LocationsPointer = std::shared_ptr<Locations>;