[HLSL CODE] 3D LUT

share shaders here
Post Reply
  • Author
  • Message
Offline
*blah-blah-blah maniac*
Posts: 565
Joined: 05 Apr 2014, 10:29
Location: Taiwan

[HLSL CODE] 3D LUT

UE4, Unity compatible 256x16 look up table(LUT)

https://docs.unrealengine.com/latest/IN ... orGrading/
https://docs.unity3d.com/Manual/script- ... ookup.html

the neutral lut here:
Image

dx11: ( Skyrim SE, Fallout 4 )

Code: Select all

//////////////////////////////////////////////////////////////////////////////
// loading lut textures
//////////////////////////////////////////////////////////////////////////////

//ignore this if using DNI 3d lut instead
Texture2D LUTtex          <string ResourceName="LUT.png"; >;  

//DNI luts, ignore these if not going for DNI 3d lut
Texture2D LUTtex_ExtNight <string ResourceName="LUT_ExtNight.png"; >; // for exterior night
Texture2D LUTtex_ExtDay   <string ResourceName="LUT_ExtDay.png";   >; // for exterior day
Texture2D LUTtex_Int      <string ResourceName="LUT_Int.png";      >; // for interior

//////////////////////////////////////////////////////////////////////////////
//3d lut function
//////////////////////////////////////////////////////////////////////////////

static const float2 CLut_Size = float2(256.0, 16.0);

float3 CLutFunc( float3 colorIN, Texture2D lutTexIn ) {
    float2 CLut_pSize = 1.0 / CLut_Size;
    float4 CLut_UV;
    colorIN    = saturate(colorIN) * ( CLut_Size.y - 1.0);
    CLut_UV.w  = floor(colorIN.b);
    CLut_UV.xy = (color.rg + 0.5) * CLut_pSize;
    CLut_UV.x += CLut_UV.w * CLut_pSize.y;
    CLut_UV.z  = CLut_UV.x + CLut_pSize.y;
    return     = lerp(lutTexIn.SampleLevel(Sampler1, CLut_UV.xy, 0).rgb, 
                      lutTexIn.SampleLevel(Sampler1, CLut_UV.zy, 0).rgb, color.b - CLut_UV.w);
}

//////////////////////////////////////////////////////////////////////////////
//pixel shader
//////////////////////////////////////////////////////////////////////////////

float4  PS_Draw(VS_OUTPUT_POST IN, float4 v0 : SV_Position0) : SV_Target
{
    //... other stuff
    
    // without DNI:
    color.rgb = ClutFunc(color.rgb, LUTtex);
    
    // DNI example:
    color.rgb = lerp(lerp(CLutFunc(color.rgb, LUTtex_ExtNight), 
                          CLutFunc(color.rgb, LUTtex_ExtDay), ENightDayFactor),
                          CLutFunc(color.rgb, LUTtex_Int),    EInteriorFactor);
 
    //... other stuff
};
dx9: (Skrim, Fallout 3, Fallout NV)

Code: Select all

//////////////////////////////////////////////////////////////////////////////
//texture helper
//////////////////////////////////////////////////////////////////////////////

#define LOAD_TEXTURE( Name, Path, sampler, UV ) \
texture2D tex##Name <string ResourceName= #Path ; >; \
sampler2D Sampler##Name = sampler_state {   \
    Texture   = < tex##Name >; SRGBTexture=FALSE;   \
    MinFilter = sampler; MagFilter = sampler; MipFilter = NONE; \
    AddressU = UV; AddressV = UV; }   

//////////////////////////////////////////////////////////////////////////////
// loading lut textures
//////////////////////////////////////////////////////////////////////////////

//ignore this if using DNI 3d lut instead
LOAD_TEXTURE( LUT,          LUT.bmp,          LINEAR, CLAMP );

//DNI luts, ignore these if not going for DNI 3d lut
LOAD_TEXTURE( LUT_ExtNight, LUT_ExtNight.bmp, LINEAR, CLAMP ); // exterior night
LOAD_TEXTURE( LUT_ExtDay,   LUT_ExtDay.bmp,   LINEAR, CLAMP ); // exterior day
LOAD_TEXTURE( LUT_Int,      LUT_Int.bmp,      LINEAR, CLAMP ); // interior

//////////////////////////////////////////////////////////////////////////////
//Lut Function
//////////////////////////////////////////////////////////////////////////////
static const float2 CLut_Size = float2(256.0, 16.0);

float3 CLutFunc( float3 colorIN, sampler2D LutSampler ) {
    float2 CLut_pSize = 1.0 / CLut_Size;
    float4 CLut_UV;
    colorIN    = saturate(colorIN) * ( CLut_Size.y - 1.0);
    CLut_UV.w  = floor(colorIN.b);
    CLut_UV.xy = (colorIN.rg + 0.5) * CLut_pSize;
    CLut_UV.x += CLut_UV.w * CLut_pSize.y;
    CLut_UV.z  = CLut_UV.x + CLut_pSize.y;
    return lerp( tex2Dlod(LutSampler, CLut_UV.xyzz).rgb, 
                 tex2Dlod(LutSampler, CLut_UV.zyzz).rgb, colorIN.b - CLut_UV.w);
}

//////////////////////////////////////////////////////////////////////////////
//Pixel Shader
//////////////////////////////////////////////////////////////////////////////

// float4 PS_D6EC7DD1(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR //Skyrim LE
float4 PS_C1DAE3F7(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR //Fallout 3
{
    //... other stuff
    
    // without DNI:
    color.rgb = ClutFunc(color.rgb, SamplerLUT);
    
    // DNI example:
    color.rgb = lerp( lerp( CLutFunc(color.rgb, SamplerLUT_ExtNight), 
                            CLutFunc(color.rgb, SamplerLUT_ExtDay), ENightDayFactor),
                            CLutFunc(color.rgb, SamplerLUT_Int),    EInteriorFactor);
    //... other stuff
};
other dimension will require modifying some constant.
Last edited by kingeric1992 on 24 Jul 2017, 09:18, edited 3 times in total.
_________________
Intel Xeon L5639 6C12T @3.96GHz | Gigabyte ga-x58a-ud3r | MSI GTX680 4G | 48G RAM | Intel 760p Nvme w clover bootloader
Flickr
YouTube

Offline
Posts: 40
Joined: 12 Feb 2013, 22:38
Location: Britain

Re: [HLSL CODE] 3D LUT

Just tried it with the green palette from the unreal website. Seems to work just fine, thanks.
Can't find much more info on it though, do the individual blocks represent anything e.g. is day/night from side to side or top to bottom?
Image

Offline
*blah-blah-blah maniac*
Posts: 565
Joined: 05 Apr 2014, 10:29
Location: Taiwan

Re: [HLSL CODE] 3D LUT

What it does is to turn color A to color B, it doesn't have any day/ night/ adaptation effect
In general, it replicate the color correction process that applied to original LUT.

These are Photoshop tutorial on how to edit them.
https://www.youtube.com/watch?v=7g6kyZ7kRPs
https://www.youtube.com/watch?v=HR_Mj8o-tQ4

If you are not using PS, here is what I conclude from the vids.

1. take a screenshot.
2. tune the screenshot in picture editing software.
3. repeat the same operation in step 2, but on the neutral LUT. (the texture provided in first post)
4. save the LUT and apply to game.

some software might have options to duplicate color operations to different layers, which is very useful at step 3.
_________________
Intel Xeon L5639 6C12T @3.96GHz | Gigabyte ga-x58a-ud3r | MSI GTX680 4G | 48G RAM | Intel 760p Nvme w clover bootloader
Flickr
YouTube

Offline
User avatar
*blah-blah-blah maniac*
Posts: 530
Joined: 30 Jan 2012, 13:18

Re: [HLSL CODE] 3D LUT

Or you can place the LUT in photoshop into the image you want to edit so it adops all the changes. Then just a simple crop and done.

Offline
Posts: 4
Joined: 02 Jul 2015, 12:45

Re: [HLSL CODE] 3D LUT

Great job and work fine! I introduced that in my blog for spread of LUT :D

Offline
Posts: 40
Joined: 12 Feb 2013, 22:38
Location: Britain

Re: [HLSL CODE] 3D LUT

For a laugh, made a Black and White one. The menus, HUD and everything else remain in colour of course.
Image

Offline
Posts: 40
Joined: 12 Feb 2013, 22:38
Location: Britain

Re: [HLSL CODE] 3D LUT

I found this Japanese site which seems to be using an adaptation of your code to enable separate day/night/interior palettes, but I couldn't get it to work. Anybody know anything about it?
http://skyrimshot.blog.fc2.com/blog-entry-78.html

Offline
*blah-blah-blah maniac*
Posts: 565
Joined: 05 Apr 2014, 10:29
Location: Taiwan

Re: [HLSL CODE] 3D LUT

the code tktk provides looks fine, are you sure you followed all the steps? you need to load 2 extra texture and copy the alternative code.
_________________
Intel Xeon L5639 6C12T @3.96GHz | Gigabyte ga-x58a-ud3r | MSI GTX680 4G | 48G RAM | Intel 760p Nvme w clover bootloader
Flickr
YouTube

Offline
User avatar
Posts: 19
Joined: 04 Jan 2016, 14:59

Re: [HLSL CODE] 3D LUT

Is there a neat way of making different LUT textures selectable through the ingame GUI for FO4?

Offline
*blah-blah-blah maniac*
Posts: 565
Joined: 05 Apr 2014, 10:29
Location: Taiwan

Re: [HLSL CODE] 3D LUT

TomDean wrote:Is there a neat way of making different LUT textures selectable through the ingame GUI for FO4?
you can use shader arguments for switching profiles (ie. through TECHNIQUE)

replace:

Code: Select all

float4  PS_Draw(VS_OUTPUT_POST IN, float4 v0 : SV_Position0) : SV_Target
with

Code: Select all

float4  PS_Draw(VS_OUTPUT_POST IN, float4 v0 : SV_Position0, uniform Texture2D LUTtex, uniform bool enablelut) : SV_Target
Also Here is the 3dlut code for dx10/11

Code: Select all

if(enablelut)
{
    float2 CLut_pSize = {0.00390625, 0.0625};// 1 / float2(256, 16)
    color.rgb         = saturate(color.rgb);
    color.b          *= 15;
    float4 CLut_UV    = 0;
    CLut_UV.w         = floor(color.b);
    CLut_UV.xy        = (color.rg * 15 + 0.5) * CLut_pSize;
    CLut_UV.x        += CLut_UV.w * CLut_pSize.y;
    CLut_UV.z         = CLut_UV.x + CLut_pSize.y;
    color.rgb         = lerp(LUTtex.SampleLevel(Sampler1, CLut_UV.xy, 0).rgb, LUTtex.SampleLevel(Sampler1, CLut_UV.zy, 0).rgb, color.b - CLut_UV.w);
}
and under technique section,
replace

Code: Select all

technique11 Draw <string UIName="ENBSeries";>
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_5_0, VS_Draw()));
		SetPixelShader(CompileShader(ps_5_0, PS_Draw()));
	}
}
with

Code: Select all

Texture2D          LUT_default < string UIName = "3DLut0";  string ResourceName = "LUT_default.png"; >; // default Lut
technique11 Draw <string UIName="ENBSeries";>
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_5_0, VS_Draw()));
		SetPixelShader(CompileShader(ps_5_0, PS_Draw(LUT_default, true)));
	}
}

Texture2D          LUT_Preset1 < string UIName = "3DLut1";  string ResourceName = "LUT_Preset1.png"; >; // Preset1 Lut
technique11 Preset1 <string UIName="Preset Name 1";>
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_5_0, VS_Draw()));
		SetPixelShader(CompileShader(ps_5_0, PS_Draw(LUT_Preset1, true)));
	}
}

Texture2D          LUT_Preset2 < string UIName = "3DLut1";  string ResourceName = "LUT_Preset2.png"; >; // Preset2 Lut
technique11 Preset2 <string UIName="Preset Name 2";>
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_5_0, VS_Draw()));
		SetPixelShader(CompileShader(ps_5_0, PS_Draw(LUT_Preset2, true)));
	}
}

//... and so on
set true to false can disable lut for the preset, or use UI to switch it on/off ingame.
_________________
Intel Xeon L5639 6C12T @3.96GHz | Gigabyte ga-x58a-ud3r | MSI GTX680 4G | 48G RAM | Intel 760p Nvme w clover bootloader
Flickr
YouTube
Post Reply