forked from crosire/reshade-shaders
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPerfectPerspective.fx
279 lines (234 loc) · 8.11 KB
/
PerfectPerspective.fx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/*
Copyright (c) 2018 Jacob Maximilian Fober
This work is licensed under the Creative Commons
Attribution-NonCommercial-NoDerivatives 4.0 International License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-nc-nd/4.0/
For inquiries please contact [email protected]
*/
// Perfect Perspective PS ver. 2.7.1
////////////
/// MENU ///
////////////
#include "ReShadeUI.fxh"
uniform int Projection <
ui_tooltip = "Stereographic projection (shape) preserves angles and proportions,\n"
"best for navigation through tight space.\n\n"
"Equisolid projection (distance) preserves size relations,\n"
"best for navigation in open areas.\n\n"
"Equidistant (speed) maintains angular speed of motion,\n"
"best for chasing fast targets.";
#if __RESHADE__ < 40000
ui_label = "Type of projection";
ui_type = "combo";
ui_items = "Stereographic (shape)\0Equisolid (distance)\0Equidistant (speed)\0";
#else
ui_type = "radio";
ui_items = "Stereographic projection (shape)\0Equisolid projection (distance)\0Equidistant projection (speed)\0";
#endif
ui_category = "Distortion Correction";
> = 0;
uniform int FOV < __UNIFORM_SLIDER_INT1
ui_label = "Corrected Field of View";
ui_tooltip = "This setting should match your in-game Field of View";
#if __RESHADE__ < 40000
ui_step = 0.2;
#endif
ui_min = 0; ui_max = 170;
ui_category = "Distortion Correction";
> = 90;
uniform float Vertical < __UNIFORM_SLIDER_FLOAT1
ui_label = "Vertical Curviness Amount";
ui_tooltip = "0.0 - cylindrical projection\n"
"1.0 - spherical projection";
ui_min = 0.0; ui_max = 1.0;
ui_category = "Distortion Correction";
> = 0.5;
uniform float VerticalScale < __UNIFORM_SLIDER_FLOAT1
ui_label = "Vertical Proportions Scale";
ui_tooltip = "Adjust proportions for cylindrical Panini projection";
ui_min = 0.8; ui_max = 1.0;
ui_category = "Distortion Correction";
> = 0.95;
uniform int Type <
ui_label = "Type of FOV (Field of View)";
ui_tooltip = "...in stereographic mode\n\n"
"If image bulges in movement (too high FOV),\n"
"change it to 'Diagonal'.\n"
"When proportions are distorted at the periphery\n"
"(too low FOV), choose 'Vertical'.";
ui_type = "combo";
ui_items = "Horizontal FOV\0Diagonal FOV\0Vertical FOV\0";
ui_category = "Distortion Correction";
> = 0;
uniform float Zooming <
ui_label = "Borders Scale";
ui_tooltip = "Adjust image scale and cropped area";
ui_type = "drag";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.001;
ui_category = "Borders Settings";
> = 1.0;
uniform float4 BorderColor < __UNIFORM_COLOR_FLOAT4
ui_label = "Color of Borders";
ui_tooltip = "Use Alpha to change transparency";
ui_category = "Borders Settings";
> = float4(0.027, 0.027, 0.027, 0.0);
uniform bool MirrorBorders <
ui_label = "Mirrored Borders";
ui_tooltip = "Choose original or mirrored image at the borders";
ui_category = "Borders Settings";
> = true;
uniform bool DebugPreview <
ui_label = "Display Resolution Scale Map";
ui_tooltip = "Color map of the Resolution Scale:\n\n"
" Red - undersampling\n"
" Green - supersampling\n"
" Blue - neutral sampling";
ui_category = "Debug Tools";
> = false;
uniform int2 ResScale <
ui_label = "Super Resolution Scale";
ui_tooltip = "Simulates application running beyond\n"
"native screen resolution (using VSR or DSR)\n\n"
" First value - screen resolution\n"
" Second value - virtual super resolution";
ui_type = "drag";
ui_min = 16; ui_max = 16384; ui_step = 0.2;
ui_category = "Debug Tools";
> = int2(1920, 1920);
//////////////
/// SHADER ///
//////////////
#include "ReShade.fxh"
// Define screen texture with mirror tiles
sampler SamplerColor
{
Texture = ReShade::BackBufferTex;
AddressU = MIRROR;
AddressV = MIRROR;
};
// Convert RGB to grayscale
float Grayscale(float3 Color)
{ return max(max(Color.r,Color.g),Color.b); }
// Perspective lookup functions by Jacob Max Fober
// Input data:
// FOV >> Camera Field of View in degrees
// Coordinates >> UV coordinates (from -1, to 1), where (0,0) is at the center of the screen
// Stereographic
float Stereographic(float2 Coordinates)
{
if(FOV==0.0) return 1.0; // Bypass
// Convert 1/4 FOV to radians and calc tangent squared
float SqrTanFOVq = pow(tan(radians(FOV * 0.25)),2.0);
float R2 = dot(Coordinates, Coordinates);
return (1.0 - SqrTanFOVq) / (1.0 - SqrTanFOVq * R2);
}
// Equisolid
float Equisolid(float2 Coordinates)
{
if(FOV==0.0) return 1.0; // Bypass
float rFOV = radians(FOV);
float R = length(Coordinates);
return tan(asin(sin(rFOV*0.25)*R)*2.0)/(tan(rFOV*0.5)*R);
}
// Equidistant
float Equidistant(float2 Coordinates)
{
if(FOV==0.0) return 1.0; // Bypass
float rFOVh = radians(FOV*0.5);
float R = length(Coordinates);
return tan(R*rFOVh)/(tan(rFOVh)*R);
}
// Shader pass
float3 PerfectPerspectivePS(float4 vois : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
// Get Aspect Ratio
float AspectR = 1.0 / ReShade::AspectRatio;
// Get Screen Pixel Size
float2 ScrPixelSize = ReShade::PixelSize;
// Convert FOV type..
float FovType; switch(Type)
{
case 0:{ FovType = 1.0; break; } // Horizontal
case 1:{ FovType = sqrt(AspectR * AspectR + 1.0); break; } // Diagonal
case 2:{ FovType = AspectR; break; } // Vertical
}
// Convert UV to Radial Coordinates
float2 SphCoord = texcoord * 2.0 - 1.0;
// Aspect Ratio correction
SphCoord.y *= AspectR;
// Zoom in image and adjust FOV type (pass 1 of 2)
// SphCoord *= Zooming / FovType;
SphCoord *= clamp(Zooming, 0.5, 2.0) / FovType; // Anti-cheat
// Perspective lookup, vertical distortion amount and FOV type (pass 2 of 2)
switch(Projection)
{
case 0:{ SphCoord *= Stereographic(float2(SphCoord.x, sqrt(Vertical) * SphCoord.y)) * FovType; break; } // Conformal
case 1:{ SphCoord *= Equisolid(float2(SphCoord.x, sqrt(Vertical) * SphCoord.y)) * FovType; break; } // Equal area
case 2:{ SphCoord *= Equidistant(float2(SphCoord.x, sqrt(Vertical) * SphCoord.y)) * FovType; break; } // Linear scaled
}
// Aspect Ratio back to square
SphCoord.y /= AspectR;
// vertical proportions adjust
if(VerticalScale != 1.0) SphCoord.y /= lerp(VerticalScale, 1.0, Vertical);
// Get Pixel Size in stereographic coordinates
float2 PixelSize = fwidth(SphCoord);
// Outside borders check with Anti-Aliasing
float2 AtBorders = smoothstep( 1.0 - PixelSize, 1.0 + PixelSize, abs(SphCoord) );
// Back to UV Coordinates
SphCoord = SphCoord * 0.5 + 0.5;
// Sample display image
float3 Display = tex2D(SamplerColor, SphCoord).rgb;
// Mask outside-border pixels or mirror
Display = lerp(
Display,
lerp(
MirrorBorders ? Display : tex2D(SamplerColor, texcoord).rgb,
BorderColor.rgb,
BorderColor.a
),
max(AtBorders.x, AtBorders.y)
);
// Output type choice
if(DebugPreview)
{
// Calculate radial screen coordinates before and after perspective transformation
float4 RadialCoord = float4(texcoord, SphCoord) * 2.0 - 1.0;
// Correct vertical aspect ratio
RadialCoord.yw *= AspectR;
// Define Mapping color
static const float3 UnderSmpl = float3(1.0, 0.0, 0.2); // Red
static const float3 SuperSmpl = float3(0.0, 1.0, 0.5); // Green
static const float3 NeutralSmpl = float3(0.0, 0.5, 1.0); // Blue
// Calculate Pixel Size difference...
float PixelScaleMap = fwidth( length(RadialCoord.xy) );
// ...and simulate Dynamic Super Resolution (DSR) scalar
PixelScaleMap *= ResScale.x / (fwidth( length(RadialCoord.zw) ) * ResScale.y);
PixelScaleMap -= 1.0;
// Generate supersampled-undersampled color map
float3 ResMap = lerp(
SuperSmpl,
UnderSmpl,
step(0.0, PixelScaleMap)
);
// Create black-white gradient mask of scale-neutral pixels
PixelScaleMap = 1.0 - abs(PixelScaleMap);
PixelScaleMap = saturate(PixelScaleMap * 4.0 - 3.0); // Clamp to more representative values
// Color neutral scale pixels
ResMap = lerp(ResMap, NeutralSmpl, PixelScaleMap);
// Blend color map with display image
Display = normalize(ResMap) * (0.8 * Grayscale(Display) + 0.2);
}
return Display;
}
//////////////
/// OUTPUT ///
//////////////
technique PerfectPerspective < ui_label = "Perfect Perspective"; ui_tooltip = "Correct fisheye distortion"; >
{
pass
{
VertexShader = PostProcessVS;
PixelShader = PerfectPerspectivePS;
}
}