verus/Verus/src/Shaders/Lib.hlsl

329 lines
7.6 KiB
HLSL

// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
#define VERUS_UBUFFER struct
#define mataff float4x3
#define _Q_LOW 0
#define _Q_MEDIUM 1
#define _Q_HIGH 2
#define _Q_ULTRA 3
#ifdef _VULKAN
# define VK_LOCATION(x) [[vk::location(x)]]
# define VK_LOCATION_POSITION [[vk::location(0)]]
# define VK_LOCATION_BLENDWEIGHTS [[vk::location(1)]]
# define VK_LOCATION_BLENDINDICES [[vk::location(6)]]
# define VK_LOCATION_NORMAL [[vk::location(2)]]
# define VK_LOCATION_TANGENT [[vk::location(14)]]
# define VK_LOCATION_BINORMAL [[vk::location(15)]]
# define VK_LOCATION_COLOR0 [[vk::location(3)]]
# define VK_LOCATION_COLOR1 [[vk::location(4)]]
# define VK_LOCATION_PSIZE [[vk::location(7)]]
# define VK_PUSH_CONSTANT [[vk::push_constant]]
# define VK_SUBPASS_INPUT(index, tex, sam, slot, space) layout(input_attachment_index = index) SubpassInput<float4> tex : REG(t##slot, space, t##index)
# define VK_SUBPASS_LOAD(tex, sam, tc) tex.SubpassLoad()
# ifdef _VS
# define VK_POINT_SIZE [[vk::builtin("PointSize")]] float psize : PSIZE;
# else
# define VK_POINT_SIZE
# endif
# define VK_SET_POINT_SIZE so.psize = 1.0
#else
# define VK_LOCATION(x)
# define VK_LOCATION_POSITION
# define VK_LOCATION_BLENDWEIGHTS
# define VK_LOCATION_BLENDINDICES
# define VK_LOCATION_NORMAL
# define VK_LOCATION_TANGENT
# define VK_LOCATION_BINORMAL
# define VK_LOCATION_COLOR0
# define VK_LOCATION_COLOR1
# define VK_LOCATION_PSIZE
# define VK_PUSH_CONSTANT
# define VK_SUBPASS_INPUT(index, tex, sam, slot, space)\
Texture2D tex : REG(t##slot, space, t##index);\
SamplerState sam : REG(s##slot, space, s##index)
# define VK_SUBPASS_LOAD(tex, sam, tc) tex.SampleLevel(sam, tc, 0.0)
# define VK_POINT_SIZE
# define VK_SET_POINT_SIZE
#endif
#ifdef _DIRECT3D11
# define CBUFFER(set, type, name) cbuffer type : register(b##set) { type name; }
# define REG(slot, space, sm50slot) register(sm50slot)
#else
# define CBUFFER(set, type, name) ConstantBuffer<type> name : register(b0, space##set);
# define REG(slot, space, sm50slot) register(slot, space)
#endif
#ifdef DEF_INSTANCED
# define _PER_INSTANCE_DATA\
VK_LOCATION(16) float4 matPart0 : INSTDATA0;\
VK_LOCATION(17) float4 matPart1 : INSTDATA1;\
VK_LOCATION(18) float4 matPart2 : INSTDATA2;\
VK_LOCATION(19) float4 instData : INSTDATA3;
#else
# define _PER_INSTANCE_DATA
#endif
// <Constants>
#define _PI 3.141592654
#define _SINGULARITY_FIX 0.001
#define _MAX_TERRAIN_LAYERS 32
// </Constants>
static const float2 _POINT_SPRITE_POS_OFFSETS[4] =
{
float2(-0.5, 0.5),
float2(-0.5, -0.5),
float2(0.5, 0.5),
float2(0.5, -0.5)
};
static const float2 _POINT_SPRITE_TEX_COORDS[4] =
{
float2(0, 0),
float2(0, 1),
float2(1, 0),
float2(1, 1)
};
// <TheMatrix>
#define _TBN_SPACE(tan, bin, nrm)\
const float3x3 matFromTBN = float3x3(tan, bin, nrm);\
const float3x3 matToTBN = transpose(matFromTBN);
matrix ToFloat4x4(mataff m)
{
return matrix(
float4(m[0], 0),
float4(m[1], 0),
float4(m[2], 0),
float4(m[3], 1));
}
// </TheMatrix>
// <ScreenSpace>
float2 ToNdcPos(float2 tc)
{
return tc * float2(2, -2) - float2(1, -1);
}
float2 ToTexCoords(float2 ndcPos)
{
return ndcPos * float2(0.5, -0.5) + 0.5;
}
// </ScreenSpace>
// <Random>
uint3 PcgHash3(uint3 v)
{
v = v * 1664525u + 1013904223u;
v.x += v.y * v.z;
v.y += v.z * v.x;
v.z += v.x * v.y;
v ^= v >> 16u;
v.x += v.y * v.z;
v.y += v.z * v.x;
v.z += v.x * v.y;
return v;
}
uint4 PcgHash4(uint4 v)
{
v = v * 1664525u + 1013904223u;
v.x += v.y * v.w;
v.y += v.z * v.x;
v.z += v.x * v.y;
v.w += v.y * v.z;
v ^= v >> 16u;
v.x += v.y * v.w;
v.y += v.z * v.x;
v.z += v.x * v.y;
v.w += v.y * v.z;
return v;
}
float3 Rand(float2 v)
{
return PcgHash3(uint3(v, 0)) * (1.0 / float(0xFFFFFFFFu));
}
float4 Rand4(float2 v)
{
return PcgHash4(uint4(v, v)) * (1.0 / float(0xFFFFFFFFu));
}
float3 RandomColor(float2 pos, float randLum, float randRGB)
{
const float4 r = Rand4(pos);
return ((1.0 - randLum - randRGB) * 0.5) + r.a * randLum + r.rgb * randRGB;
}
float3 NormalDither(float3 rand)
{
const float2 rr = rand.xy * (1.0 / 400.0) - (0.5 / 400.0);
return float3(rr, 0);
}
float Dither2x2(float2 fragCoord)
{
const float2 pos = floor(fragCoord);
const float scale = 0.5;
return frac((pos.x + pos.y) * scale) + frac(pos.x * scale) * scale;
}
float Dither3x3(float2 fragCoord)
{
const float2 pos = floor(fragCoord);
const float scale = 1.0 / 3.0;
return frac((pos.x + pos.y) * scale) + frac(pos.x * scale) * scale;
}
// </Random>
// <Math>
float ComputeFade(float x, float from, float to)
{
return saturate((x - from) * (1.0 / (to - from)));
}
// Asymmetric abs():
float2 AsymAbs(float2 x, float negScale = -1.0, float posScale = 1.0)
{
return x * lerp(posScale, negScale, step(x, 0.0));
}
float SinAcos(float x) // sin(acos(x))
{
return sqrt(saturate(1.0 - x * x));
}
// </Math>
// <PhysicallyBasedRendering>
// See: https://en.wikipedia.org/wiki/Schlick%27s_approximation
float3 FresnelSchlick(float3 f0, float3 f1, float pow5)
{
return f0 + f1 * pow5;
}
float3 CheapRefract(float3 i, float3 n)
{
return lerp(i, -n, 0.5);
}
// Prevent values from reaching inf and nan.
float3 SaturateHDR(float3 hdr)
{
// Typical ambient lit surface is 4000.
// Typical sunlight lit surface is 16000.
return clamp(hdr, 0.0, 32000.0);
}
// If two channels are mutually exclusive, they can be stored as one channel:
float CombineMutexChannels(float2 x)
{
return saturate((x.x - x.y) * 0.5 + 0.5);
}
float2 SeparateMutexChannels(float x)
{
const float x2 = x * 2.0;
return saturate(float2(x2 - 1.0, 1.0 - x2));
}
float2 CleanMutexChannels(float2 x) // Filter out BC7 compression artifacts:
{
return saturate((x - (15.0 / 255.0)) * (255.0 / 240.0));
}
// </PhysicallyBasedRendering>
// <Misc>
float AlphaToResolveDitheringMask(float alpha)
{
return 1.0 - floor(alpha + (15.0 / 255.0));
}
float UnpackTerrainHeight(float height)
{
return height * 0.01;
}
float ToLandMask(float height)
{
return saturate(height * 0.2 + 1.0); // [-5 to 0] -> [0 to 1]
}
float ToWaterPlanktonMask(float height)
{
const float mask = saturate(height * 0.02 + 1.0); // [-50 to 0] -> [0 to 1]
return mask * mask * mask;
}
// Also known as The Multiplier Map, for hemicube's shape compensation.
float ComputeHemicubeMask(float2 tc)
{
// Hint. Compare two pixels when looking at them from the focal point of hemicube:
// one is in the middle of hemicube's face and the other one is at the corner.
// What will be the ratio of their areas (solid angles)?
const float2 atc = abs(tc * 2.0 - 1.0);
if (atc.y < 0.5)
{
if (atc.x < 0.5)
{
const float3 faceNrm = float3(0, 0, 1);
const float3 v = float3(atc.x * 2.0, atc.y * 2.0, 1);
const float len = length(v);
const float3 vn = v / len;
const float cosLaw = vn.z;
const float distFactor = 1.0 / (len * len);
const float faceFactor = dot(vn, faceNrm);
return cosLaw * distFactor * faceFactor;
}
else
{
const float3 faceNrm = float3(1, 0, 0);
const float3 v = float3(1, atc.y * 2.0, 2.0 - 2.0 * atc.x);
const float len = length(v);
const float3 vn = v / len;
const float cosLaw = vn.z;
const float distFactor = 1.0 / (len * len);
const float faceFactor = dot(vn, faceNrm);
return cosLaw * distFactor * faceFactor;
}
}
else
{
if (atc.x < 0.5)
{
const float3 faceNrm = float3(0, 1, 0);
const float3 v = float3(atc.x * 2.0, 1, 2.0 - 2.0 * atc.y);
const float len = length(v);
const float3 vn = v / len;
const float cosLaw = vn.z;
const float distFactor = 1.0 / (len * len);
const float faceFactor = dot(vn, faceNrm);
return cosLaw * distFactor * faceFactor;
}
else
{
return 0.0;
}
}
}
// </Misc>