slang-shaders/stereoscopic-3d/shaders/fubax_vr/fubax_vr_shared_funcs.inc

206 lines
6.3 KiB
C++

// Adjust to limited RGB
vec3 tv(vec3 Input)
{ return Input*((235.0-16.0)/255.0)+16.0/255.0; }
// Generate test grid
vec3 Grid(vec2 Coordinates, float AspectRatio)
{
// Grid settings
#ifndef BoxAmount
#define BoxAmount 31 // Number of boxes horizontally (choose odd number)
#endif
#ifndef thicknessA
#define thicknessA 0.25 // White grid thickness
#endif
#ifndef thicknessB
#define thicknessB 0.125 // Yellow cross thickness
#endif
#ifndef crossColor
#define crossColor vec3(1.0, 1.0, 0.0) // Center cross color (yellow)
#endif
bool RadialPattern = (SoloLines == 3);
vec2 GridCoord = Coordinates;
GridCoord.y -= 0.5; // Center coordinates vertically
GridCoord.y /= AspectRatio; // Correct aspect
GridCoord.y += 0.5; // Center at middle
vec2 CrossUV = GridCoord; // Store center cross coordinates
vec2 PixelSize; vec3 gridColor;
// Generate grid pattern
GridCoord = (RadialPattern) ? vec2(length(GridCoord-0.5)*1.618) : GridCoord; // Switch to radial pattern
GridCoord = abs(fract(GridCoord*BoxAmount)*2.0-1.0)*(thicknessA+1.0);
// Anti-aliased grid
PixelSize = fwidth(GridCoord.xy);
GridCoord = smoothstep(1.0-PixelSize, 1.0+PixelSize, GridCoord);
// Combine/solo vertical and horizontal lines
switch(SoloLines)
{
case 1:
{ gridColor = vec3(GridCoord.y); break; }
case 2:
{ gridColor = vec3(GridCoord.x); break; }
default:
{ gridColor = vec3(max(GridCoord.x, GridCoord.y)); break; }
};
// Generate center cross
CrossUV = 1.0-abs(CrossUV*2.0-1.0);
CrossUV = CrossUV*(thicknessB/BoxAmount+1.0);
// Anti-aliased cross
PixelSize = fwidth(CrossUV);
CrossUV = smoothstep(1.0-PixelSize, 1.0+PixelSize, CrossUV);
// Combine vertical and horizontal line
float CrossMask = max(CrossUV.y, CrossUV.x);
// Blend grid and center cross
gridColor = mix(gridColor, ((RadialPattern) ? vec3(1.0) : crossColor), vec3(CrossMask));
// Solo colors
if(SoloGreen) gridColor.b = 0.0;
if(SoloBlue) gridColor.g = 0.0;
// Reduce grid brightness
return tv(gridColor);
}
// Divide screen into two halfs
vec2 StereoVision(vec2 Coordinates, float Center)
{
vec2 StereoCoord = Coordinates;
StereoCoord.x = 0.25 + abs( StereoCoord.x*2.0-1.0 ) * 0.5; // Divide screen in two
StereoCoord.x -= mix(-0.25, 0.25, Center); // Change center for interpupillary distance (IPD)
// Mirror left half
float ScreenSide = step(0.5, Coordinates.x);
StereoCoord.x *= ScreenSide*2.0-1.0;
StereoCoord.x += 1.0 - ScreenSide;
return StereoCoord;
}
// Convert stereo coordinates to mono
vec2 InvStereoVision(vec2 Coordinates, int ScreenMask, float Center)
{
vec2 stereoCoord = Coordinates;
stereoCoord.x += Center*0.5 * ScreenMask;
return stereoCoord;
}
// Generate border mask with anti-aliasing from UV coordinates
float BorderMaskAA(vec2 Coordinates)
{
vec2 RaidalCoord = abs(Coordinates*2.0-1.0);
// Get pixel size in transformed coordinates (for anti-aliasing)
vec2 PixelSize = fwidth(RaidalCoord);
// Create borders mask (with anti-aliasing)
vec2 Borders = smoothstep(1.0-PixelSize, 1.0+PixelSize, RaidalCoord);
// Combine side and top borders
return max(Borders.x, Borders.y);
}
/*
// Can't really use this one as RetroArch can't access the depth buffer
float GetDepth(vec2 texcoord)
{
return ReShade::GetLinearizedDepth(texcoord);
}
// Horizontal parallax offset effect
vec2 Parallax(vec2 Coordinates, float Offset, float Center, int GapOffset, int Steps)
{
// Limit amount of loop steps to make it finite
#ifndef MaximumParallaxSteps
#def MaximumParallaxSteps 64
#endif
// Offset per step progress
float LayerDepth = 1.0 / min(MaximumParallaxSteps, Steps);
// Netto layer offset change
float deltaCoordinates = Offset * LayerDepth;
vec2 ParallaxCoord = Coordinates;
// Offset image horizontally so that parallax is in the depth appointed center
ParallaxCoord.x += Offset * Center;
float CurrentDepthMapValue = GetDepth(ParallaxCoord); // Replace function
// Steep parallax mapping
float CurrentLayerDepth = 0.0;
[loop]
while(CurrentLayerDepth < CurrentDepthMapValue)
{
// Shift coordinates horizontally in linear fasion
ParallaxCoord.x -= deltaCoordinates;
// Get depth value at current coordinates
CurrentDepthMapValue = GetDepth(ParallaxCoord); // Replace function
// Get depth of next layer
CurrentLayerDepth += LayerDepth;
continue;
}
// Parallax Occlusion Mapping
vec2 PrevParallaxCoord = ParallaxCoord;
PrevParallaxCoord.x += deltaCoordinates;
float afterDepthValue = CurrentDepthMapValue - CurrentLayerDepth;
float beforeDepthValue = GetDepth(PrevParallaxCoord); // Replace function
// Store depth read difference for masking
float DepthDifference = beforeDepthValue - CurrentDepthMapValue;
beforeDepthValue += LayerDepth - CurrentLayerDepth;
// Interpolate coordinates
float weight = afterDepthValue / (afterDepthValue - beforeDepthValue);
ParallaxCoord = PrevParallaxCoord * weight + ParallaxCoord * (1.0 - weight);
// Apply gap masking (by JMF)
DepthDifference *= GapOffset * Offset * 100.0;
DepthDifference *= ReShade::PixelSize.x; // Replace function
ParallaxCoord.x += DepthDifference;
return ParallaxCoord;
};
*/
// Lens projection model (algorithm by JMF)
float Orthographic(float rFOV, float R){ return tan(asin(sin(rFOV*0.5)*R))/(tan(rFOV*0.5)*R); }
float Equisolid(float rFOV, float R){ return tan(asin(sin(rFOV*0.25)*R)*2.0)/(tan(rFOV*0.5)*R); }
float Equidistant(float rFOV, float R){ return tan(R*rFOV*0.5)/(tan(rFOV*0.5)*R); }
float Stereographic(float rFOV, float R){ return tan(atan(tan(rFOV*0.25)*R)*2.0)/(tan(rFOV*0.5)*R); }
// Brown-Conrady radial distortion model (multiply by coordinates)
float kRadial(float R2, float K1, float K2, float K3, float K4)
{ return 1.0 + K1*R2 + K2*pow(R2,2) + K3*pow(R2,4) + K4*pow(R2,6); }
// Brown-Conrady tangental distortion model (add to coordinates)
vec2 pTangental(vec2 Coord, float R2, float P1, float P2, float P3, float P4)
{
return vec2(
(P1*(R2+pow(Coord.x,2)*2.0)+2.0*P2*Coord.x*Coord.y)*(1.0+P3*R2+P4*pow(R2,2)),
(P2*(R2+pow(Coord.y,2)*2.0)+2.0*P1*Coord.x*Coord.y)*(1.0+P3*R2+P4*pow(R2,2))
);
}
// RGB to YUV709.luma
float Luma(vec3 Input)
{
const vec3 Luma709 = vec3(0.2126, 0.7152, 0.0722);
return dot(Input, Luma709);
}
// Overlay blending mode
float Overlay(float LayerA, float LayerB)
{
float MinA = min(LayerA, 0.5);
float MinB = min(LayerB, 0.5);
float MaxA = max(LayerA, 0.5);
float MaxB = max(LayerB, 0.5);
return 2.0 * (MinA * MinB + MaxA + MaxB - MaxA * MaxB) - 1.5;
}