84 lines
3.3 KiB
HLSL
84 lines
3.3 KiB
HLSL
// Crest Water System
|
|
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
|
|
|
#ifndef CREST_WATER_FRESNEL_H
|
|
#define CREST_WATER_FRESNEL_H
|
|
|
|
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
|
|
|
|
m_CrestNameSpace
|
|
|
|
float CalculateFresnelReflectionCoefficient(const float i_CosineTheta, const float i_RefractiveIndexOfAir, const float i_RefractiveIndexOfWater)
|
|
{
|
|
// Fresnel calculated using Schlick's approximation.
|
|
// See: http://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf
|
|
// Reflectance at facing angle.
|
|
float R_0 = (i_RefractiveIndexOfAir - i_RefractiveIndexOfWater) / (i_RefractiveIndexOfAir + i_RefractiveIndexOfWater);
|
|
R_0 *= R_0;
|
|
const float R_theta = R_0 + (1.0 - R_0) * pow(max(0., 1.0 - i_CosineTheta), 5.0);
|
|
return R_theta;
|
|
}
|
|
|
|
void ApplyReflectionUnderwater(
|
|
const half3 i_ViewDirectionWS,
|
|
const half3 i_NormalWS,
|
|
const float i_RefractiveIndexOfAir,
|
|
const float i_RefractiveIndexOfWater,
|
|
out float o_LightTransmitted,
|
|
out float o_LightReflected
|
|
) {
|
|
// The the angle of outgoing light from water's surface (whether refracted form outside or internally reflected).
|
|
const float cosOutgoingAngle = max(dot(i_NormalWS, i_ViewDirectionWS), 0.);
|
|
|
|
// Calculate the amount of light transmitted from the sky (o_LightTransmitted).
|
|
{
|
|
// Have to calculate the incident angle of incoming light to water.
|
|
// Surface based on how it would be refracted so as to hit the camera.
|
|
const float cosIncomingAngle = cos(asin(clamp((i_RefractiveIndexOfWater * sin(acos(cosOutgoingAngle))) / i_RefractiveIndexOfAir, -1.0, 1.0)));
|
|
const float reflectionCoefficient = CalculateFresnelReflectionCoefficient(cosIncomingAngle, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater);
|
|
o_LightTransmitted = (1.0 - reflectionCoefficient);
|
|
o_LightTransmitted = max(o_LightTransmitted, 0.0);
|
|
}
|
|
|
|
// Calculate the amount of light reflected from below the water.
|
|
{
|
|
// Angle of incident is angle of reflection.
|
|
const float cosIncomingAngle = cosOutgoingAngle;
|
|
const float reflectionCoefficient = CalculateFresnelReflectionCoefficient(cosIncomingAngle, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater);
|
|
o_LightReflected = reflectionCoefficient;
|
|
}
|
|
}
|
|
|
|
void ApplyFresnel
|
|
(
|
|
const half3 i_ViewDirectionWS,
|
|
const half3 i_NormalWS,
|
|
const bool i_IsUnderwater,
|
|
const float i_RefractiveIndexOfAir,
|
|
const float i_RefractiveIndexOfWater,
|
|
const float i_TirIntensity,
|
|
out float o_LightTransmitted,
|
|
out float o_LightReflected
|
|
)
|
|
{
|
|
o_LightTransmitted = 1.0;
|
|
|
|
if (i_IsUnderwater)
|
|
{
|
|
ApplyReflectionUnderwater(i_ViewDirectionWS, i_NormalWS, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater, o_LightTransmitted, o_LightReflected);
|
|
// Limit how strong TIR is. Not sure if this is the best way but it seems to work gracefully.
|
|
o_LightTransmitted = max(o_LightTransmitted, 1.0 - i_TirIntensity);
|
|
o_LightReflected = min(o_LightReflected, i_TirIntensity);
|
|
}
|
|
else
|
|
{
|
|
const float cosAngle = max(dot(i_NormalWS, i_ViewDirectionWS), 0.0);
|
|
// Hardcode water IOR for above surface.
|
|
o_LightReflected = CalculateFresnelReflectionCoefficient(cosAngle, i_RefractiveIndexOfAir, 1.33);
|
|
}
|
|
}
|
|
|
|
m_CrestNameSpaceEnd
|
|
|
|
#endif
|