1. 程式人生 > 其它 >Unity_GlossyEnvironment--包含所有用於轉換粗糙度,對立方體貼圖取樣以及從HDR轉換的程式碼。

Unity_GlossyEnvironment--包含所有用於轉換粗糙度,對立方體貼圖取樣以及從HDR轉換的程式碼。

技術標籤:Unity Shader

UnityStandardBRDF包含檔案包含Unity_GlossyEnvironment函式。它包含所有用於轉換粗糙度,對立方體貼圖取樣以及從HDR轉換的程式碼。

作用:根據粗糙度取樣對應mipmap級別的環境貼圖

取樣環境貼圖得到間接光的環境反射的例子(鏡面反射):

UnityIndirect CreateIndirectLight(Interpolators i, float3 viewDir)
{
    UnityIndirect indirectLight;
    indirectLight.diffuse = 0;
    indirectLight.specular = 0;

    // base pass 才計算環境光
    if defined(FORWARD_BASE_PASS)
        // 計算從反射出來的方向
        // viewDir是片元到攝像機的向量
        // i.normal是片元在世界空間下的法線方向
        float3 reflectionDir = reflect(-viewDir, i.normal)  
    
        // 用於計算的結構體
        Unity_GlossyEnvironmentData envData;     
        envData.roughness = 1 - _Smoothness; // 粗糙度
        envData.reflUVW = reflectionDir;     // 對CubeMap取樣的方向
        indirectLight.specular = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData);
    #endif
    return indirectLight;
}

UNITY_PASS_TEXCUBE是什麼?

原始碼:

// Macros to declare textures and samplers, possibly separately. For platforms
// that have separate samplers & textures (like DX11), and we'd want to conserve
// the samplers.
//  - UNITY_DECLARE_TEX*_NOSAMPLER declares a texture, without a sampler.
//  - UNITY_SAMPLE_TEX*_SAMPLER samples a texture, using sampler from another texture.
//      That another texture must also be actually used in the current shader, otherwise
//      the correct sampler will not be set.
#if defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL) || (defined(SHADER_TARGET_SURFACE_ANALYSIS) && !defined(SHADER_TARGET_SURFACE_ANALYSIS_MOJOSHADER))
    #define UNITY_PASS_TEXCUBE(tex) tex, sampler##tex
#else
    // DX9 style HLSL syntax; same object for texture+sampler
    #define UNITY_PASS_TEXCUBE(tex) tex
#endif

如果是D3D11:

Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData);

就相當於

Unity_GlossyEnvironment(unity_SpecCube0, samplerunity_SpecCube0, unity_SpecCube0_HDR, envData);

Unity_GlossyEnviroment原始碼:

half perceptualRoughnessToMipmapLevel(half perceptualRoughness)
{   
    // 0~1的粗糙度轉換成mipmap級別,UNITY_SPECCUBE_LOD_STEPS是mipmap的最大級別
    return perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS;
}


half3 Unity_GlossyEnvironment (UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn)
{
    half perceptualRoughness = glossIn.roughness;

// TODO: CAUTION: remap from Morten may work only with offline convolution, see impact with runtime convolution!
// For now disabled
#if 0
    // 涉及如何建立mipmap的詳細資訊, 註釋掉的內容
    // 真正的計算三線性過濾mipmap不同級別之間的關係
    float m = PerceptualRoughnessToRoughness(perceptualRoughness); // m is the real roughness parameter
    const float fEps = 1.192092896e-07F;        // smallest such that 1.0+FLT_EPSILON != 1.0  (+1e-4h is NOT good here. is visibly very wrong)
    float n =  (2.0/max(fEps, m*m))-2.0;        // remap to spec power. See eq. 21 in --> https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf

    n /= 4;                                     // remap from n_dot_h formulatino to n_dot_r. See section "Pre-convolved Cube Maps vs Path Tracers" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html

    perceptualRoughness = pow( 2/(n+2), 0.25);      // remap back to square root of real roughness (0.25 include both the sqrt root of the conversion and sqrt for going from roughness to perceptualRoughness)
#else
    // MM: came up with a surprisingly close approximation to what the #if 0'ed out code above does.
    // 得到與上面#if 0差不多效果的程式碼,修正了粗糙度與mipmap級別之間的關係不是線性的問題,計算量小很多。
    perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
#endif

    half mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);
    half3 R = glossIn.reflUVW;
    half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);  // 對cubemap進行取樣

    return DecodeHDR(rgbm, hdr);
}

UNITY_ARGS_TEXCUBE(tex)是什麼?

原始碼:

// Macros to declare textures and samplers, possibly separately. For platforms
// that have separate samplers & textures (like DX11), and we'd want to conserve
// the samplers.
//  - UNITY_DECLARE_TEX*_NOSAMPLER declares a texture, without a sampler.
//  - UNITY_SAMPLE_TEX*_SAMPLER samples a texture, using sampler from another texture.
//      That another texture must also be actually used in the current shader, otherwise
//      the correct sampler will not be set.
#if defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL) || (defined(SHADER_TARGET_SURFACE_ANALYSIS) && !defined(SHADER_TARGET_SURFACE_ANALYSIS_MOJOSHADER))
    #define UNITY_ARGS_TEXCUBE(tex) TextureCube tex, SamplerState sampler##tex
#else
    // DX9 style HLSL syntax; same object for texture+sampler
    #define UNITY_ARGS_TEXCUBE(tex) samplerCUBE tex
#endif

如果是D3D11:

half3 Unity_GlossyEnvironment (UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn)

相當於

half3 Unity_GlossyEnvironment (TextureCube tex, SamplerState samplertex, half4 hdr, Unity_GlossyEnvironmentData glossIn)

其中samplertex是配合UNITY_SAMPLE_TEXCUBE_LOD的

UNITY_SAMPLE_TEXCUBE_LOD是什麼?

原始碼:

// Macros to declare textures and samplers, possibly separately. For platforms
// that have separate samplers & textures (like DX11), and we'd want to conserve
// the samplers.
//  - UNITY_DECLARE_TEX*_NOSAMPLER declares a texture, without a sampler.
//  - UNITY_SAMPLE_TEX*_SAMPLER samples a texture, using sampler from another texture.
//      That another texture must also be actually used in the current shader, otherwise
//      the correct sampler will not be set.
#if defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL) || (defined(SHADER_TARGET_SURFACE_ANALYSIS) && !defined(SHADER_TARGET_SURFACE_ANALYSIS_MOJOSHADER))
    #define UNITY_SAMPLE_TEXCUBE_LOD(tex,coord,lod) tex.SampleLevel (sampler##tex,coord, lod)
#else
    // DX9 style HLSL syntax; same object for texture+sampler
    #define UNITY_SAMPLE_TEXCUBE_LOD(tex,coord,lod) texCUBElod (tex, half4(coord, lod))
#endif

如果是D3D11:

half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);

相當於:

half4 rgbm = tex.SampleLevel (samplertex, R, mip);

DecodeHDR是什麼樣的?

因為立方體貼圖包含HDR(高動態範圍)顏色,這使其可以包含大於1的亮度值。我們必須將樣本從HDR格式轉換為RGB。

HDR資料使用RGBM格式儲存在四個通道中。因此,我們必須取樣一個half4值,然後進行轉換。

RGBM包含三個RGB通道,以及一個包含幅度因子的M通道。通過將它們乘以 圖片 來計算最終的RGB值。這裡,x 是標量,y 是指數,儲存在解碼指令的前兩個部分中。

// Decodes HDR textures
// handles dLDR, RGBM formats
inline half3 DecodeHDR (half4 data, half4 decodeInstructions)
{
    // Take into account texture alpha if decodeInstructions.w is true(the alpha value affects the RGB channels)
    half alpha = decodeInstructions.w * (data.a - 1.0) + 1.0;

    // If Linear mode is not supported we can skip exponent part
    #if defined(UNITY_COLORSPACE_GAMMA)
        return (decodeInstructions.x * alpha) * data.rgb;
    #else
    #   if defined(UNITY_USE_NATIVE_HDR)
            return decodeInstructions.x * data.rgb; // Multiplier for future HDRI relative to absolute conversion.
    #   else
            return (decodeInstructions.x * pow(alpha, decodeInstructions.y)) * data.rgb;
    #   endif
    #endif
}

M通道的轉換是必需的,因為當儲存在紋理中時,它被限制為0到1範圍內的8位值。所以 X 指令將其放大,並且 y指令使它成為非線性的,就像伽瑪空間一樣。