/*------------------. | :: Description :: | '-------------------/ Display LUT PS (version 1.3.4) Apply LUT PS (version 2.0.2) Copyright: Display LUT © 2018-2023 Jakub Maksymilian Fober Apply LUT © 2018-2023 Jakub Maksymilian Fober (remix of version 1.0 LUT shader © 2016 Marty McFly) License: This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ */ /*--------------. | :: Commons :: | '--------------*/ #include "ReShade.fxh" #include "ReShadeUI.fxh" /*-------------. | :: Macros :: | '-------------*/ // Define LUT texture size #ifndef LUT_BLOCK_SIZE #define LUT_BLOCK_SIZE 32 #endif // Define LUT texture name #ifndef LUT_FILE_NAME #define LUT_FILE_NAME "lut.png" #endif // Define LUT orientation #ifndef LUT_VERTICAL #define LUT_VERTICAL 0 #endif // Global macros #if LUT_VERTICAL #define LUT_DIMENSIONS int2(LUT_BLOCK_SIZE, LUT_BLOCK_SIZE*LUT_BLOCK_SIZE) #else #define LUT_DIMENSIONS int2(LUT_BLOCK_SIZE*LUT_BLOCK_SIZE, LUT_BLOCK_SIZE) #endif #define LUT_PIXEL_SIZE 1f/LUT_DIMENSIONS /*-----------. | :: Menu :: | '-----------*/ uniform int LutRes < ui_label = "LUT box resolution"; ui_tooltip = "Horizontal resolution equals value squared.\n" "Default 32 is 1024.\n" "To set texture size and name for ApplyLUT, define\n" " LUT_BLOCK_SIZE [number]\n" "and \n" " LUT_FILE_NAME [name]"; ui_type = "drag"; ui_category = "Display LUT settings"; ui_min = 8; ui_max = 128; ui_step = 1; > = 32; uniform bool VerticalOrietation < __UNIFORM_INPUT_BOOL1 ui_label = "Vertical LUT"; ui_tooltip = "Select LUT texture orientation, default is horizontal.\n" "To change orientation for input LUT, add PreProcessor definition 'LUT_VERTICAL true'."; ui_category = "Display LUT settings"; > = false; uniform float2 LutChromaLuma < __UNIFORM_SLIDER_FLOAT2 ui_label = "LUT chroma/luma blend"; ui_tooltip = "How much LUT affects chrominance/luminance"; ui_category = "Apply LUT settings"; ui_min = 0f; ui_max = 1f; ui_step = 0.005; > = float2(1f, 1f); /*----------------. | :: Functions :: | '----------------*/ // Convert 3D LUT texel coordinates to 2D texel coordinates int2 toLut2D(int3 lut3D) { #if LUT_VERTICAL return int2(lut3D.x, lut3D.y+lut3D.z); #else return int2(lut3D.x+lut3D.z, lut3D.y); #endif } /*---------------. | :: Textures :: | '---------------*/ // LUT texture for Apply Lut PS texture LUTTex < source = LUT_FILE_NAME;> { Width = LUT_DIMENSIONS.x; Height = LUT_DIMENSIONS.y; Format = RGBA8; }; sampler LUTSampler { Texture = LUTTex; }; /*--------------. | :: Shaders :: | '--------------*/ // Shader No.1 pass float3 DisplayLutPS( float4 vois : SV_Position, float2 TexCoord : TEXCOORD ) : SV_Target { // Calculate LUT texture bounds float2 LutBounds; if (VerticalOrietation) LutBounds = float2(LutRes, LutRes*LutRes); else LutBounds = float2(LutRes*LutRes, LutRes); LutBounds *= BUFFER_PIXEL_SIZE; if( any(TexCoord>=LutBounds) ) return tex2D(ReShade::BackBuffer, TexCoord).rgb; else { // Generate pattern UV float2 Gradient = TexCoord*BUFFER_SCREEN_SIZE/LutRes; // Convert pattern to RGB LUT float3 LUT; LUT.rg = frac(Gradient)-0.5/LutRes; LUT.rg /= 1f-1f/LutRes; LUT.b = floor(VerticalOrietation? Gradient.g : Gradient.r)/(LutRes-1); // Display LUT texture return LUT; } } // Shader No.2 pass void ApplyLutPS( float4 vois : SV_Position, float2 TexCoord : TEXCOORD, out float3 Image : SV_Target ) { // Grab background color Image = tex2D(ReShade::BackBuffer, TexCoord).rgb; // Convert to sub pixel coordinates float3 lut3D = Image*(LUT_BLOCK_SIZE-1); // Get 2D LUT coordinates float2 lut2D[2]; #if LUT_VERTICAL // Front lut2D[0].x = lut3D.x; lut2D[0].y = floor(lut3D.z)*LUT_BLOCK_SIZE+lut3D.y; // Back lut2D[1].x = lut3D.x; lut2D[1].y = ceil(lut3D.z)*LUT_BLOCK_SIZE+lut3D.y; #else // Front lut2D[0].x = floor(lut3D.z)*LUT_BLOCK_SIZE+lut3D.x; lut2D[0].y = lut3D.y; // Back lut2D[1].x = ceil(lut3D.z)*LUT_BLOCK_SIZE+lut3D.x; lut2D[1].y = lut3D.y; #endif // Convert from texel to texture coords lut2D[0] = (lut2D[0]+0.5)*LUT_PIXEL_SIZE; lut2D[1] = (lut2D[1]+0.5)*LUT_PIXEL_SIZE; // Bicubic LUT interpolation float3 LutImage = lerp( tex2D(LUTSampler, lut2D[0]).rgb, // Front Z tex2D(LUTSampler, lut2D[1]).rgb, // Back Z frac(lut3D.z) ); // Blend LUT image with original if ( all(LutChromaLuma==1f) ) Image = LutImage; else { Image = lerp( normalize(Image), normalize(LutImage), LutChromaLuma.x )*lerp( length(Image), length(LutImage), LutChromaLuma.y ); } } /*-------------. | :: Output :: | '-------------*/ technique DisplayLUT < ui_label = "Display LUT"; ui_tooltip = "Display generated-neutral LUT texture in left to corner of the screen\n" "\n" "How to use:\n" "* adjust lut size\n" "* (optionally) adjust color effecs to bake shaders into LUT\n" "* take a screenshot\n" "* adjust and crop screenshot to texture using external image editor\n" "* load LUT texture in 'Apply LUT .fx'" "\n" "This effect © 2018-2023 Jakub Maksymilian Fober\n" "Licensed under CC BY-SA 4.0"; > { pass { VertexShader = PostProcessVS; PixelShader = DisplayLutPS; } } technique ApplyLUT < ui_label = "Apply LUT"; ui_tooltip = "Apply LUT texture color adjustment\n" "To change texture name, add following to global preprocessor definitions:\n" "\n" " LUT_FILE_NAME 'YourLUT.png'\n" "\n" "To change LUT texture resolution, define:\n" "\n" " LUT_BLOCK_SIZE 17\n" "\n" "To change LUT texture orientation, define:\n" "\n" " LUT_VERTICAL true\n" "\n" "This effect © 2018-2023 Jakub Maksymilian Fober\n" "Licensed under CC BY-SA 4.0"; > { pass { VertexShader = PostProcessVS; PixelShader = ApplyLutPS; } }