国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Overload游戲引擎細節(jié)分析】PBR材質(zhì)Shader---完結(jié)篇

這篇具有很好參考價值的文章主要介紹了【Overload游戲引擎細節(jié)分析】PBR材質(zhì)Shader---完結(jié)篇。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

PBR基于物理的渲染可以實現(xiàn)更加真實的效果,其Shader值得分析一下。但PBR需要較多的基礎(chǔ)知識,不適合不會OpenGL的朋友。

一、PBR理論

PBR指基于物理的渲染,其理論較多,需要的基礎(chǔ)知識也較多,我在這就不再寫一遍了,具體可以參看:
LearnOpenGL PBR理論-英文 或者 LearnOpenGL PBR理論-中文

Overload也提供了這種材料,借助貼圖可以實現(xiàn)非常真實的材質(zhì)效果。下面這個例子的貼圖來自LearnOpenGL,大家可以自己去下載。
【Overload游戲引擎細節(jié)分析】PBR材質(zhì)Shader---完結(jié)篇,Overload游戲引擎細節(jié)分析,游戲引擎,圖形渲染

二、PBR Shader分析

頂點著色器
#shader vertex
#version 430 core

layout (location = 0) in vec3 geo_Pos;
layout (location = 1) in vec2 geo_TexCoords;
layout (location = 2) in vec3 geo_Normal;
layout (location = 3) in vec3 geo_Tangent;
layout (location = 4) in vec3 geo_Bitangent;

/* Global information sent by the engine */
layout (std140) uniform EngineUBO
{
    mat4    ubo_Model;
    mat4    ubo_View;
    mat4    ubo_Projection;
    vec3    ubo_ViewPos;
    float   ubo_Time;
};

/* Information passed to the fragment shader */
out VS_OUT
{
    vec3        FragPos;
    vec3        Normal;
    vec2        TexCoords;
    mat3        TBN;
    flat vec3   TangentViewPos;
    vec3        TangentFragPos;
} vs_out;

void main()
{
    vs_out.TBN = mat3
    (
        normalize(vec3(ubo_Model * vec4(geo_Tangent,   0.0))),
        normalize(vec3(ubo_Model * vec4(geo_Bitangent, 0.0))),
        normalize(vec3(ubo_Model * vec4(geo_Normal,    0.0)))
    );

    mat3 TBNi = transpose(vs_out.TBN);

    vs_out.FragPos          = vec3(ubo_Model * vec4(geo_Pos, 1.0));
    vs_out.Normal           = normalize(mat3(transpose(inverse(ubo_Model))) * geo_Normal);
    vs_out.TexCoords        = geo_TexCoords;
    vs_out.TangentViewPos   = TBNi * ubo_ViewPos;
    vs_out.TangentFragPos   = TBNi * vs_out.FragPos;

    gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0);
}

頂點著色器基本與standard材質(zhì)一致,這里就不再分析了,具體可看standard材質(zhì)Shader

片元著色器:
#shader fragment
#version 430 core

/** 模型視圖矩陣、攝像機位置,使用UBO傳入 */
/* Global information sent by the engine */
layout (std140) uniform EngineUBO
{
    mat4    ubo_Model;
    mat4    ubo_View;
    mat4    ubo_Projection;
    vec3    ubo_ViewPos;
    float   ubo_Time;
};

/* 頂點著色器的輸出 */
/* Information passed from the fragment shader */
in VS_OUT
{
    vec3        FragPos;
    vec3        Normal;
    vec2        TexCoords;
    mat3        TBN;
    flat vec3   TangentViewPos;
    vec3        TangentFragPos;
} fs_in;

/* 光源數(shù)據(jù)用SSBO傳入 */
/* Light information sent by the engine */
layout(std430, binding = 0) buffer LightSSBO
{
    mat4 ssbo_Lights[];
};

out vec4 FRAGMENT_COLOR;

uniform sampler2D   u_AlbedoMap; // 反照率貼圖
uniform sampler2D   u_MetallicMap; // 金屬度貼圖
uniform sampler2D   u_RoughnessMap; // 粗糙度貼圖
uniform sampler2D   u_AmbientOcclusionMap; // 環(huán)境光遮蔽貼圖
uniform sampler2D   u_NormalMap; // 法線貼圖
uniform vec4        u_Albedo                = vec4(1.0); // 反照率系數(shù),控制反照率貼圖的權(quán)重
uniform vec2        u_TextureTiling         = vec2(1.0, 1.0);
uniform vec2        u_TextureOffset         = vec2(0.0, 0.0);
uniform bool        u_EnableNormalMapping   = false;  // 是否使用法線貼圖
uniform float       u_HeightScale           = 0.0;
uniform float       u_Metallic              = 1.0; // 金屬度
uniform float       u_Roughness             = 1.0; // 粗糙度

const float PI = 3.14159265359;

// 計算法向分布函數(shù)D,使用Trowbridge-Reitz GGX  
float DistributionGGX(vec3 N, vec3 H, float roughness)
{
    float a      = roughness*roughness;
    float a2     = a*a;
    float NdotH  = max(dot(N, H), 0.0);
    float NdotH2 = NdotH*NdotH;
	
    float num   = a2;
    float denom = (NdotH2 * (a2 - 1.0) + 1.0);
    denom = PI * denom * denom;
	
    return num / denom;
}


float GeometrySchlickGGX(float NdotV, float roughness)
{
    float r = (roughness + 1.0);
    float k = (r*r) / 8.0;

    float num   = NdotV;
    float denom = NdotV * (1.0 - k) + k;
	
    return num / denom;
}

// Smith’s method
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
{
    float NdotV = max(dot(N, V), 0.0);
    float NdotL = max(dot(N, L), 0.0);
    float ggx2  = GeometrySchlickGGX(NdotV, roughness);
    float ggx1  = GeometrySchlickGGX(NdotL, roughness);
	
    return ggx1 * ggx2;
}

// 菲涅爾項,使用Fresnel-Schlick方程
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

/* 將32位數(shù)字變成RGBA顏色 */
vec3 UnPack(float p_Target)
{
    return vec3
    (
        // CPU傳入的數(shù)據(jù)是0-255,轉(zhuǎn)換成0-1.0
        float((uint(p_Target) >> 24) & 0xff)    * 0.003921568627451,
        float((uint(p_Target) >> 16) & 0xff)    * 0.003921568627451,
        float((uint(p_Target) >> 8) & 0xff)     * 0.003921568627451
    );
}

bool PointInAABB(vec3 p_Point, vec3 p_AabbCenter, vec3 p_AabbHalfSize)
{
    return
    (
        p_Point.x > p_AabbCenter.x - p_AabbHalfSize.x && p_Point.x < p_AabbCenter.x + p_AabbHalfSize.x &&
        p_Point.y > p_AabbCenter.y - p_AabbHalfSize.y && p_Point.y < p_AabbCenter.y + p_AabbHalfSize.y &&
        p_Point.z > p_AabbCenter.z - p_AabbHalfSize.z && p_Point.z < p_AabbCenter.z + p_AabbHalfSize.z
    );
}

/*光照衰減系數(shù),LearnOpenGL中有具體公式*/
float LuminosityFromAttenuation(mat4 p_Light)
{
    const vec3  lightPosition   = p_Light[0].rgb;
    const float constant        = p_Light[0][3];
    const float linear          = p_Light[1][3];
    const float quadratic       = p_Light[2][3];

    const float distanceToLight = length(lightPosition - fs_in.FragPos);
    const float attenuation     = (constant + linear * distanceToLight + quadratic * (distanceToLight * distanceToLight));
    return 1.0 / attenuation;
}

/* 盒狀環(huán)境光 */
vec3 CalcAmbientBoxLight(mat4 p_Light)
{
    const vec3  lightPosition   = p_Light[0].rgb;
    const vec3  lightColor      = UnPack(p_Light[2][0]);
    const float intensity       = p_Light[3][3];
    const vec3  size            = vec3(p_Light[0][3], p_Light[1][3], p_Light[2][3]);

    return PointInAABB(fs_in.FragPos, lightPosition, size) ? lightColor * intensity : vec3(0.0);
}

/* 球狀環(huán)境光 */
vec3 CalcAmbientSphereLight(mat4 p_Light)
{
    const vec3  lightPosition   = p_Light[0].rgb;
    const vec3  lightColor      = UnPack(p_Light[2][0]);
    const float intensity       = p_Light[3][3];
    const float radius          = p_Light[0][3];

    return distance(lightPosition, fs_in.FragPos) <= radius ? lightColor * intensity : vec3(0.0);
}

void main()
{
    vec2 texCoords = u_TextureOffset + vec2(mod(fs_in.TexCoords.x * u_TextureTiling.x, 1), mod(fs_in.TexCoords.y * u_TextureTiling.y, 1));

    vec4 albedoRGBA     = texture(u_AlbedoMap, texCoords) * u_Albedo; // Albedo反照率貼圖數(shù)據(jù)
    vec3 albedo         = pow(albedoRGBA.rgb, vec3(2.2)); // 這種反照率處理方式與LearOpenGL一致
    float metallic      = texture(u_MetallicMap, texCoords).r * u_Metallic; // 金屬度
    float roughness     = texture(u_RoughnessMap, texCoords).r * u_Roughness; // 粗糙度
    float ao            = texture(u_AmbientOcclusionMap, texCoords).r; // 環(huán)境光遮蔽AO
    vec3 normal;

    if (u_EnableNormalMapping) // 是否使用法線貼圖
    {
        normal = texture(u_NormalMap, texCoords).rgb; // 法線貼圖的原始值
        normal = normalize(normal * 2.0 - 1.0);   // 法線貼圖矢量坐標(biāo)范圍變成-1到1
        normal = normalize(fs_in.TBN * normal);   // 變換到全局坐標(biāo)系下
    }
    else
    {
        normal = normalize(fs_in.Normal); // 使用頂點著色器輸出的法線
    }

    vec3 N = normalize(normal); 
    vec3 V = normalize(ubo_ViewPos - fs_in.FragPos); // 計算視線方向

    vec3 F0 = vec3(0.04); 
    F0 = mix(F0, albedo, metallic); // 插值方式得到平面的基礎(chǔ)反射率F0
	           
    // reflectance equation
    vec3 Lo = vec3(0.0);
    vec3 ambientSum = vec3(0.0); // 環(huán)境光結(jié)果

    for (int i = 0; i < ssbo_Lights.length(); ++i) 
    {
        // 兩種環(huán)境光燈光
        if (int(ssbo_Lights[i][3][0]) == 3)
        {
            ambientSum += CalcAmbientBoxLight(ssbo_Lights[i]);
        }
        else if (int(ssbo_Lights[i][3][0]) == 4)
        {
            ambientSum += CalcAmbientSphereLight(ssbo_Lights[i]);
        }
        else
        {
            // calculate per-light radiance
            // 光源方向
            vec3 L = int(ssbo_Lights[i][3][0]) == 1 ? -ssbo_Lights[i][1].rgb : normalize(ssbo_Lights[i][0].rgb - fs_in.FragPos);
            vec3 H = normalize(V + L);// 半程向量
            float distance    = length(ssbo_Lights[i][0].rgb - fs_in.FragPos);
            float lightCoeff = 0.0; // 最終到片元處的光強系數(shù) 

            switch(int(ssbo_Lights[i][3][0]))
            {
                case 0:
                    lightCoeff = LuminosityFromAttenuation(ssbo_Lights[i]) * ssbo_Lights[i][3][3]; // 點光源要考慮隨距離衰減
                    break;

                case 1:
                    lightCoeff = ssbo_Lights[i][3][3]; // 方向光無衰減
                    break;

                // 聚光燈的計算
                case 2:
                    const vec3  lightForward    = ssbo_Lights[i][1].rgb;
                    const float cutOff          = cos(radians(ssbo_Lights[i][3][1]));
                    const float outerCutOff     = cos(radians(ssbo_Lights[i][3][1] + ssbo_Lights[i][3][2]));

                    const vec3  lightDirection  = normalize(ssbo_Lights[i][0].rgb - fs_in.FragPos);
                    const float luminosity      = LuminosityFromAttenuation(ssbo_Lights[i]);

                    /* Calculate the spot intensity */
                    const float theta           = dot(lightDirection, normalize(-lightForward)); 
                    const float epsilon         = cutOff - outerCutOff;
                    const float spotIntensity   = clamp((theta - outerCutOff) / epsilon, 0.0, 1.0);

                    lightCoeff = luminosity * spotIntensity * ssbo_Lights[i][3][3];
                    break;
            }

            vec3 radiance = UnPack(ssbo_Lights[i][2][0]) * lightCoeff;
            
            // cook-torrance brdf
            float NDF = DistributionGGX(N, H, roughness); // 法線分布函數(shù)
            float G   = GeometrySmith(N, V, L, roughness); // 幾何函數(shù)
            vec3 F    = fresnelSchlick(max(dot(H, V), 0.0), F0); // 菲涅爾項
            
            vec3 kS = F;
            vec3 kD = vec3(1.0) - kS;
            kD *= 1.0 - metallic;
            
            vec3 numerator    = NDF * G * F;
            float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
            vec3 specular     = numerator / max(denominator, 0.001);
                
            // add to outgoing radiance Lo
            float NdotL = max(dot(N, L), 0.0);
            Lo += (kD * albedo / PI + specular) * radiance * NdotL; 
        }
    }

    vec3 ambient = ambientSum * albedo * ao;// 環(huán)境光最終貢獻
    vec3 color = ambient + Lo; // 環(huán)境光與cook-torrance模型累加
	
    // HDR色調(diào)映射
    color = color / (color + vec3(1.0));
    // gamma 矯正
    color = pow(color, vec3(1.0/2.2));  
   
    FRAGMENT_COLOR = vec4(color, albedoRGBA.a); // alpha使用反照率貼圖
}

Fragment Shader大體分為三部分:

  1. 從貼圖中獲取反照率、金屬度、粗糙度、法線數(shù)據(jù)
  2. 計算燈光光照,環(huán)境光燈光只影響環(huán)境光;方向光、聚光燈、點光源會影響光強lightCoeff,最終的光照使用cook-torrance模型進行計算,公式可以參考LearnOpenGL
  3. 最后進行環(huán)境光與PBR模型結(jié)果進行疊加,并進行色調(diào)映射與gamma矯正,這里使用的公式在LearnOpenGL中都有的

總結(jié):
這個PBR Shader整體上與LearnOpenGL中的理論一致,看完LearnOpenGL之后再看這個Shader就比較簡單了。

完結(jié)總結(jié):

寫的這里,這個專欄暫時告一段落了,主要分析了Overload的Render模塊,其他的包括UI、物理引擎、音頻等模塊沒有涉及。Overload是一個Demo性質(zhì)的游戲引擎,其渲染涉只涉及最基礎(chǔ)的渲染方式,是對OpenGL簡單封裝,遠遠滿足不了實際游戲開發(fā)需求,只能作為渲染引擎入門。
另外,這個專欄的文章只聚焦一些細節(jié),對應(yīng)架構(gòu)涉及很少,因為本人發(fā)現(xiàn)架構(gòu)方面的文章參考性不大,一旦一個軟件定型架構(gòu)方面的改動很困難,讀了軟件架構(gòu)的文章也很難在工作中用上。故單純只介紹一個技術(shù)點反而可能拿來直接使用。最后希望能對大家有所幫助!文章來源地址http://www.zghlxwxcb.cn/news/detail-716063.html

到了這里,關(guān)于【Overload游戲引擎細節(jié)分析】PBR材質(zhì)Shader---完結(jié)篇的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【Overload游戲引擎細節(jié)分析】UBO與SSBO的封裝

    一、OpenGL的UBO ? 在OpenGL Shader中,如果邏輯比較復(fù)雜,使用的uniform變量較多。通常多個著色器使用同一個uniform變量。由于uniform變量的位置是著色器鏈接時候產(chǎn)生的,因此它在應(yīng)用程序中獲得的索引會有變化。Uniform Buffer Object(UBO)是一種優(yōu)化uniform變量訪問,不同著色器直接

    2024年02月07日
    瀏覽(25)
  • 【Overload游戲引擎細節(jié)分析】鼠標(biāo)鍵盤控制攝像機原理

    在上文中分析了攝像機類的實現(xiàn),在計算投影視圖矩陣時需要給攝像機輸入其位置及轉(zhuǎn)動四元數(shù)。這兩個量一般通過鼠標(biāo)鍵盤來控制,從而達到控制攝像機的目的。本文分析一下其控制原理。 Overload的攝像機控制實現(xiàn)在類CameraController中,其有三個個方法HandleCameraPanning、Hand

    2024年02月08日
    瀏覽(25)
  • 【Overload游戲引擎細節(jié)分析】視圖投影矩陣計算與攝像機

    【Overload游戲引擎細節(jié)分析】視圖投影矩陣計算與攝像機

    本文只羅列公式,不做具體的推導(dǎo)。 OpenGL本身沒有攝像機(Camera)的概念,但我們?yōu)榱水a(chǎn)品上的需求與編程上的方便,一般會抽象一個攝像機組件。攝像機類似于人眼,可以建立一個本地坐標(biāo)系。相機的位置是坐標(biāo)原點,攝像機的朝向Forward是攝像機看的方向,再給定向上的Up軸

    2024年02月07日
    瀏覽(36)
  • 【GAMES-104現(xiàn)代游戲引擎】4、引擎渲染基礎(chǔ)(渲染基礎(chǔ)數(shù)據(jù)、全局光照、PBR、陰影)

    【GAMES-104現(xiàn)代游戲引擎】4、引擎渲染基礎(chǔ)(渲染基礎(chǔ)數(shù)據(jù)、全局光照、PBR、陰影)

    游戲渲染的挑戰(zhàn) 一個場景包含成千上萬的GO需要的材質(zhì)、shader、效果都不盡相同,因此 復(fù)雜度極高 當(dāng)代各種硬件的適配難度高,硬件架構(gòu)一直在變化 高幀率、高分辨率的要求下,使得繪制算法繪制一幀的時間越來越短, 算法效率要求高 繪制系統(tǒng)可以100%的使用顯卡,但CPU只

    2023年04月09日
    瀏覽(53)
  • 自制游戲引擎之shader預(yù)編譯

    自制游戲引擎之shader預(yù)編譯

    shader預(yù)編譯為二進制,在程序運行時候加載,可以提升性能,節(jié)省啟動時間. third_party文件里需要放依賴的第三方 因為電腦訪問google的問題,無法通過 shaderc-2023.4utilsgit-sync-deps 腳本自動下載第三方,手動下載 https://codeload.github.com/KhronosGroup/SPIRV-Tools/zip/refs/tags/v2023.3.rc1 https://codeloa

    2024年02月13日
    瀏覽(19)
  • PBR材質(zhì)理解整理

    PBR材質(zhì)理解整理

    草履蟲都能看懂的PBR講解(迫真) 先前看了很多遍類似的了,結(jié)合《Unity Shader 入門精要》中的內(nèi)容整理了下便于以后理解,以后有補充再添加。 光與材質(zhì)相交會發(fā)生 散射和吸收 ,散射改變光的方向,吸收改變光的能量。 在均勻介質(zhì)中,光沿直線傳播。傳播過程中材質(zhì)的折

    2024年02月13日
    瀏覽(25)
  • PBR材質(zhì)紋理下載

    PBR材質(zhì)紋理下載

    03:10 按照視頻里的順序 我們從第6個網(wǎng)站開始倒數(shù) 點擊本行文字或下方鏈接 進入查看 6大網(wǎng)站地址 網(wǎng)址查看鏈接 : http://www.uzing.net/community_show-1962-48-48-35.html 簡介 :最大的紋理網(wǎng)站之一,質(zhì)量非常高,最多可添加500多種材料;分辨率1K為免費素材。此外,每天登陸網(wǎng)站能獲得

    2024年01月20日
    瀏覽(9)
  • 7.PBR材質(zhì)與紋理貼圖

    7.PBR材質(zhì)與紋理貼圖

    友情鏈接:threejs 中文文檔 目錄 1. PBR材質(zhì)簡介 光照模型 網(wǎng)格模型材質(zhì)整體回顧 2. PBR材質(zhì)金屬度和粗糙度 金屬度metalness 粗糙度roughness? 3. 環(huán)境貼圖.enMap 環(huán)境貼圖反射率.envMapIntensity 場景環(huán)境屬性.environment 4. MeshPhysicalMaterial清漆層 清漆層屬性.clearcoat 清漆層粗糙度.clearcoatRo

    2024年02月12日
    瀏覽(23)
  • PBR材質(zhì)背光面太暗優(yōu)化

    PBR材質(zhì)背光面太暗優(yōu)化

    圖形學(xué)中漫反射光照遵循 蘭伯特光照模型 ,它的公式如下 其中: ?????????:漫反射光顏色 ?????????:入射光顏色 ?????????:材質(zhì)的漫反射系數(shù) ?????????:法線方向 ?????????:光源方向 由于背光面的法線方向和光源方向的點積為負數(shù),因此光線無法

    2024年01月18日
    瀏覽(23)
  • SuperMap Hi-Fi 3D SDK for Unity制作游戲引擎材質(zhì)

    SuperMap Hi-Fi 3D SDK for Unity制作游戲引擎材質(zhì)

    kele ????在交通,電力,規(guī)劃等行業(yè)中,有的對象常常具有很強的質(zhì)感,比如金屬質(zhì)感的 鋼軌,電力塔;陶瓷材質(zhì)的絕緣子;玻璃材質(zhì)的建筑幕墻等,但常規(guī)方式的表現(xiàn)效果 往往差強人意。 ????游戲引擎(Unity3D)中已有豐富的材質(zhì)資源庫,比如玻璃,金屬等材質(zhì),這

    2024年02月09日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包