User Tools

Site Tools


ibl_sample_shader_lys

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ibl_sample_shader_lys [2017/05/16 02:53]
adavies [Downloading and running the shader in FX Composer]
ibl_sample_shader_lys [2017/05/23 03:49]
Line 1: Line 1:
-====== Image Based Lighting Sample Shader ====== 
  
-Throughout the following page we are providing a free IBL sample shader and the associated source files. 
- 
-The shader specifically covers cube maps that have been generated within Lys using the Burley option for image based lighting but may also serve as a useful reference in general. 
- 
- 
-  
-[{{https://​s3.amazonaws.com/​docs.knaldtech.com/​docuwiki/​freeLysIblSample.jpg?​nolink&​1175|The IBL sample shader running in FX Composer 2.51.}}] 
- 
-===== Downloading and running the shader in FX Composer ===== 
- 
----- 
- 
- 
-  - Download the shader and asset files from [[https://​s3-us-west-2.amazonaws.com/​knalduswest/​docs/​freeLysIblSample.zip|HERE]]. 
-  - Download FX Composer from [[http://​developer.download.nvidia.com/​tools/​FX_Composer/​2.5/​FX_Composer2_2.51.0701.1135.exe|HERE]] & install. 
-  - Extract the .zip file to a location of your choosing. 
-  - Double click the freeLysIblSample.fxcproj file found in the extracted folder. 
-  - Ensure that the renderer is set to Direct3D10 by selecting the option found within in the dropdown menu located at the far right of the top top row of buttons. 
-  - Select the IblLysBurley material in the Materials panel. 
-  - Assign the cubemap and textures within the Properties panel by clicking each texture slot and their associated tool buttons> clicking the Image icon> clicking the + icon located at the top left of the popup and then finally selecting the textures you want to load. Repeat for all the textures as required. 
-  - Enjoy! 
- 
-Below is the full shader. You can download the sample shader and assets [[https://​s3-us-west-2.amazonaws.com/​knalduswest/​docs/​freeLysIblSample.zip|HERE]] 
- 
-<code glsl> 
-/* 
- 
-% Copyright 2017 Knald Technologies,​ LLC 
-% See LICENSE.txt for licensing and redistribution terms. 
-% Free IBL sample using cube map exported from Knaldtech'​s tool Lys. https://​www.knaldtech.com/​lys/​ 
-% The cube map was made with offset set to 3 and exported as GGX with Burley roughness drop. 
-% Despite the difference in distribution of MIPs the lit specular response resulting from the “roughness texture” 
-% will be identical to existing PBR based game engines and tools. 
-*/ 
- 
-#define FLT_EPSILON ​    ​1.192092896e-07f ​       // smallest such that 1.0+FLT_EPSILON != 1.0 
- 
-// assume the default value of 3 which assigns maximum roughness to mip level 8x8 
-const int nMipOffset = 3; 
- 
-// global matrices 
-float4x4 g_mObjToViewProj : WorldViewProjection;​ 
-float4x4 g_mObjToWorld : World; 
-float4x4 g_mWorldToObjTransposed : WorldInverseTranspose;​ 
-float4x4 g_mViewToWorld : ViewInverse;​ 
-float4x4 g_mObjToView : WorldView; 
-float4x4 g_mViewToObj : WorldViewInverse;​ 
-float4x4 g_mViewToObjTransposed : WorldViewInverseTranspose;​ 
- 
-// sampler 
-SamplerState samLinear 
-{ 
-    Filter = MIN_MAG_MIP_LINEAR;​ 
-    AddressU = Wrap; 
-    AddressV = Wrap; 
-}; 
- 
- 
-// textures 
- 
-TextureCube lysBurleyCube < 
-    string UIName =  "IBL. cube"; 
-    string ResourceType = "​cube";​ 
->; 
- 
-Texture2D albedo_tex < 
-    string UIName =  "​albedo Texture";​ 
-    string ResourceType = "​2D";​ 
->; 
- 
-Texture2D smoothness_tex < 
-    string UIName =  "​smoothness Texture";​ 
-    string ResourceType = "​2D";​ 
->; 
- 
-Texture2D metalness_tex < 
-    string UIName =  "​metalness Texture";​ 
-    string ResourceType = "​2D";​ 
->; 
- 
-Texture2D normal_tex < 
-    string UIName =  "​normal Texture";​ 
-    string ResourceType = "​2D";​ 
->; 
- 
-Texture2D ao_tex < 
-    string UIName =  "ao Texture";​ 
-    string ResourceType = "​2D";​ 
->; 
- 
- 
-// vertex shader input 
-struct vertInput 
-{ 
-    float4 position : POSITION; 
-    float3 normal : NORMAL; 
-    float3 tang : TANGENT; 
-    float3 bino : BINORMAL; 
-    float2 texcoord : TEXCOORD0; 
-}; 
- 
-// vertex shader output (fed to pixel shader) 
-struct vertexOutput 
-{ 
-    float4 position : POSITION; 
-    float3 pos : TEXCOORD0; 
-    float3 normal : TEXCOORD1; 
-    float2 stcoord : TEXCOORD2; 
-    float3 tang : TEXCOORD3; 
-    float3 bino : TEXCOORD4; 
-}; 
- 
-float SpecularPowerFromPerceptualRoughness(float fPerceptualRoughness);​ 
-float PerceptualRoughnessFromSpecularPower(float fSpecPower);​ 
-float3 EvalBRDF(TextureCube lysBurleyCube,​ float3 vN, float3 vN_unit, float3 to_cam, float perceptualRoughness,​ float metalness, float3 albedo, float ao); 
-float3 GetSpecularDominantDir(float3 vN, float3 vR, float fRealRoughness);​ 
-float RoughnessFromPerceptualRoughness(float fPerceptualRoughness);​ 
-float gain(float value, float g); 
-float GetReductionInMicrofacets(float perceptualRoughness);​ 
-float EmpiricalSpecularAO(float ao, float perceptualRoughness);​ 
-float ApproximateSpecularSelfOcclusion(float3 vR, float3 vertNormalNormalized);​ 
- 
-// Note that our implementation of BurleyToMip() below differs from the more typical 
-// form as cube maps convolved in Lys are based on RdotL and not NdotH. You can find 
-// a more detailed description in "​Pre-convolved Cube Maps vs Path Tracers"​ 
-// Despite the difference in distribution of MIPs the lit specular response resulting from 
-// the “roughness texture” will be identical to existing PBR based game engines and tools. 
-float BurleyToMip(float fPerceptualRoughness,​ int nMips, float NdotR) 
-{ 
-    float fSpecPower = SpecularPowerFromPerceptualRoughness(fPerceptualRoughness);​ 
-    fSpecPower /= (4*max(NdotR,​ FLT_EPSILON)); ​     // see section "​Pre-convolved Cube Maps vs Path Tracers"​ 
-    float fScale = PerceptualRoughnessFromSpecularPower(fSpecPower);​ 
-    return fScale*(nMips-1-nMipOffset);​ 
-} 
- 
-float BurleyToMipSimple(float fPerceptualRoughness,​ int nMips) 
-{ 
-    float fScale = fPerceptualRoughness*(1.7 - 0.7*fPerceptualRoughness); ​   // approximate remap from LdotR based distribution to NdotH 
-    return fScale*(nMips-1-nMipOffset);​ 
-} 
- 
-int GetNumMips(TextureCube cubeTex) 
-{ 
-    int iWidth=0, iHeight=0, numMips=0; 
-    cubeTex.GetDimensions(0,​ iWidth, iHeight, numMips); 
-    return numMips; 
-} 
- 
-// sRGB not built into fx composer. Must do by hand. 
-// don't do this in your own engine. 
-float3 GammaToLinear( float3 color) 
-{ 
-    return pow(color,​2.2);​ 
-} 
- 
-float3 LinearToGamma( float3 linearColor) 
-{ 
-    return pow(linearColor,​1.0/​2.2);​ 
-} 
- 
- 
-// vertex shader 
-vertexOutput main_VS(vertInput IN) 
-{ 
-    vertexOutput res; 
-    ​ 
-    res.stcoord = float2(IN.texcoord.x,​ 1.0-IN.texcoord.y);​ 
-    ​ 
-    // transform attributes to world space 
-    res.pos = mul(float4(IN.position.xyz,​1),​ g_mObjToWorld).xyz;​ 
-    res.tang = normalize( mul(float4(IN.tang,​ 0), g_mObjToWorld ).xyz ); 
-    res.bino = -normalize( mul(float4(IN.bino,​ 0), g_mObjToWorld ).xyz );   // bitangent negated in fxcomposer 
-    ​ 
-    // normals are transformed using inverse transposed so this gives us the normal in world space. 
-    res.normal = normalize( mul(float4(IN.normal.xyz,​0),​ g_mWorldToObjTransposed).xyz ); 
-    ​ 
-    // used by rasterizer 
-    res.position = mul(float4(IN.position.xyz,​ 1.0), g_mObjToViewProj);​ 
-    ​ 
-    return res; 
-} 
- 
-// pixel shader 
-float4 main_FP(vertexOutput IN) : COLOR 
-{ 
-    // gather inputs 
-    float3 vN = IN.normal; 
-    float3 vT = IN.tang; 
-    float3 vB = IN.bino; 
-    float3 vN_unit = normalize(vN);​ 
-    float3 pos = IN.pos; 
-    float2 st = IN.stcoord.xy;​ 
-    ​ 
-    // material properties from texture 
-    float smoothness = smoothness_tex.Sample(samLinear,​ st).x; ​ // not gamma corrected 
-    float perceptualRoughness = 1.0 - smoothness; 
-    float metalness = metalness_tex.Sample(samLinear,​ st).x; ​   // not gamma corrected 
-    float3 texNormal = 2*normal_tex.Sample(samLinear,​ st).xyz - 1.0;    // not gamma corrected 
-    float3 albedo = GammaToLinear( albedo_tex.Sample(samLinear,​ st).xyz ); 
-    float ao = ao_tex.Sample(samLinear,​ st).x; ​ // not gamma corrected 
-    ​ 
-    // get camera position and direction in world space 
-    float3 eyePos = float3(g_mViewToWorld[3].x,​g_mViewToWorld[3].y,​g_mViewToWorld[3].z);​ 
-    float3 to_cam = normalize(eyePos - pos);        // to view vector 
-    ​ 
-    // normal mapping 
- 
-    //vN = normalize(vT*texNormal.x + vB*texNormal.y + vN*texNormal.z); ​            // tangent space normal map 
-    vN = normalize( mul(float4(texNormal.xyz,​0),​ g_mWorldToObjTransposed).xyz );    // object space normal map 
-    //vN = vN_unit; ​    // normal mapping disabled (use interpolated vertex normal) 
-    ​ 
-    // evaluate ibl based brdf 
-    float3 outRadiance = EvalBRDF(lysBurleyCube,​ vN, vN_unit, to_cam, perceptualRoughness,​ metalness, albedo, ao); 
- 
- 
-    // sRGB not built into fx composer. Must do by hand. 
-    // don't do this in your own engine. 
-    return float4(LinearToGamma(outRadiance),​ 1.0); 
-} 
- 
-float3 EvalBRDF(TextureCube lysBurleyCube,​ float3 vN, float3 org_normal, float3 to_cam, float perceptualRoughness,​ float metalness, float3 albedo, float ao) 
-{ 
-    int numMips = GetNumMips(lysBurleyCube);​ 
-    const int nrBrdfMips = numMips-nMipOffset;​ 
-    float VdotN = clamp(dot(to_cam,​ vN), 0.0, 1.0f); ​   // same as NdotR 
-    const float3 vRorg = 2*vN*VdotN-to_cam;​ 
-    ​ 
-    float3 vR = GetSpecularDominantDir(vN,​ vRorg, RoughnessFromPerceptualRoughness(perceptualRoughness));​ 
-    float RdotNsat = saturate(dot(vN,​ vR)); 
-        ​ 
-#if 1    
-    float l = BurleyToMip(perceptualRoughness,​ numMips, RdotNsat); 
-#else 
-    float l = BurleyToMipSimple(perceptualRoughness,​ numMips); 
-#endif 
- 
- 
-    // fxcomposer uses a right hand coordinate frame (unlike d3d which uses left) 
-    // and has Y axis up. We've exported accordingly in Lys. For conventional 
-    // d3d11 just set Y axis as up in Lys before export. 
-    float3 specRad = lysBurleyCube.SampleLevel(samLinear,​ vR, l).xyz; 
-    float3 diffRad = lysBurleyCube.SampleLevel(samLinear,​ vN, (float) (nrBrdfMips-1)).xyz;​ 
-    ​ 
-    ​ 
-    float3 spccol = lerp( (float3) 0.04, albedo, metalness); 
-    float3 dfcol = lerp( (float3) 0.0, albedo, 1-metalness);​ 
-    ​ 
-    // fresnel 
-    float fT = 1.0-RdotNsat;​ 
-    float fT5 = fT*fT; fT5 = fT5*fT5*fT; 
-    spccol = lerp(spccol,​ (float3) 1.0, fT5); 
-    ​ 
-    // take reduction in brightness into account. 
-    float fFade = GetReductionInMicrofacets(perceptualRoughness);​ 
-    fFade *= EmpiricalSpecularAO(ao,​ perceptualRoughness);​ 
-    fFade *= ApproximateSpecularSelfOcclusion(vR,​ org_normal);​ 
-    ​ 
-    // final result 
-    return ao*dfcol*diffRad + fFade*spccol*specRad;​ 
-} 
- 
-float GetReductionInMicrofacets(float perceptualRoughness) 
-{ 
-    // this is not needed if you separately precompute an integrated FG term such as proposed 
-    // by epic. Alternatively this simple analytical approximation retains the energy 
-    // loss associated with Integral GGX(NdotH)*NdotH * (NdotL>​0) dH which 
-    // for GGX equals 1/​(roughness^2+1) when integrated over the half sphere. 
-    // without the NdotL>0 indicator term the integral equals one. 
-    float roughness = RoughnessFromPerceptualRoughness(perceptualRoughness);​ 
-    return 1.0 / (roughness*roughness+1.0);​ 
-} 
- 
-float EmpiricalSpecularAO(float ao, float perceptualRoughness) 
-{ 
-    // basically a ramp curve allowing ao on very diffuse specular 
-    // and gradually less so as the reflection hardens. 
-    float fSmooth = 1-perceptualRoughness;​ 
-    float fSpecAo = gain(ao,​0.5+max(0.0,​fSmooth*0.4));​ 
-    ​ 
-    return min(1.0,​fSpecAo + lerp(0.0, 0.5, fSmooth*fSmooth*fSmooth*fSmooth));​ 
-} 
- 
-// marmoset horizon occlusion http://​marmosetco.tumblr.com/​post/​81245981087 
-float ApproximateSpecularSelfOcclusion(float3 vR, float3 vertNormalNormalized) 
-{ 
-    const float fFadeParam = 1.3; 
-    float rimmask = clamp( 1 + fFadeParam * dot(vR, vertNormalNormalized),​ 0.0, 1.0); 
-    rimmask *= rimmask; 
-    ​ 
-    return rimmask; 
-} 
- 
-float RoughnessFromPerceptualRoughness(float fPerceptualRoughness) 
-{ 
-    return fPerceptualRoughness*fPerceptualRoughness;​ 
-} 
- 
-float PerceptualRoughnessFromRoughness(float fRoughness) 
-{ 
-    return sqrt(max(0.0,​fRoughness));​ 
-} 
- 
-float SpecularPowerFromPerceptualRoughness(float fPerceptualRoughness) 
-{ 
-    float fRoughness = RoughnessFromPerceptualRoughness(fPerceptualRoughness);​ 
-    return (2.0/​max(FLT_EPSILON,​ fRoughness*fRoughness))-2.0;​ 
-} 
- 
-float PerceptualRoughnessFromSpecularPower(float fSpecPower) 
-{ 
-    float fRoughness = sqrt(2.0/​(fSpecPower + 2.0)); 
-    return PerceptualRoughnessFromRoughness(fRoughness);​ 
-} 
- 
-// frostbite presentation (moving frostbite to pbr) 
-float3 GetSpecularDominantDir(float3 vN, float3 vR, float fRealRoughness) 
-{ 
-    float fInvRealRough = saturate(1 - fRealRoughness);​ 
-    float lerpFactor = fInvRealRough * (sqrt(fInvRealRough)+fRealRoughness);​ 
- 
-    return lerp(vN, vR, lerpFactor);​ 
-} 
- 
-float bias(float value, float b) 
-{ 
-    return (b > 0.0) ? pow(value, log(b) / log(0.5)) : 0.0; 
-} 
- 
-// contrast function. 
-float gain(float value, float g) 
-{ 
-    return 0.5 * ((value < 0.5) ? bias(2.0*value,​ 1.0-g) : (2.0 - bias(2.0-2.0*value,​ 1.0-g))); 
-} 
- 
- 
-// set depth, cull and blend states 
-DepthStencilState EnableDepth 
-{ 
-    DepthEnable = TRUE; 
-    DepthWriteMask = ALL; 
-    DepthFunc = LESS_EQUAL; 
-}; 
- 
-BlendState NoBlending 
-{ 
-    AlphaToCoverageEnable = FALSE; 
-    BlendEnable[0] = FALSE; 
-}; 
- 
-RasterizerState RasterizerSettings 
-{ 
-    CullMode = FRONT; 
-    ​ 
-}; 
- 
-technique10 Render { 
-    pass p0 { 
-        SetVertexShader( CompileShader( vs_4_0, main_VS() ) ); 
-        SetPixelShader( CompileShader( ps_4_0, main_FP() ) ); 
-        ​ 
-        SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); 
-        SetDepthStencilState( EnableDepth,​ 0 ); 
-        SetRasterizerState(RasterizerSettings); ​ 
-    } 
-} 
-</​code>​ 
ibl_sample_shader_lys.txt · Last modified: 2017/05/23 03:49 (external edit)