欢迎来到飞鸟慕鱼博客,开始您的技术之旅!
当前位置: 首页知识笔记正文

overload operator,overloaded operator

墨初 知识笔记 1481阅读

PBR基于物理的渲染可以实现更加真实的效果其Shader值得分析一下。但PBR需要较多的基础知识不适合不会OpenGL的朋友。

一、PBR理论
PBR指基于物理的渲染其理论较多需要的基础知识也较多我在这就不再写一遍了具体可以参看
LearnOpenGL PBR理论-英文 或者 LearnOpenGL PBR理论-中文

Overload也提供了这种材料借助贴图可以实现非常真实的材质效果。下面这个例子的贴图来自LearnOpenGL大家可以自己去下载。

二、PBR Shader分析
顶点着色器

#shader vertex#version 430 corelayout (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材质一致这里就不再分析了具体可看standard材质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;/* 光源数据用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; // 环境光遮蔽贴图uniform sampler2D   u_NormalMap; // 法线贴图uniform vec4        u_Albedo                 vec4(1.0); // 反照率系数控制反照率贴图的权重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;// 计算法向分布函数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 methodfloat 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位数字变成RGBA颜色 */vec3 UnPack(float p_Target){    return vec3    (        // CPU传入的数据是0-255转换成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    );}/*光照衰减系数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;}/* 盒状环境光 */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);}/* 球状环境光 */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反照率贴图数据    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; // 环境光遮蔽AO    vec3 normal;    if (u_EnableNormalMapping) // 是否使用法线贴图    {        normal  texture(u_NormalMap, texCoords).rgb; // 法线贴图的原始值        normal  normalize(normal * 2.0 - 1.0);   // 法线贴图矢量坐标范围变成-1到1        normal  normalize(fs_in.TBN * normal);   // 变换到全局坐标系下    }    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); // 插值方式得到平面的基础反射率F0               // reflectance equation    vec3 Lo  vec3(0.0);    vec3 ambientSum  vec3(0.0); // 环境光结果    for (int i  0; i < ssbo_Lights.length(); i)     {        // 两种环境光灯光        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; // 最终到片元处的光强系数             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); // 法线分布函数            float G    GeometrySmith(N, V, L, roughness); // 几何函数            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;// 环境光最终贡献    vec3 color  ambient  Lo; // 环境光与cook-torrance模型累加    // HDR色调映射    color  color / (color  vec3(1.0));    // gamma 矫正    color  pow(color, vec3(1.0/2.2));         FRAGMENT_COLOR  vec4(color, albedoRGBA.a); // alpha使用反照率贴图}

Fragment Shader大体分为三部分

从贴图中获取反照率、金属度、粗糙度、法线数据计算灯光光照环境光灯光只影响环境光方向光、聚光灯、点光源会影响光强lightCoeff最终的光照使用cook-torrance模型进行计算公式可以参考LearnOpenGL最后进行环境光与PBR模型结果进行叠加并进行色调映射与gamma矫正这里使用的公式在LearnOpenGL中都有的

总结
这个PBR Shader整体上与LearnOpenGL中的理论一致看完LearnOpenGL之后再看这个Shader就比较简单了。

标签:
声明:无特别说明,转载请标明本文来源!