Fix code style

This commit is contained in:
Wojtek Figat
2020-12-21 23:21:46 +01:00
parent 47c0797028
commit 4f954c2eb4
5 changed files with 339 additions and 428 deletions

Binary file not shown.

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}