Fix code style
This commit is contained in:
Binary file not shown.
@@ -61,11 +61,11 @@ protected:
|
||||
|
||||
PACK_STRUCT(struct Data
|
||||
{
|
||||
float FirstOrder;
|
||||
float First;
|
||||
float AtmosphereR;
|
||||
int AtmosphereLayer;
|
||||
float Dummy0;
|
||||
Vector4 DhdH;
|
||||
Vector4 dhdh;
|
||||
});
|
||||
|
||||
namespace AtmospherePreComputeImpl
|
||||
@@ -367,17 +367,17 @@ void AtmospherePreComputeService::Dispose()
|
||||
release();
|
||||
}
|
||||
|
||||
void GetLayerValue(int32 layer, float& atmosphereR, Vector4& DhdH)
|
||||
void GetLayerValue(int32 layer, float& atmosphereR, Vector4& dhdh)
|
||||
{
|
||||
float r = layer / Math::Max<float>(InscatterAltitudeSampleNum - 1.0f, 1.0f);
|
||||
r = r * r;
|
||||
r = Math::Sqrt(RadiusGround * RadiusGround + r * (RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround)) + (layer == 0 ? 0.01f : (layer == InscatterAltitudeSampleNum - 1 ? -0.001f : 0.0f));
|
||||
float dMin = RadiusAtmosphere - r;
|
||||
float dMax = Math::Sqrt(r * r - RadiusGround * RadiusGround) + Math::Sqrt(RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround);
|
||||
float dMinP = r - RadiusGround;
|
||||
float dMaxP = Math::Sqrt(r * r - RadiusGround * RadiusGround);
|
||||
const float dMin = RadiusAtmosphere - r;
|
||||
const float dMax = Math::Sqrt(r * r - RadiusGround * RadiusGround) + Math::Sqrt(RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround);
|
||||
const float dMinP = r - RadiusGround;
|
||||
const float dMaxP = Math::Sqrt(r * r - RadiusGround * RadiusGround);
|
||||
atmosphereR = r;
|
||||
DhdH = Vector4(dMin, dMax, dMinP, dMaxP);
|
||||
dhdh = Vector4(dMin, dMax, dMinP, dMaxP);
|
||||
}
|
||||
|
||||
void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
@@ -390,8 +390,8 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
}
|
||||
ASSERT(_isUpdatePending && _updateFrameNumber == 0);
|
||||
|
||||
auto shader = _shader->GetShader();
|
||||
auto cb = shader->GetCB(0);
|
||||
const auto shader = _shader->GetShader();
|
||||
const auto cb = shader->GetCB(0);
|
||||
Data data;
|
||||
|
||||
// Compute transmittance texture T (line 1 in algorithm 4.1)
|
||||
@@ -415,7 +415,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
context->SetState(_psInscatter1_A);
|
||||
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
|
||||
{
|
||||
GetLayerValue(layer, data.AtmosphereR, data.DhdH);
|
||||
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
|
||||
data.AtmosphereLayer = layer;
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
@@ -426,7 +426,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
context->SetState(_psInscatter1_B);
|
||||
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
|
||||
{
|
||||
GetLayerValue(layer, data.AtmosphereR, data.DhdH);
|
||||
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
|
||||
data.AtmosphereLayer = layer;
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
@@ -439,7 +439,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
//// old way to render Inscatter1 to DeltaSR and DeltaSM at once but didn't work well :/ (no time to find out why)
|
||||
//for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
|
||||
//{
|
||||
// GetLayerValue(layer, data.AtmosphereR, data.DhdH);
|
||||
// GetLayerValue(layer, data.AtmosphereR, data.dhdh);
|
||||
// data.AtmosphereLayer = layer;
|
||||
// cb->SetData(&data);
|
||||
// context->Bind(0, cb);
|
||||
@@ -472,7 +472,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
context->BindSR(5, AtmosphereDeltaSM->ViewVolume());
|
||||
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
|
||||
{
|
||||
GetLayerValue(layer, data.AtmosphereR, data.DhdH);
|
||||
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
|
||||
data.AtmosphereLayer = layer;
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
@@ -489,14 +489,14 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
context->UnBindSR(6);
|
||||
context->SetViewportAndScissors((float)InscatterWidth, (float)InscatterHeight);
|
||||
context->SetState(_psInscatterS);
|
||||
data.FirstOrder = order == 2 ? 1.0f : 0.0f;
|
||||
data.First = order == 2 ? 1.0f : 0.0f;
|
||||
context->BindSR(0, AtmosphereTransmittance);
|
||||
context->BindSR(3, AtmosphereDeltaE);
|
||||
context->BindSR(4, AtmosphereDeltaSR->ViewVolume());
|
||||
context->BindSR(5, AtmosphereDeltaSM->ViewVolume());
|
||||
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
|
||||
{
|
||||
GetLayerValue(layer, data.AtmosphereR, data.DhdH);
|
||||
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
|
||||
data.AtmosphereLayer = layer;
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
@@ -523,7 +523,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
context->BindSR(6, AtmosphereDeltaJ->ViewVolume());
|
||||
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
|
||||
{
|
||||
GetLayerValue(layer, data.AtmosphereR, data.DhdH);
|
||||
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
|
||||
data.AtmosphereLayer = layer;
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
@@ -545,7 +545,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
|
||||
context->BindSR(4, AtmosphereDeltaSR->ViewVolume());
|
||||
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
|
||||
{
|
||||
GetLayerValue(layer, data.AtmosphereR, data.DhdH);
|
||||
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
|
||||
data.AtmosphereLayer = layer;
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
|
||||
@@ -57,9 +57,8 @@ const static int InscatterNuNum = 8;
|
||||
const static int AtmosphericFogInscatterAltitudeSampleNum = 4;
|
||||
|
||||
// Configuration
|
||||
#define TRANSMITTANCE_NON_LINEAR 1
|
||||
#define INSCATTER_NON_LINEAR 1
|
||||
#define ATMOSPHERIC_TEXTURE_SAMPLE_FIX 1
|
||||
#define TRANSMITTANCE_NON_LINEAR 1
|
||||
#define INSCATTER_NON_LINEAR 1
|
||||
|
||||
#ifndef ATMOSPHERIC_NO_SUN_DISK
|
||||
#define ATMOSPHERIC_NO_SUN_DISK 0
|
||||
|
||||
@@ -24,39 +24,38 @@
|
||||
|
||||
static const float HeightOffset = 0.01f;
|
||||
|
||||
/** inscattered light along ray x+tv, when sun in direction s (=S[L]-T(x,x0)S[L]|x0) */
|
||||
float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S, float radius, float Mu, out float3 attenuation, bool isSceneGeometry)
|
||||
// inscattered light along ray x+tv, when sun in direction s (=S[L]-T(x,x0)S[L]|x0)
|
||||
float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S, float radius, float Mu, out float3 attenuation, bool isSceneGeometry)
|
||||
{
|
||||
float3 result = float3(0.f, 0.f, 0.f); // X in space and ray looking in space, intialize
|
||||
attenuation = float3(1.f, 1.f, 1.f);
|
||||
float3 result = float3(0.0f, 0.0f, 0.0f);
|
||||
attenuation = float3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
float D = -radius * Mu - sqrt(radius * radius * (Mu * Mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere);
|
||||
if (D > 0.0)
|
||||
{
|
||||
// if X in space and ray intersects atmosphere
|
||||
// move X to nearest intersection of ray with top atmosphere boundary
|
||||
X += D * V;
|
||||
T -= D;
|
||||
Mu = (radius * Mu + D) / RadiusAtmosphere;
|
||||
radius = RadiusAtmosphere;
|
||||
}
|
||||
|
||||
float Epsilon = 0.005f;//maybe 0.004?
|
||||
|
||||
if (radius < RadiusGround + HeightOffset + Epsilon)
|
||||
float d = -radius * Mu - sqrt(radius * radius * (Mu * Mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere);
|
||||
if (d > 0.0f)
|
||||
{
|
||||
float Diff = (RadiusGround + HeightOffset + Epsilon) - radius;
|
||||
X -= Diff * V;
|
||||
T -= Diff;
|
||||
radius = RadiusGround + HeightOffset + Epsilon;
|
||||
// if X in space and ray intersects atmosphere
|
||||
// move X to nearest intersection of ray with top atmosphere boundary
|
||||
X += d * V;
|
||||
T -= d;
|
||||
Mu = (radius * Mu + d) / RadiusAtmosphere;
|
||||
radius = RadiusAtmosphere;
|
||||
}
|
||||
|
||||
float epsilon = 0.005f;
|
||||
|
||||
if (radius < RadiusGround + HeightOffset + epsilon)
|
||||
{
|
||||
float diff = (RadiusGround + HeightOffset + epsilon) - radius;
|
||||
X -= diff * V;
|
||||
T -= diff;
|
||||
radius = RadiusGround + HeightOffset + epsilon;
|
||||
Mu = dot(X, V) / radius;
|
||||
}
|
||||
|
||||
if (radius <= RadiusAtmosphere && fogDepth > 0.f)
|
||||
{
|
||||
if (radius <= RadiusAtmosphere && fogDepth > 0.0f)
|
||||
{
|
||||
float3 X0 = X + T * V;
|
||||
float R0 = length(X0);
|
||||
// if ray intersects atmosphere
|
||||
float Nu = dot(V, S);
|
||||
float MuS = dot(X, S) / radius;
|
||||
|
||||
@@ -64,11 +63,11 @@ float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S,
|
||||
|
||||
if (isSceneGeometry)
|
||||
{
|
||||
Mu = max(Mu, MuHorizon + Epsilon + 0.15);
|
||||
Mu = max(Mu, MuHorizon + epsilon + 0.15f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Mu = max(Mu, MuHorizon + Epsilon);
|
||||
{
|
||||
Mu = max(Mu, MuHorizon + epsilon);
|
||||
}
|
||||
|
||||
float MuOriginal = Mu;
|
||||
@@ -81,9 +80,8 @@ float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S,
|
||||
{
|
||||
V.z = max(V.z, 0.15);
|
||||
V = normalize(V);
|
||||
float3 X1 = X + T * V;
|
||||
float R1 = length(X1);
|
||||
Mu = dot(X1, V) / R1;
|
||||
float3 x1 = X + T * V;
|
||||
Mu = dot(x1, V) / length(x1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,212 +89,185 @@ float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S,
|
||||
float phaseM = PhaseFunctionM(Nu);
|
||||
float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu), 0.0);
|
||||
|
||||
if (T > 0.0)
|
||||
if (T > 0.0)
|
||||
{
|
||||
#if ATMOSPHERIC_TEXTURE_SAMPLE_FIX
|
||||
// Avoids imprecision problems in transmittance computations based on textures
|
||||
attenuation = AnalyticTransmittance(radius, Mu, T);
|
||||
#else
|
||||
attenuation = TransmittanceWithDistance(radius, Mu, V, X0);
|
||||
#endif
|
||||
|
||||
float Mu0 = dot(X0, V) / R0;
|
||||
float MuS0 = dot(X0, S) / R0;
|
||||
|
||||
if (isSceneGeometry)
|
||||
{
|
||||
R0 = max(R0, radius);
|
||||
}
|
||||
|
||||
|
||||
if (R0 > RadiusGround + HeightOffset)
|
||||
{
|
||||
if (blendRatio < 1.0)
|
||||
{
|
||||
inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu), 0.0);
|
||||
#if ATMOSPHERIC_TEXTURE_SAMPLE_FIX
|
||||
// avoids imprecision problems near horizon by interpolating between two points above and below horizon
|
||||
if (!isSceneGeometry )
|
||||
if (!isSceneGeometry)
|
||||
{
|
||||
if (abs(Mu - MuHorizon) < Epsilon)
|
||||
if (abs(Mu - MuHorizon) < epsilon)
|
||||
{
|
||||
float Alpha = ((Mu - MuHorizon) + Epsilon) * 0.5f / Epsilon;
|
||||
|
||||
Mu = MuHorizon - Epsilon;
|
||||
Mu = MuHorizon - epsilon;
|
||||
R0 = sqrt(radius * radius + T * T + 2.0 * radius * T * Mu);
|
||||
Mu0 = (radius * Mu + T) / R0;
|
||||
|
||||
Mu0 = max(MuHorizon + Epsilon, Mu0);
|
||||
float4 Inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu);
|
||||
float4 Inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu);
|
||||
float4 InscatterA = max(Inscatter0 - attenuation.rgbr * Inscatter1, 0.0);
|
||||
Mu0 = max(MuHorizon + epsilon, Mu0);
|
||||
float4 inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu);
|
||||
float4 inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu);
|
||||
float4 inscatterA = max(inscatter0 - attenuation.rgbr * inscatter1, 0.0);
|
||||
|
||||
Mu = MuHorizon + Epsilon;
|
||||
Mu = MuHorizon + epsilon;
|
||||
R0 = sqrt(radius * radius + T * T + 2.0 * radius * T * Mu);
|
||||
|
||||
Mu0 = (radius * Mu + T) / R0;
|
||||
Mu0 = max(MuHorizon + Epsilon, Mu0);
|
||||
Inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu);
|
||||
Inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu);
|
||||
float4 InscatterB = max(Inscatter0 - attenuation.rgbr * Inscatter1, 0.0);
|
||||
Mu0 = max(MuHorizon + epsilon, Mu0);
|
||||
inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu);
|
||||
inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu);
|
||||
float4 inscatterB = max(inscatter1 - attenuation.rgbr * inscatter1, 0.0);
|
||||
|
||||
inscatter = lerp(InscatterA, InscatterB, Alpha);
|
||||
float alpha = ((Mu - MuHorizon) + epsilon) * 0.5f / epsilon;
|
||||
inscatter = lerp(inscatterA, inscatterB, alpha);
|
||||
}
|
||||
}
|
||||
else if (blendRatio > 0.0)
|
||||
{
|
||||
inscatter = lerp(inscatter, (1.0 - attenuation.rgbr) * max(Texture4DSample(AtmosphereInscatterTexture, radius, MuOriginal, MuS, Nu), 0.0), blendRatio);
|
||||
inscatter = lerp(inscatter, (1.0 - attenuation.rgbr) * max(Texture4DSample(AtmosphereInscatterTexture, radius, MuOriginal, MuS, Nu), 0.0), blendRatio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
inscatter = (1.0 - attenuation.rgbr) * inscatter;
|
||||
inscatter = (1.0 - attenuation.rgbr) * inscatter;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if ATMOSPHERIC_TEXTURE_SAMPLE_FIX
|
||||
// Avoids imprecision problems in Mie scattering when sun is below horizon
|
||||
inscatter.w *= smoothstep(0.00, 0.02, MuS);
|
||||
#endif
|
||||
result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0);
|
||||
}
|
||||
|
||||
|
||||
inscatter.w *= smoothstep(0.00, 0.02, MuS);
|
||||
result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Ground radiance at end of ray x+tv, when sun in direction s attenuated bewteen ground and viewer (=R[L0]+R[L*])
|
||||
// Ground radiance at end of ray x+tv, when sun in direction s attenuated between ground and viewer (=R[L0]+R[L*])
|
||||
float3 GetGroundColor(float4 sceneColor, float3 X, float T, float3 V, float3 S, float radius, float3 attenuation, bool isSceneGeometry)
|
||||
{
|
||||
float3 result = float3(0.f, 0.f, 0.f); // ray looking at the sky (for intial value)
|
||||
if (T > 0.0)
|
||||
{
|
||||
float3 result = float3(0.0f, 0.0f, 0.0f);
|
||||
if (T > 0.0f)
|
||||
{
|
||||
// if ray hits ground surface
|
||||
// ground Reflectance at end of ray, X0
|
||||
float3 X0 = X + T * V;
|
||||
float R0 = length(X0);
|
||||
float3 N = X0 / R0;
|
||||
N = X0 / R0;
|
||||
// ground Reflectance at end of ray, X0
|
||||
float3 X0 = X + T * V;
|
||||
float R0 = length(X0);
|
||||
float3 N = X0 / R0;
|
||||
sceneColor.xyz = saturate(sceneColor.xyz + 0.05);
|
||||
|
||||
float4 reflectance = sceneColor * float4(0.2, 0.2, 0.2, 1.0);
|
||||
float4 reflectance = sceneColor * float4(0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
// direct sun light (radiance) reaching X0
|
||||
float MuS = dot(N, S);
|
||||
float3 SunLight = isSceneGeometry ? float3(0.f, 0.f, 0.f) : TransmittanceWithShadow(R0, MuS);
|
||||
// direct sun light (radiance) reaching X0
|
||||
float MuS = dot(N, S);
|
||||
float3 sunLight = isSceneGeometry ? float3(0.f, 0.f, 0.f) : TransmittanceWithShadow(R0, MuS);
|
||||
|
||||
// precomputed sky light (irradiance) (=E[L*]) at X0
|
||||
float3 GroundSkyLight = Irradiance(AtmosphereIrradianceTexture, R0, MuS);
|
||||
// precomputed sky light (irradiance) (=E[L*]) at X0
|
||||
float3 groundSkyLight = Irradiance(AtmosphereIrradianceTexture, R0, MuS);
|
||||
|
||||
// light reflected at X0 (=(R[L0]+R[L*])/T(X,X0))
|
||||
float3 groundColor = (reflectance.rgb * (max(MuS, 0.0) * SunLight + GroundSkyLight)) / PI;
|
||||
// light reflected at X0 (=(R[L0]+R[L*])/T(X,X0))
|
||||
float3 groundColor = reflectance.rgb * ((max(MuS, 0.0) * sunLight + groundSkyLight) / PI);
|
||||
|
||||
// water specular color due to SunLight
|
||||
if (!isSceneGeometry && reflectance.w > 0.0)
|
||||
// water specular color due to SunLight
|
||||
if (!isSceneGeometry && reflectance.w > 0.0)
|
||||
{
|
||||
float3 H = normalize(S - V);
|
||||
float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-V, H), 5.0);
|
||||
float waterBrdf = fresnel * pow(max(dot(H, N), 0.0), 150.0);
|
||||
groundColor += reflectance.w * max(waterBrdf, 0.0) * SunLight;
|
||||
}
|
||||
float3 H = normalize(S - V);
|
||||
float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-V, H), 5.0);
|
||||
float waterBrdf = fresnel * pow(max(dot(H, N), 0.0), 150.0);
|
||||
groundColor += reflectance.w * max(waterBrdf, 0.0) * sunLight;
|
||||
}
|
||||
|
||||
result = attenuation * groundColor; //=R[L0]+R[L*]
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Direct sun light for ray x+tv, when sun in direction s (=L0)
|
||||
float3 GetSunColor(AtmosphericFogData atmosphericFog, float3 X, float T, float3 V, float3 S, float radius, float Mu)
|
||||
float3 GetSunColor(AtmosphericFogData atmosphericFog, float3 X, float T, float3 V, float3 S, float radius, float Mu)
|
||||
{
|
||||
if (T > 0.0)
|
||||
{
|
||||
return float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
float3 transmittance = radius <= RadiusAtmosphere ? TransmittanceWithShadow(radius, Mu) : float3(1.0, 1.0, 1.0); // T(X,xo)
|
||||
float sunIntensity = step(cos(PI * atmosphericFog.AtmosphericFogSunDiscScale / 180.0), dot(V, S)); // Lsun
|
||||
return transmittance * sunIntensity; // Eq (9)
|
||||
}
|
||||
|
||||
float3 transmittance = radius <= RadiusAtmosphere ? TransmittanceWithShadow(radius, Mu) : float3(1.0, 1.0, 1.0); // T(X,xo)
|
||||
float sunIntensity = step(cos(PI * atmosphericFog.AtmosphericFogSunDiscScale / 180.0), dot(V, S)); // Lsun
|
||||
return transmittance * sunIntensity; // Eq (9)
|
||||
}
|
||||
|
||||
float3 inscatter(inout float3 x, inout float t, float3 v, float3 s, out float r, out float mu, out float3 attenuation)
|
||||
{
|
||||
float3 result = 0;
|
||||
r = length(x);
|
||||
mu = dot(x, v) / r;
|
||||
float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere);
|
||||
float3 result = 0;
|
||||
r = length(x);
|
||||
mu = dot(x, v) / r;
|
||||
float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere);
|
||||
|
||||
// if x in space and ray intersects atmosphere
|
||||
if (d > 0.0)
|
||||
if (d > 0.0)
|
||||
{
|
||||
// move x to nearest intersection of ray with top atmosphere boundary
|
||||
x += d * v;
|
||||
t -= d;
|
||||
mu = (r * mu + d) / RadiusAtmosphere;
|
||||
r = RadiusAtmosphere;
|
||||
}
|
||||
// move x to nearest intersection of ray with top atmosphere boundary
|
||||
x += d * v;
|
||||
t -= d;
|
||||
mu = (r * mu + d) / RadiusAtmosphere;
|
||||
r = RadiusAtmosphere;
|
||||
}
|
||||
|
||||
float epsilon = 0.0045f;
|
||||
|
||||
// if ray intersects atmosphere
|
||||
if (r <= RadiusAtmosphere)
|
||||
if (r <= RadiusAtmosphere)
|
||||
{
|
||||
float nu = dot(v, s);
|
||||
float muS = dot(x, s) / r;
|
||||
float phaseR = PhaseFunctionR(nu);
|
||||
float phaseM = PhaseFunctionM(nu);
|
||||
float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu), 0.0);
|
||||
float nu = dot(v, s);
|
||||
float muS = dot(x, s) / r;
|
||||
float phaseR = PhaseFunctionR(nu);
|
||||
float phaseM = PhaseFunctionM(nu);
|
||||
float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu), 0.0);
|
||||
|
||||
if (t > 0.0)
|
||||
if (t > 0.0)
|
||||
{
|
||||
float3 x0 = x + t * v;
|
||||
float r0 = length(x0);
|
||||
float rMu0 = dot(x0, v);
|
||||
float mu0 = rMu0 / r0;
|
||||
float muS0 = dot(x0, s) / r0;
|
||||
#ifdef ATMOSPHERIC_TEXTURE_SAMPLE_FIX
|
||||
// avoids imprecision problems in transmittance computations based on textures
|
||||
float3 x0 = x + t * v;
|
||||
float r0 = length(x0);
|
||||
float rMu0 = dot(x0, v);
|
||||
float mu0 = rMu0 / r0;
|
||||
float muS0 = dot(x0, s) / r0;
|
||||
attenuation = AnalyticTransmittance(r, mu, t);
|
||||
#else
|
||||
attenuation = TransmittanceWithDistance(r, mu, v, x0);
|
||||
#endif
|
||||
if (r0 > RadiusGround + 0.01)
|
||||
if (r0 > RadiusGround + 0.01)
|
||||
{
|
||||
// computes S[L]-T(x,x0)S[L]|x0
|
||||
inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu), 0.0);
|
||||
#ifdef ATMOSPHERIC_TEXTURE_SAMPLE_FIX
|
||||
// avoids imprecision problems near horizon by interpolating between two points above and below horizon
|
||||
const float EPS = 0.004;
|
||||
// computes S[L]-T(x,x0)S[L]|x0
|
||||
inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu), 0.0);
|
||||
float muHoriz = -sqrt(1.0 - (RadiusGround / r) * (RadiusGround / r));
|
||||
if (abs(mu - muHoriz) < EPS)
|
||||
if (abs(mu - muHoriz) < epsilon)
|
||||
{
|
||||
float a = ((mu - muHoriz) + EPS) / (2.0 * EPS);
|
||||
|
||||
mu = muHoriz - EPS;
|
||||
mu = muHoriz - epsilon;
|
||||
r0 = sqrt(r * r + t * t + 2.0 * r * t * mu);
|
||||
mu0 = (r * mu + t) / r0;
|
||||
float4 inScatter0 = Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu);
|
||||
float4 inScatter1 = Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu);
|
||||
float4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0);
|
||||
|
||||
mu = muHoriz + EPS;
|
||||
mu = muHoriz + epsilon;
|
||||
r0 = sqrt(r * r + t * t + 2.0 * r * t * mu);
|
||||
mu0 = (r * mu + t) / r0;
|
||||
inScatter0 = Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu);
|
||||
inScatter1 = Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu);
|
||||
float4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0);
|
||||
|
||||
inscatter = lerp(inScatterA, inScatterB, a);
|
||||
|
||||
float alpha = ((mu - muHoriz) + epsilon) / (2.0 * epsilon);
|
||||
inscatter = lerp(inScatterA, inScatterB, alpha);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef ATMOSPHERIC_TEXTURE_SAMPLE_FIX
|
||||
// avoids imprecision problems in Mie scattering when sun is below horizon
|
||||
inscatter.w *= smoothstep(0.00, 0.02, muS);
|
||||
#endif
|
||||
result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
inscatter.w *= smoothstep(0.00, 0.02, muS);
|
||||
result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const float EPSILON_ATMOSPHERE = 0.002f;
|
||||
@@ -308,19 +279,19 @@ static const float EPSILON_INSCATTER = 0.004f;
|
||||
// output - maxPathLength: distance traversed within atmosphere
|
||||
// output - return value: intersection occurred true/false
|
||||
bool intersectAtmosphere(in float3 viewPosition, in float3 d, out float offset, out float maxPathLength)
|
||||
{
|
||||
{
|
||||
offset = 0.0f;
|
||||
maxPathLength = 0.0f;
|
||||
|
||||
|
||||
// vector from ray origin to center of the sphere
|
||||
float3 l = -viewPosition;
|
||||
float l2 = dot(l,l);
|
||||
float s = dot(l,d);
|
||||
|
||||
float l2 = dot(l, l);
|
||||
float s = dot(l, d);
|
||||
|
||||
// adjust top atmosphere boundary by small epsilon to prevent artifacts
|
||||
float r = Rt - EPSILON_ATMOSPHERE;
|
||||
float r2 = r*r;
|
||||
if(l2 <= r2)
|
||||
float r2 = r * r;
|
||||
if (l2 <= r2)
|
||||
{
|
||||
// ray origin inside sphere, hit is ensured
|
||||
float m2 = l2 - (s * s);
|
||||
@@ -328,11 +299,11 @@ bool intersectAtmosphere(in float3 viewPosition, in float3 d, out float offset,
|
||||
maxPathLength = s + q;
|
||||
return true;
|
||||
}
|
||||
else if(s >= 0)
|
||||
else if (s >= 0)
|
||||
{
|
||||
// ray starts outside in front of sphere, hit is possible
|
||||
float m2 = l2 - (s * s);
|
||||
if(m2 <= r2)
|
||||
if (m2 <= r2)
|
||||
{
|
||||
// ray hits atmosphere definitely
|
||||
float q = sqrt(r2 - m2);
|
||||
@@ -341,7 +312,7 @@ bool intersectAtmosphere(in float3 viewPosition, in float3 d, out float offset,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -358,7 +329,7 @@ float3 GetInscatteredLight(AtmosphericFogData atmosphericFog, in float3 viewPosi
|
||||
|
||||
if (intersectAtmosphere(viewPosition, viewDir, offset, maxPathLength))
|
||||
{
|
||||
return float3(offset / 10,0,0);
|
||||
return float3(offset / 10, 0, 0);
|
||||
|
||||
float pathLength = distance(viewPosition, surfacePos);
|
||||
//return pathLength.xxx;
|
||||
@@ -367,10 +338,11 @@ float3 GetInscatteredLight(AtmosphericFogData atmosphericFog, in float3 viewPosi
|
||||
if (pathLength > offset)
|
||||
{
|
||||
//return float3(1,0,0);
|
||||
|
||||
|
||||
// offsetting camera
|
||||
float3 startPos = viewPosition + offset * viewDir;
|
||||
float startPosHeight = length(startPos); pathLength -= offset;
|
||||
float startPosHeight = length(startPos);
|
||||
pathLength -= offset;
|
||||
|
||||
// starting position of path is now ensured to be inside atmosphere
|
||||
// was either originally there or has been moved to top boundary
|
||||
@@ -457,9 +429,9 @@ float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float
|
||||
viewPosition.y = (viewPosition.y - atmosphericFog.AtmosphericFogGroundOffset) * atmosphericFog.AtmosphericFogAltitudeScale;
|
||||
//viewPosition *= atmosphericFog.AtmosphericFogDistanceScale;
|
||||
//viewPosition *= scale;
|
||||
|
||||
|
||||
//viewPosition *= scale;
|
||||
|
||||
|
||||
//if(length(worldPosition) > Rg)
|
||||
// return float4(0, 0,0 ,0);
|
||||
|
||||
@@ -480,27 +452,27 @@ float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float
|
||||
return float4(0, 0, 0, 1);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if 1
|
||||
|
||||
// TODO: scale viewPosition from cm to km
|
||||
|
||||
|
||||
float scale = 0.0001f * atmosphericFog.AtmosphericFogDistanceScale;
|
||||
viewPosition.y = (viewPosition.y - atmosphericFog.AtmosphericFogGroundOffset) * atmosphericFog.AtmosphericFogAltitudeScale;
|
||||
//viewPosition *= atmosphericFog.AtmosphericFogDistanceScale;
|
||||
viewPosition *= scale;
|
||||
//viewPosition.xz *= 0.00001f;
|
||||
|
||||
|
||||
//viewPosition *= scale;
|
||||
viewPosition.y += RadiusGround + HeightOffset;
|
||||
|
||||
|
||||
//viewPosition.y -= atmosphericFog.AtmosphericFogGroundOffset;
|
||||
//worldPosition
|
||||
float Radius = length(viewPosition);
|
||||
float3 V = normalize(viewVector);
|
||||
float Mu = dot(viewPosition, V) / Radius;
|
||||
float T = -Radius * Mu - sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround);
|
||||
|
||||
|
||||
//-Radius * Mu > sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround)
|
||||
/*
|
||||
float3 g = viewPosition - float3(0.0, 0.0, RadiusGround + 10.0);
|
||||
|
||||
@@ -3,6 +3,23 @@
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/Atmosphere.hlsl"
|
||||
|
||||
// Provides functions for atmospheric scattering and aerial perspective.
|
||||
//
|
||||
// Explanations:
|
||||
// Scale Height = the altitude (height above ground) at which the average
|
||||
// atmospheric density is found.
|
||||
// Optical Depth = also called optical length, airmass, etc.
|
||||
//
|
||||
// References:
|
||||
// [GPUGems2] GPU Gems 2: Accurate Atmospheric Scattering by Sean O'Neil.
|
||||
// [GPUPro3] An Approximation to the Chapman Grazing-Incidence Function for
|
||||
// Atmospheric Scattering, GPU Pro3, pp. 105.
|
||||
// Papers bei Bruneton, Nishita, etc.
|
||||
//
|
||||
// This code contains embedded portions of free sample source code from
|
||||
// http://www-evasion.imag.fr/Membres/Eric.Bruneton/PrecomputedAtmosphericScattering2.zip, Author: Eric Bruneton,
|
||||
// 08/16/2011, Copyright (c) 2008 INRIA, All Rights Reserved, which have been altered from their original version.
|
||||
|
||||
const static int TransmittanceIntegralSamples = 500;
|
||||
const static int InscatterIntegralSamples = 50;
|
||||
const static int IrradianceIntegralSamples = 32;
|
||||
@@ -14,11 +31,11 @@ const static float InscatterDeltaPhi = PI / float(InscatterSphericalIntegralSamp
|
||||
const static float InscatterDeltaTheta = PI / float(InscatterSphericalIntegralSamples);
|
||||
|
||||
META_CB_BEGIN(0, Data)
|
||||
float FirstOrder;
|
||||
float First;
|
||||
float AtmosphereR;
|
||||
int AtmosphereLayer;
|
||||
float Dummy0;
|
||||
float4 DhdH;
|
||||
float4 dhdh;
|
||||
META_CB_END
|
||||
|
||||
Texture2D AtmosphereDeltaETexture : register(t3);
|
||||
@@ -26,117 +43,72 @@ Texture3D AtmosphereDeltaSRTexture : register(t4);
|
||||
Texture3D AtmosphereDeltaSMTexture : register(t5);
|
||||
Texture3D AtmosphereDeltaJTexture : register(t6);
|
||||
|
||||
struct AtmosphereGSOutput
|
||||
float GetOpticalDepth(float h, float radius, float mu)
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
//uint LayerIndex : SV_RenderTargetArrayIndex;
|
||||
};
|
||||
|
||||
/*
|
||||
META_VS(true, FEATURE_LEVEL_ES2)
|
||||
META_VS_IN_ELEMENT(POSITION, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
Quad_VS2PS VS(float2 Position : POSITION0, float2 TexCoord : TEXCOORD0)
|
||||
{
|
||||
Quad_VS2PS output;
|
||||
|
||||
output.Position = float4(Position, 0, 1);
|
||||
output.TexCoord = TexCoord;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
META_GS(true, FEATURE_LEVEL_SM4)
|
||||
[maxvertexcount(3)]
|
||||
void GS_Atmosphere(triangle Quad_VS2PS input[3], inout TriangleStream<AtmosphereGSOutput> output)
|
||||
{
|
||||
AtmosphereGSOutput vertex;
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
vertex.Position = input[i].Position;
|
||||
vertex.TexCoord = input[i].TexCoord;
|
||||
vertex.LayerIndex = AtmosphereLayer;
|
||||
|
||||
output.Append(vertex);
|
||||
}
|
||||
}
|
||||
*/
|
||||
float OpticalDepth(float H, float radius, float Mu)
|
||||
{
|
||||
float result = 0.0;
|
||||
float Ti = Limit(radius, Mu) / float(TransmittanceIntegralSamples);
|
||||
float Xi = 0.0;
|
||||
float Yi = exp(-(radius - RadiusGround) / H);
|
||||
|
||||
float result = 0.0f;
|
||||
float ti = Limit(radius, mu) / float(TransmittanceIntegralSamples);
|
||||
float xi = 0.0f;
|
||||
float yi = exp(-(radius - RadiusGround) / h);
|
||||
LOOP
|
||||
for (int i = 1; i <= TransmittanceIntegralSamples; i++)
|
||||
{
|
||||
float Xj = float(i) * Ti;
|
||||
float Yj = exp(-(sqrt(radius * radius + Xj * Xj + 2.0 * Xj * radius * Mu) - RadiusGround) / H);
|
||||
result += (Yi + Yj) / 2.0 * Ti;
|
||||
Xi = Xj;
|
||||
Yi = Yj;
|
||||
float xj = float(i) * ti;
|
||||
float yj = exp(-(sqrt(radius * radius + xj * xj + 2.0f * xj * radius * mu) - RadiusGround) / h);
|
||||
result += (yi + yj) * 0.5f * ti;
|
||||
xi = xj;
|
||||
yi = yj;
|
||||
}
|
||||
|
||||
return Mu < -sqrt(1.0 - (RadiusGround / radius) * (RadiusGround / radius)) ? 1e9 : result;
|
||||
return mu < -sqrt(1.0f - (RadiusGround / radius) * (RadiusGround / radius)) ? 1e9 : result;
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_Transmittance(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
float radius, MuS;
|
||||
GetTransmittanceRMuS(input.TexCoord, radius, MuS);
|
||||
float3 depth = BetaRayleighScattering * OpticalDepth(HeightScaleRayleigh, radius, MuS) + BetaMieExtinction * OpticalDepth(HeightScaleMie, radius, MuS);
|
||||
return float4(exp(-depth), 0.0f); // Eq (5)
|
||||
float radius, mus;
|
||||
GetTransmittanceRMuS(input.TexCoord, radius, mus);
|
||||
float3 depth = BetaRayleighScattering * GetOpticalDepth(HeightScaleRayleigh, radius, mus) + BetaMieExtinction * GetOpticalDepth(HeightScaleMie, radius, mus);
|
||||
return float4(exp(-depth), 0.0f);
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_Irradiance1(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
float radius, MuS;
|
||||
GetIrradianceRMuS(input.TexCoord, radius, MuS);
|
||||
return float4(Transmittance(radius, MuS) * max(MuS, 0.0), 0.0);
|
||||
float radius, mus;
|
||||
GetIrradianceRMuS(input.TexCoord, radius, mus);
|
||||
return float4(Transmittance(radius, mus) * max(mus, 0.0f), 0.0f);
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_IrradianceN(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
float radius, MuS;
|
||||
GetIrradianceRMuS(input.TexCoord, radius, MuS);
|
||||
float3 S = float3(sqrt(max(1.0 - MuS * MuS, 0.0)), 0.0, MuS);
|
||||
float3 result = float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Integral over 2.PI around x with two nested loops over W directions (theta, phi) -- Eq (15)
|
||||
float radius, mus;
|
||||
GetIrradianceRMuS(input.TexCoord, radius, mus);
|
||||
float3 s = float3(sqrt(max(1.0f - mus * mus, 0.0f)), 0.0f, mus);
|
||||
float3 result = float3(0, 0, 0);
|
||||
for (int iPhi = 0; iPhi < 4 * IrradianceIntegralSamplesHalf; iPhi++)
|
||||
{
|
||||
float phi = (float(iPhi) + 0.5) * IrradianceDeltaPhi;
|
||||
float phi = (float(iPhi) + 0.5f) * IrradianceDeltaPhi;
|
||||
for (int iTheta = 0; iTheta < IrradianceIntegralSamplesHalf; iTheta++)
|
||||
{
|
||||
float theta = (float(iTheta) + 0.5) * IrradianceDeltaTheta;
|
||||
float Dw = IrradianceDeltaTheta * IrradianceDeltaPhi * sin(theta);
|
||||
float3 W = float3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta));
|
||||
float Nu = dot(S, W);
|
||||
float theta = (float(iTheta) + 0.5f) * IrradianceDeltaTheta;
|
||||
float dw = IrradianceDeltaTheta * IrradianceDeltaPhi * sin(theta);
|
||||
float3 w = float3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta));
|
||||
float nu = dot(s, w);
|
||||
|
||||
if (FirstOrder == 1.0)
|
||||
if (First == 1.0f)
|
||||
{
|
||||
// First iteration is special because Rayleigh and Mie were stored separately,
|
||||
// without the phase functions factors; they must be reintroduced here
|
||||
float Pr1 = PhaseFunctionR(Nu);
|
||||
float Pm1 = PhaseFunctionM(Nu);
|
||||
float3 Ray1 = Texture4DSample(AtmosphereDeltaSRTexture, radius, W.z, MuS, Nu).rgb;
|
||||
float3 Mie1 = Texture4DSample(AtmosphereDeltaSMTexture, radius, W.z, MuS, Nu).rgb;
|
||||
|
||||
result += (Ray1 * Pr1 + Mie1 * Pm1) * W.z * Dw;
|
||||
float pr1 = PhaseFunctionR(nu);
|
||||
float pm1 = PhaseFunctionM(nu);
|
||||
float3 ray1 = Texture4DSample(AtmosphereDeltaSRTexture, radius, w.z, mus, nu).xyz;
|
||||
float3 mie1 = Texture4DSample(AtmosphereDeltaSMTexture, radius, w.z, mus, nu).xyz;
|
||||
result += (ray1 * pr1 + mie1 * pm1) * w.z * dw;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += Texture4DSample(AtmosphereDeltaSRTexture, radius, W.z, MuS, Nu).rgb * W.z * Dw;
|
||||
result += Texture4DSample(AtmosphereDeltaSRTexture, radius, w.z, mus, nu).xyz * w.z * dw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return float4(result, 0.0);
|
||||
}
|
||||
|
||||
@@ -146,217 +118,185 @@ float4 PS_CopyIrradiance1(Quad_VS2PS input) : SV_Target0
|
||||
return AtmosphereDeltaETexture.Sample(SamplerLinearClamp, input.TexCoord);
|
||||
}
|
||||
|
||||
void Integrand(float radius, float Mu, float MuS, float Nu, float T, out float3 Ray, out float3 Mie)
|
||||
void Integrand(float radius, float mu, float mus, float nu, float t, out float3 ray, out float3 mie)
|
||||
{
|
||||
Ray = float3(0, 0, 0);
|
||||
Mie = float3(0, 0, 0);
|
||||
float Ri = sqrt(radius * radius + T * T + 2.0 * radius * Mu * T);
|
||||
float MuSi = (Nu * T + MuS * radius) / Ri;
|
||||
Ri = max(RadiusGround, Ri);
|
||||
if (MuSi >= -sqrt(1.0 - RadiusGround * RadiusGround / (Ri * Ri)) )
|
||||
ray = float3(0, 0, 0);
|
||||
mie = float3(0, 0, 0);
|
||||
float ri = sqrt(radius * radius + t * t + 2.0f * radius * mu * t);
|
||||
float musi = (nu * t + mus * radius) / ri;
|
||||
ri = max(RadiusGround, ri);
|
||||
if (musi >= -sqrt(1.0 - RadiusGround * RadiusGround / (ri * ri)) )
|
||||
{
|
||||
float3 Ti = TransmittanceWithDistance(radius, Mu, T) * Transmittance(Ri, MuSi);
|
||||
Ray = exp(-(Ri - RadiusGround) / HeightScaleRayleigh) * Ti;
|
||||
Mie = exp(-(Ri - RadiusGround) / HeightScaleMie) * Ti;
|
||||
float3 ti = TransmittanceWithDistance(radius, mu, t) * Transmittance(ri, musi);
|
||||
ray = exp(-(ri - RadiusGround) / HeightScaleRayleigh) * ti;
|
||||
mie = exp(-(ri - RadiusGround) / HeightScaleMie) * ti;
|
||||
}
|
||||
}
|
||||
|
||||
// For Inscatter 1
|
||||
void Inscatter(float radius, float Mu, float MuS, float Nu, out float3 Ray, out float3 Mie)
|
||||
void Inscatter(float radius, float mu, float mus, float nu, out float3 ray, out float3 mie)
|
||||
{
|
||||
Ray = float3(0, 0, 0);
|
||||
Mie = float3(0, 0, 0);
|
||||
float Dx = Limit(radius, Mu) / float(InscatterIntegralSamples);
|
||||
float Xi = 0.0;
|
||||
float3 Rayi;
|
||||
float3 Miei;
|
||||
Integrand(radius, Mu, MuS, Nu, 0.0, Rayi, Miei);
|
||||
ray = float3(0, 0, 0);
|
||||
mie = float3(0, 0, 0);
|
||||
float dx = Limit(radius, mu) / float(InscatterIntegralSamples);
|
||||
float xi = 0.0f;
|
||||
float3 rayi;
|
||||
float3 miei;
|
||||
Integrand(radius, mu, mus, nu, 0.0f, rayi, miei);
|
||||
for (int i = 1; i <= InscatterIntegralSamples; i++)
|
||||
{
|
||||
float Xj = float(i) * Dx;
|
||||
float xj = float(i) * dx;
|
||||
float3 Rayj;
|
||||
float3 Miej;
|
||||
Integrand(radius, Mu, MuS, Nu, Xj, Rayj, Miej);
|
||||
Ray += (Rayi + Rayj) / 2.0 * Dx;
|
||||
Mie += (Miei + Miej) / 2.0 * Dx;
|
||||
Xi = Xj;
|
||||
Rayi = Rayj;
|
||||
Miei = Miej;
|
||||
Integrand(radius, mu, mus, nu, xj, Rayj, Miej);
|
||||
ray += (rayi + Rayj) * 0.5f * dx;
|
||||
mie += (miei + Miej) * 0.5f * dx;
|
||||
xi = xj;
|
||||
rayi = Rayj;
|
||||
miei = Miej;
|
||||
}
|
||||
Ray *= BetaRayleighScattering;
|
||||
Mie *= BetaMieScattering;
|
||||
}
|
||||
|
||||
struct Inscatter1Output
|
||||
{
|
||||
float4 DeltaSR : SV_Target0;
|
||||
float4 DeltaSM : SV_Target1;
|
||||
};
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_Inscatter1_A(AtmosphereGSOutput input) : SV_Target
|
||||
{
|
||||
float3 Ray;
|
||||
float3 Mie;
|
||||
float Mu, MuS, Nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu);
|
||||
Inscatter(AtmosphereR, Mu, MuS, Nu, Ray, Mie);
|
||||
|
||||
// Store separately Rayleigh and Mie contributions, WITHOUT the phase function factor (cf "Angular precision")
|
||||
return float4(Ray, 1);
|
||||
ray *= BetaRayleighScattering;
|
||||
mie *= BetaMieScattering;
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_CopyInscatter1(AtmosphereGSOutput input) : SV_Target0
|
||||
float4 PS_Inscatter1_A(Quad_VS2PS input) : SV_Target
|
||||
{
|
||||
float3 UVW = float3(input.TexCoord, (float(AtmosphereLayer) + 0.5f) / float(AtmosphericFogInscatterAltitudeSampleNum));
|
||||
float4 Ray = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, UVW);
|
||||
float4 Mie = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, UVW);
|
||||
return float4(Ray.rgb, Mie.r);
|
||||
float3 ray;
|
||||
float3 mie;
|
||||
float mu, mus, nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu);
|
||||
Inscatter(AtmosphereR, mu, mus, nu, ray, mie);
|
||||
return float4(ray, 1);
|
||||
}
|
||||
|
||||
// For Inscatter S
|
||||
void Inscatter(float Radius, float Mu, float MuS, float Nu, out float3 RayMie)
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_CopyInscatter1(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
Radius = clamp(Radius, RadiusGround, RadiusAtmosphere);
|
||||
Mu = clamp(Mu, -1.0, 1.0);
|
||||
MuS = clamp(MuS, -1.0, 1.0);
|
||||
float variation = sqrt(1.0 - Mu * Mu) * sqrt(1.0 - MuS * MuS);
|
||||
Nu = clamp(Nu, MuS * Mu - variation, MuS * Mu + variation);
|
||||
float3 uvw = float3(input.TexCoord, (float(AtmosphereLayer) + 0.5f) / float(AtmosphericFogInscatterAltitudeSampleNum));
|
||||
float4 ray = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, uvw);
|
||||
float4 mie = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, uvw);
|
||||
return float4(ray.xyz, mie.x);
|
||||
}
|
||||
|
||||
float cThetaMin = -sqrt(1.0 - (RadiusGround / Radius) * (RadiusGround / Radius));
|
||||
void Inscatter(float radius, float mu, float mus, float nu, out float3 rayMie)
|
||||
{
|
||||
radius = clamp(radius, RadiusGround, RadiusAtmosphere);
|
||||
mu = clamp(mu, -1.0f, 1.0f);
|
||||
mus = clamp(mus, -1.0f, 1.0f);
|
||||
float variation = sqrt(1.0f - mu * mu) * sqrt(1.0f - mus * mus);
|
||||
nu = clamp(nu, mus * mu - variation, mus * mu + variation);
|
||||
float cThetaMin = -sqrt(1.0f - (RadiusGround / radius) * (RadiusGround / radius));
|
||||
float3 v = float3(sqrt(1.0f - mu * mu), 0.0f, mu);
|
||||
float sx = v.x == 0.0f ? 0.0f : (nu - mus * mu) / v.x;
|
||||
float3 s = float3(sx, sqrt(max(0.0f, 1.0f - sx * sx - mus * mus)), mus);
|
||||
rayMie = float3(0, 0, 0);
|
||||
|
||||
float3 V = float3(sqrt(1.0 - Mu * Mu), 0.0, Mu);
|
||||
float Sx = V.x == 0.0 ? 0.0 : (Nu - MuS * Mu) / V.x;
|
||||
float3 S = float3(Sx, sqrt(max(0.0, 1.0 - Sx * Sx - MuS * MuS)), MuS);
|
||||
|
||||
RayMie = float3(0.f, 0.f, 0.f);
|
||||
|
||||
// Integral over 4.PI around x with two nested loops over W directions (theta, phi) - Eq (7)
|
||||
for (int iTheta = 0; iTheta < InscatterSphericalIntegralSamples; iTheta++)
|
||||
{
|
||||
float theta = (float(iTheta) + 0.5) * InscatterDeltaTheta;
|
||||
float theta = (float(iTheta) + 0.5f) * InscatterDeltaTheta;
|
||||
float cTheta = cos(theta);
|
||||
|
||||
float GReflectance = 0.0;
|
||||
float DGround = 0.0;
|
||||
float3 GTransmittance = float3(0.f, 0.f, 0.f);
|
||||
|
||||
float ground = 0.0f;
|
||||
float3 transmittance = float3(0, 0, 0);
|
||||
float reflectance = 0.0f;
|
||||
if (cTheta < cThetaMin)
|
||||
{
|
||||
// If ground visible in direction W, Compute transparency GTransmittance between x and ground
|
||||
GReflectance = AverageGroundRelectance / PI;
|
||||
DGround = -Radius * cTheta - sqrt(Radius * Radius * (cTheta * cTheta - 1.0) + RadiusGround * RadiusGround);
|
||||
GTransmittance = TransmittanceWithDistance(RadiusGround, -(Radius * cTheta + DGround) / RadiusGround, DGround);
|
||||
{
|
||||
ground = -radius * cTheta - sqrt(radius * radius * (cTheta * cTheta - 1.0f) + RadiusGround * RadiusGround);
|
||||
transmittance = TransmittanceWithDistance(RadiusGround, -(radius * cTheta + ground) / RadiusGround, ground);
|
||||
reflectance = AverageGroundRelectance / PI;
|
||||
}
|
||||
|
||||
for (int iPhi = 0; iPhi < 2 * InscatterSphericalIntegralSamples; iPhi++)
|
||||
{
|
||||
float phi = (float(iPhi) + 0.5) * InscatterDeltaPhi;
|
||||
float Dw = InscatterDeltaTheta * InscatterDeltaPhi * sin(theta);
|
||||
float3 W = float3(cos(phi) * sin(theta), sin(phi) * sin(theta), cTheta);
|
||||
float dw = InscatterDeltaTheta * InscatterDeltaPhi * sin(theta);
|
||||
float3 w = float3(cos(phi) * sin(theta), sin(phi) * sin(theta), cTheta);
|
||||
float nu1 = dot(s, w);
|
||||
float nu2 = dot(v, w);
|
||||
float pr2 = PhaseFunctionR(nu2);
|
||||
float pm2 = PhaseFunctionM(nu2);
|
||||
float3 normal = (float3(0.0f, 0.0f, radius) + ground * w) / RadiusGround;
|
||||
float3 irradiance = Irradiance(AtmosphereDeltaETexture, RadiusGround, dot(normal, s));
|
||||
float3 rayMie1 = reflectance * irradiance * transmittance;
|
||||
|
||||
float Nu1 = dot(S, W);
|
||||
float Nu2 = dot(V, W);
|
||||
float Pr2 = PhaseFunctionR(Nu2);
|
||||
float Pm2 = PhaseFunctionM(Nu2);
|
||||
|
||||
// Compute irradiance received at ground in direction W (if ground visible) =deltaE
|
||||
float3 GNormal = (float3(0.0, 0.0, Radius) + DGround * W) / RadiusGround;
|
||||
float3 GIrradiance = Irradiance(AtmosphereDeltaETexture, RadiusGround, dot(GNormal, S));
|
||||
|
||||
float3 RayMie1; // light arriving at x from direction W
|
||||
|
||||
// First term = light reflected from the ground and attenuated before reaching x, =T.alpha/PI.deltaE
|
||||
RayMie1 = GReflectance * GIrradiance * GTransmittance;
|
||||
|
||||
// Second term = inscattered light, =deltaS
|
||||
if (FirstOrder == 1.0)
|
||||
if (First == 1.0f)
|
||||
{
|
||||
// First iteration is special because Rayleigh and Mie were stored separately,
|
||||
// without the phase functions factors; they must be reintroduced here
|
||||
float Pr1 = PhaseFunctionR(Nu1);
|
||||
float Pm1 = PhaseFunctionM(Nu1);
|
||||
float3 Ray1 = Texture4DSample(AtmosphereDeltaSRTexture, Radius, W.z, MuS, Nu1).rgb;
|
||||
float3 Mie1 = Texture4DSample(AtmosphereDeltaSMTexture, Radius, W.z, MuS, Nu1).rgb;
|
||||
RayMie1 += Ray1 * Pr1 + Mie1 * Pm1;
|
||||
}
|
||||
else
|
||||
float pr1 = PhaseFunctionR(nu1);
|
||||
float pm1 = PhaseFunctionM(nu1);
|
||||
float3 ray1 = Texture4DSample(AtmosphereDeltaSRTexture, radius, w.z, mus, nu1).xyz;
|
||||
float3 mie1 = Texture4DSample(AtmosphereDeltaSMTexture, radius, w.z, mus, nu1).xyz;
|
||||
rayMie1 += ray1 * pr1 + mie1 * pm1;
|
||||
}
|
||||
else
|
||||
{
|
||||
RayMie1 += Texture4DSample(AtmosphereDeltaSRTexture, Radius, W.z, MuS, Nu1).rgb;
|
||||
rayMie1 += Texture4DSample(AtmosphereDeltaSRTexture, radius, w.z, mus, nu1).xyz;
|
||||
}
|
||||
|
||||
// Light coming from direction W and scattered in direction V
|
||||
// = light arriving at x from direction W (RayMie1) * SUM(scattering coefficient * phaseFunction) - Eq (7)
|
||||
RayMie += RayMie1 * (BetaRayleighScattering * exp(-(Radius - RadiusGround) / HeightScaleRayleigh) * Pr2 + BetaMieScattering * exp(-(Radius - RadiusGround) / HeightScaleMie) * Pm2) * Dw;
|
||||
rayMie += rayMie1 * (BetaRayleighScattering * exp(-(radius - RadiusGround) / HeightScaleRayleigh) * pr2 + BetaMieScattering * exp(-(radius - RadiusGround) / HeightScaleMie) * pm2) * dw;
|
||||
}
|
||||
}
|
||||
|
||||
// output RayMie = J[T.alpha/PI.deltaE + deltaS] (line 7 in algorithm 4.1)
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_InscatterS(AtmosphereGSOutput input) : SV_Target0
|
||||
float4 PS_InscatterS(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
float3 RayMie;
|
||||
float Mu, MuS, Nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu);
|
||||
Inscatter(AtmosphereR, Mu, MuS, Nu, RayMie);
|
||||
return float4(RayMie, 0);
|
||||
float3 rayMie;
|
||||
float mu, mus, nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu);
|
||||
Inscatter(AtmosphereR, mu, mus, nu, rayMie);
|
||||
return float4(rayMie, 0);
|
||||
}
|
||||
|
||||
float3 Integrand(float Radius, float Mu, float MuS, float Nu, float T)
|
||||
float3 Integrand(float radius, float mu, float mus, float nu, float t)
|
||||
{
|
||||
float Ri = sqrt(Radius * Radius + T * T + 2.0 * Radius * Mu * T);
|
||||
float Mui = (Radius * Mu + T) / Ri;
|
||||
float MuSi = (Nu * T + MuS * Radius) / Ri;
|
||||
return Texture4DSample(AtmosphereDeltaJTexture, Ri, Mui, MuSi, Nu).rgb * TransmittanceWithDistance(Radius, Mu, T);
|
||||
float ri = sqrt(radius * radius + t * t + 2.0 * radius * mu * t);
|
||||
float mui = (radius * mu + t) / ri;
|
||||
float musi = (nu * t + mus * radius) / ri;
|
||||
return Texture4DSample(AtmosphereDeltaJTexture, ri, mui, musi, nu).xyz * TransmittanceWithDistance(radius, mu, t);
|
||||
}
|
||||
|
||||
// InscatterN
|
||||
float3 Inscatter(float Radius, float Mu, float MuS, float Nu)
|
||||
float3 Inscatter(float radius, float mu, float mus, float nu)
|
||||
{
|
||||
float3 RayMie = float3(0.f, 0.f, 0.f);
|
||||
float Dx = Limit(Radius, Mu) / float(InscatterIntegralSamples);
|
||||
float Xi = 0.0;
|
||||
float3 RayMiei = Integrand(Radius, Mu, MuS, Nu, 0.0);
|
||||
|
||||
float3 rayMie = float3(0, 0, 0);
|
||||
float dx = Limit(radius, mu) / float(InscatterIntegralSamples);
|
||||
float xi = 0.0f;
|
||||
float3 raymiei = Integrand(radius, mu, mus, nu, 0.0f);
|
||||
for (int i = 1; i <= InscatterIntegralSamples; i++)
|
||||
{
|
||||
float Xj = float(i) * Dx;
|
||||
float3 RayMiej = Integrand(Radius, Mu, MuS, Nu, Xj);
|
||||
RayMie += (RayMiei + RayMiej) / 2.0 * Dx;
|
||||
Xi = Xj;
|
||||
RayMiei = RayMiej;
|
||||
float xj = float(i) * dx;
|
||||
float3 RayMiej = Integrand(radius, mu, mus, nu, xj);
|
||||
rayMie += (raymiei + RayMiej) * 0.5f * dx;
|
||||
xi = xj;
|
||||
raymiei = RayMiej;
|
||||
}
|
||||
|
||||
return RayMie;
|
||||
return rayMie;
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_InscatterN(AtmosphereGSOutput input) : SV_Target0
|
||||
float4 PS_InscatterN(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
float Mu, MuS, Nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu);
|
||||
return float4(Inscatter(AtmosphereR, Mu, MuS, Nu), 0);
|
||||
float mu, mus, nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu);
|
||||
return float4(Inscatter(AtmosphereR, mu, mus, nu), 0);
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_CopyInscatterN(AtmosphereGSOutput input) : SV_Target0
|
||||
float4 PS_CopyInscatterN(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
float Mu, MuS, Nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu);
|
||||
float3 UVW = float3(input.TexCoord, (float(AtmosphereLayer) + 0.5f) / float(AtmosphericFogInscatterAltitudeSampleNum));
|
||||
float4 Ray = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, UVW) / PhaseFunctionR(Nu);
|
||||
return float4(Ray.rgb, 0);
|
||||
float mu, mus, nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu);
|
||||
float3 uvw = float3(input.TexCoord, (float(AtmosphereLayer) + 0.5f) / float(AtmosphericFogInscatterAltitudeSampleNum));
|
||||
float4 ray = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, uvw) / PhaseFunctionR(nu);
|
||||
return float4(ray.xyz, 0);
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_Inscatter1_B(AtmosphereGSOutput input) : SV_Target
|
||||
float4 PS_Inscatter1_B(Quad_VS2PS input) : SV_Target
|
||||
{
|
||||
float3 Ray;
|
||||
float3 Mie;
|
||||
float Mu, MuS, Nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu);
|
||||
Inscatter(AtmosphereR, Mu, MuS, Nu, Ray, Mie);
|
||||
return float4(Mie, 1);
|
||||
float3 ray;
|
||||
float3 mie;
|
||||
float mu, mus, nu;
|
||||
GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu);
|
||||
Inscatter(AtmosphereR, mu, mus, nu, ray, mie);
|
||||
return float4(mie, 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user