111 lines
3.8 KiB
PostScript
111 lines
3.8 KiB
PostScript
|
/*
|
||
|
=====================================================================
|
||
|
Addon : Parallax Reflex Sights
|
||
|
Link : https://www.moddb.com/mods/stalker-anomaly/addons/parallax-reflex-sights
|
||
|
Authors : LVutner, party_50
|
||
|
Date : 06.02.2024
|
||
|
Last Edit : 06.02.2024
|
||
|
=====================================================================
|
||
|
*/
|
||
|
|
||
|
#include "common.h"
|
||
|
#include "mark_adjust.h"
|
||
|
|
||
|
// Important:
|
||
|
// In perfect world OFFSET constants should be 0, but most of reflex sight lenses
|
||
|
// are not actually parallel to screen, so we compensate it. For PROJECT_DISTANCE=100
|
||
|
// offset values should be at least 0.005 even for perfect models and position configs due
|
||
|
// to normal vectors resolution.
|
||
|
//
|
||
|
// If you want the most realistic look, set PROJECT_DISTANCE to some high value (like 100.0),
|
||
|
// increase SIZE_FACTOR to something like 20.0, set OFFSET_X and OFFSET_Y to 0.005.
|
||
|
// Then you will have to adjust models so that mark texture point is exactly in center
|
||
|
// and edit aim position in configs.
|
||
|
|
||
|
#define OFFSET_X 0.004 // (default 0.004) Normal vector x coordinate max absolute value which is considered 0
|
||
|
#define OFFSET_Y 0.05 // (default 0.05) Normal vector y coordinate max absolute value which is considered 0
|
||
|
#define PROJECT_DISTANCE 20.0 // (default 20.0) Distance to projected mark
|
||
|
#define SIZE_FACTOR 4.0 // (default 4.0) Mark size factor
|
||
|
|
||
|
// Vertex to Pixel struct
|
||
|
struct vf
|
||
|
{
|
||
|
float2 tc0 : TEXCOORD0;
|
||
|
float3 v_pos : TEXCOORD1;
|
||
|
float3 v_nrm : TEXCOORD2;
|
||
|
};
|
||
|
|
||
|
// This gives us cotangent basis that can be used instead of TBN.
|
||
|
// It is useful when tangents of your mesh are broken, or not available.
|
||
|
// Source: http://www.thetenthplanet.de/archives/1180
|
||
|
float3x3 cotangent_frame(float3 N, float3 P, float2 uv)
|
||
|
{
|
||
|
// Get edge vectors of the pixel triangle
|
||
|
float3 dp1 = ddx(P);
|
||
|
float3 dp2 = ddy(P);
|
||
|
float2 duv1 = ddx(uv);
|
||
|
float2 duv2 = ddy(uv);
|
||
|
|
||
|
// Solve the linear system
|
||
|
float3 dp2perp = cross(dp2, N);
|
||
|
float3 dp1perp = cross(N, dp1);
|
||
|
float3 T = dp2perp * duv1.x + dp1perp * duv2.x;
|
||
|
float3 B = dp2perp * duv1.y + dp1perp * duv2.y;
|
||
|
|
||
|
// Construct a scale-invariant frame
|
||
|
float invmax = rsqrt(max(dot(T, T), dot(B, B)));
|
||
|
return float3x3(T * invmax, B * invmax, N);
|
||
|
}
|
||
|
|
||
|
// If N.xy vector is close to zero, make it zero
|
||
|
float3 offset_normal(float3 N)
|
||
|
{
|
||
|
if (N.x > 0)
|
||
|
N.x = max(N.x, OFFSET_X) - OFFSET_X;
|
||
|
else
|
||
|
N.x = min(N.x, -OFFSET_X) + OFFSET_X;
|
||
|
|
||
|
if (N.y > 0)
|
||
|
N.y = max(N.y, OFFSET_Y) - OFFSET_Y;
|
||
|
else
|
||
|
N.y = min(N.y, -OFFSET_Y) + OFFSET_Y;
|
||
|
|
||
|
return N;
|
||
|
}
|
||
|
|
||
|
float4 main(vf I): SV_Target
|
||
|
{
|
||
|
// Derive view direction from view space position
|
||
|
float3 V = -I.v_pos;
|
||
|
|
||
|
// Build cotangent frame
|
||
|
// Important: In theory, you don't need to do this. It should be possible to pass TBN straight from VS
|
||
|
float3x3 TBN = cotangent_frame(offset_normal(I.v_nrm), I.v_pos, I.tc0.xy);
|
||
|
|
||
|
// Transform view direction to tangent space, and normalize (Just in case)
|
||
|
float3 V_tangent = normalize(float3(dot(V, TBN[0]), dot(V, TBN[1]), dot(V, TBN[2])));
|
||
|
|
||
|
// Calculate texture coordinates used to fetch the mark texture
|
||
|
// Important: PROJECT_DISTANCE can be positive or negative, 0 = no projection at all
|
||
|
float2 parallax_tc = I.tc0 - V_tangent.xy * PROJECT_DISTANCE;
|
||
|
|
||
|
// Upscaling the texture
|
||
|
parallax_tc.x = (parallax_tc.x + (SIZE_FACTOR - 1) / 2) / SIZE_FACTOR;
|
||
|
parallax_tc.y = (parallax_tc.y + (SIZE_FACTOR - 1) / 2) / SIZE_FACTOR;
|
||
|
|
||
|
#ifdef MARK_ADJUST
|
||
|
parallax_tc = mark_adjust(parallax_tc);
|
||
|
#endif
|
||
|
|
||
|
// Fetch the mark texture
|
||
|
// Important: We do not want texture to repeat itself, so we use sampler with CLAMP address
|
||
|
// Important2: We do not want to sample mip levels of the mark texture, let's keep this thing sharp as fuck
|
||
|
float4 color = s_base.SampleLevel(smp_rtlinear, parallax_tc, 0.0);
|
||
|
|
||
|
#ifdef MARK_ADJUST
|
||
|
color = lum_adjust(color);
|
||
|
#endif
|
||
|
|
||
|
return color;
|
||
|
}
|