Clients/Client2014/shaders/source/common.h

141 lines
4.2 KiB
C

#include "globals.h"
// GLSLES has limited number of vertex shader registers so we have to use less bones
#ifdef GLSLES
#define MAX_BONE_COUNT 32
#else
#define MAX_BONE_COUNT 72
#endif
// PowerVR saturate() is compiled to min/max pair
// These are cross-platform specialized saturates that are free on PC and only cost 1 cycle on PowerVR
#ifdef GLSLES
float saturate0(float v) { return max(v, 0); }
float saturate1(float v) { return min(v, 1); }
#else
float saturate0(float v) { return saturate(v); }
float saturate1(float v) { return saturate(v); }
#endif
#define GBUFFER_MAX_DEPTH 500.0f
float4 gbufferPack(float depth, float3 diffuse, float3 specular, float fog)
{
depth = saturate(depth / GBUFFER_MAX_DEPTH);
const float3 bitSh = float3(255*255, 255, 1);
const float3 lumVec = float3(0.299, 0.587, 0.114);
float2 comp;
comp = depth*float2(255,255*256);
comp = frac(comp);
comp = float2(depth,comp.x*256/255) - float2(comp.x, comp.y)/255;
float4 result;
result.r = lerp(1, dot(specular, lumVec), saturate(3 * fog));
result.g = lerp(0, dot(diffuse, lumVec), saturate(3 * fog));
result.ba = comp.yx;
return result;
}
float3 getPosInLightSpace(float3 posIn)
{
float3 lightToWorld = posIn - G.BlobShadowData0.xyz;
return float3(dot(G.Lamp0Right, lightToWorld), dot(G.Lamp0Up, lightToWorld), dot(G.Lamp0Dir, lightToWorld));
}
float getSingleBlobShadowOrigin(float3 lightSpacePos, float4 blobData)
{
float distSq = dot(lightSpacePos.xy, lightSpacePos.xy);
// OH MY GOD! a BRANCH? Why? Because this produces a better assembly over other solution
float projDistScaled = lightSpacePos.z * 0.04;
if (lightSpacePos.z < 0)
projDistScaled = lightSpacePos.z * -0.3;
return min(1, distSq * G.OutlineBrightness_ShadowInfo.z + projDistScaled + blobData.a);
}
float getSingleBlobShadow(float3 lightSpacePos, float4 blobData)
{
return getSingleBlobShadowOrigin(lightSpacePos - blobData.xyz, blobData);
}
float getBlobShadow(float3 lightSpacePos)
{
#ifdef PIN_HQ
float shadow = min(getSingleBlobShadowOrigin(lightSpacePos, G.BlobShadowData0), getSingleBlobShadow(lightSpacePos, G.BlobShadowData1));
shadow = min(getSingleBlobShadow(lightSpacePos, G.BlobShadowData2), shadow);
shadow = min(getSingleBlobShadow(lightSpacePos, G.BlobShadowData3), shadow);
return shadow;
#else
return getSingleBlobShadowOrigin(lightSpacePos, G.BlobShadowData0);
#endif
}
float3 lgridOffset(float3 v, float3 n)
{
// cells are 4 studs in size
// offset in normal direction to prevent self-occlusion
// the offset has to be 1.5 cells in order to fully eliminate the influence of the source cell with trilinear filtering
// (i.e. 1 cell is enough for point filtering, but is not enough for trilinear filtering)
return v + n * (1.5f * 4.f);
}
float3 lgridPrepareSample(float3 c)
{
// yxz swizzle is necessary for GLSLES sampling to work efficiently
// (having .y as the first component allows to do the LUT lookup as a non-dependent texture fetch)
return c.yxz * G.LightConfig0.xyz + G.LightConfig1.xyz;
}
#ifdef GLSLES
#define LGRID_SAMPLER sampler2D
float4 lgridSample(LGRID_SAMPLER t, sampler2D lut, float3 data)
{
float4 offsets = tex2D(lut, data.xy);
// texture is 64 pixels high
// let's compute slice lerp coeff
float slicef = frac(data.x * 64);
// texture has 64 slices with 8x8 atlas setup
float2 base = saturate(data.yz) * 0.125;
float4 s0 = tex2D(t, base + offsets.xy);
float4 s1 = tex2D(t, base + offsets.zw);
return lerp(s0, s1, slicef);
}
#else
#define LGRID_SAMPLER sampler3D
float4 lgridSample(LGRID_SAMPLER t, sampler2D lut, float3 data)
{
float3 edge = step(G.LightConfig3.xyz, abs(data - G.LightConfig2.xyz));
float edgef = saturate1(dot(edge, 1));
// replace data with 0 on edges to minimize texture cache misses
float4 light = tex3D(t, data.yzx - data.yzx * edgef);
return lerp(light, G.LightBorder, edgef);
}
#endif
#ifdef GLSLES
float3 nmapUnpack(float4 value)
{
return value.rgb * 2 - 1;
}
#else
float3 nmapUnpack(float4 value)
{
float2 xy = value.ag * 2 - 1;
return float3(xy, sqrt(saturate(1 + dot(-xy, xy))));
}
#endif