Shadow Mapping
- Renders the entire scene’s depth from the point of the view of the camera. This data corresponds to a fragment’s z coordinates in clip space.
- Render the entire scene’s shadow map of the light from the point of the view of the light source. Light acts as a camera.
- the depth values tell us how far a ray of light traveled before it hit something.
- multiple renders if shadow cascades is active.
- Compare depth measurements from both points of view. The point is lit if both view points can see the point.
- Unity uses ScreenSpaceShadows shader to samples both depth textures, compares the values, and renders the final shadow value to a screen space shadow map.
URP Cascade: https://zhuanlan.zhihu.com/p/378451316
Water
Harry Alisavaski’s take on water shader: https://halisavakis.com/my-take-on-shaders-stylized-water-shader/
Alan Zucconi: https://www.alanzucconi.com/2019/10/08/journey-sand-shader-4/
screenPos.w: https://forum.unity.com/threads/what-is-screenpos-w.616003/
There are three parts in this water shader: color by depth, specular by normals, and fresnel.
Color by depth
Interpolating color by depth, or the difference between the eye depth and the view space depth, we can create the fog like effect in the water. With multiple lerp
, we can even create foam, intersection, and fog color.
float sceneRawDepth = SampleSceneDepth(screenPos.xy / screenPos.w);
float sceneEyeDepth = LinearEyeDepth(sceneRawDepth, _ZBufferParams)
float diff = saturate( (sceneEyeDepth - screenPos.w) / _Threshold);
It worth to notice that a sine wave created the ripple effect in the intersection. By adding an offset in the foam area, the sine wave extended visually. By adding a foam texture value to the wave, the wave has foam shapes.
Specular by normal
$$ I = (N \cdot H)^{power} * \text{strength} $$
It worth to notice that unpack normal on different platforms is different too. UnpackNormal
usually handles it better than hand written method. It is same as BlendNormal
.
Fresnel
This part changes the transparency in the foam area. Without uniform normal values, there will be more details, but I think the water looks good without it too.
float fresnel = pow(1.0 - saturate(normal, viewDir), _FresnelPower);
float alpha = lerp( lerp(Alpha * fresnel, 1.0, foam), _FogColor.a, fogDiff);
Caustic
FLOGELZ, Caustic effect, Twitter: https://twitter.com/flogelz/status/1165251296720576512?s=20 Alan Zucconi: https://www.alanzucconi.com/2019/09/13/believable-caustics-reflections/
A hacky way to add caustic effect. It samples the same texture twice and blends them by min()
.
Shader
ZTest
https://blog.csdn.net/puppet_master/article/details/53900568
Offset
Offset [factor] [units]
Factor takes z-slope in screen space. Negative number means pulling closer to the camera. If we only have set factor to 1 or -1, it will avoid z-fighting when the camera is NOT perpendicular to the screen, because it has very very little contribution to the z-slope. The equation is:
$$ \text{finalOffset} = r \times \text{factor} + d \times \text{units} $$
r is the z-slope of the geometry, and d is the minimum constant units for the depth offset. d’s value depends on the devices.
WorldDir vs. WorldNormal in Unity Shader
WorldDir
is applying the rotation from the transform matrix.
WorldNormal
is applying the rotation from the inverse transpose matrix.
Why?
Answer:
- http://web.archive.org/web/20120228095346/http://www.arcsynthesis.org/gltut/Illumination/Tut09 Normal Transformation.html
- https://forum.unity.com/threads/difference-between-unityobjecttoworlddir-and-unityobjecttoworldnormal.435302/
keyword
REQUIRES_WORLD_SPACE_POS_INTERPOLATOR
and REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR
https://forum.unity.com/threads/shadow-cascades-weird-since-7-2-0.828453/
URP defines this keyword when the calculation requires world space position. It does NOT mean the shader can calculate world space position in vertex or fragment. It means if the shader requires it. Same to the shadow coord.
In URP’s Lit shader:
Parallax effect defines REQUIRES_TANGENT_SPACE_VIEW_DIR_INTERPOLATOR
. It requires tangent space view direction.
Normal Map defines REQUIRES_WORLD_SPACE_TANGENT_INTERPOLATOR
. It requires world space tangent to calculate tanToWorld
matrix.
Receiving shadows and disabling cascade defines REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR
. So it requires shadowCoord
to get shadow value from shadow maps. Using cascade calls upon TransformWorldToShadowCoord
to get shadowCoord
.
vertex animation
rotate around y-axis https://forum.unity.com/threads/rotating-mesh-in-vertex-shader.501709/
Variable, input, and methods
unity_SpecCube0
contains data for the active reflection probe.
UNITY_SAMPLE_TEXCUBE
samples a cube map.
Decode HDR
In DecodeHDR
and DecodeHDREnvironment
functions:
X and y are in the decodedInstructions
.
RGBM = RGB + Magnitude. The final RGB values is :
$$ xM^{y} \cdot \text{RGB} $$
C#
protected
access modifier is similar to private, but any subclass has access too.
internal
access modifier limit the access in the same assembly
Fractal Brownian Motion
$$ y = A \cdot \sin{(x \cdot \text{frequency})} $$
Adding up different sine waves together to create noise. Different sine waves surely can create some random effect, but Perlin Noise is a better way.
Fractal Brownian Motion: increment the frequencies in regular steps (lacunarity) and decrease the amplitude (gains) of the noise (octaves), we can obtain a finer granularity in the noise and get more fine details.
const int octaves = 1; // add more details, also more self-similarity are added
float lacunarity = 2.0;
float gain = 0.5;
float amplitude = 0.5;
float frequency = 1.0;
for (int i=0; i<octaves; ++i)
{
y += amplitude * noise(frequency * x);
frequency *= lacunarity;
amplitude *= gain;
}
Turbulence. Essentially an fBm, but constructed the absolute value of a signed noise to crate sharp valleys
for (int i=0; i<OCTAVES; ++i)
{
value += amplitude * abs(snoise(st));
st *= 2.0;
amplitude *= .5;
}
Ridge. The sharp valleys are turned upside down to create sharp ridges instead.
n = abs(n); // create creases
n = offset - n; // invert so creases are at top
n = n*n; // sharpen creases
Reading Material:
Normal Map:
- https://forum.unity.com/threads/way-to-bake-_bumpscale-into-a-normal-map-im-atlasing-many-textures.661360/
- https://forum.unity.com/threads/load-and-apply-normal-maps-at-runtime.1140874/
- https://www.fsdeveloper.com/wiki/index.php?title=DXT_compression_explained
Dithered Transparency
Depth Srot
Dissolve Shader
- cyan: https://www.cyanilux.com/tutorials/dissolve-shader-breakdown/
- Febucci: https://www.febucci.com/2018/09/dissolve-shader/
Malioffline Compiler
Light Wrap