• 十九,镜面IBL--BRDF积分贴图


    再回顾下镜面部分的分割求和近似法
    在这里插入图片描述
    现在关注第二部分
    在这里插入图片描述
    最后可化为
    在这里插入图片描述
    也就是说,这两部分积分可以获得F0的系数和F0的偏差。

    这两个值可以存储到BRDF积分贴图的RG部分。
    
    • 1

    void main()
    {
    vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y);
    FragColor = integratedBRDF;
    }
    再看函数vec2 IntegrateBRDF(float NdotV, float roughness) ,可知积分贴图的横坐标是NotV,纵坐标是粗糙度。
    查看这个RG是如何计算的。

    		循环采样后
    	A /= float(SAMPLE_COUNT);	
    	B /= float(SAMPLE_COUNT);	
    	return vec2(A, B);			
    	即A,B分别是F0和系数和F0的偏差,也就是积分贴图的RG部分。
    	结合公式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    在对每个采样向量中,
    float Fc = pow(1.0 - VdotH, 5.0);
    A += (1.0 - Fc) * G_Vis;
    B += Fc * G_Vis;

    	继续向下
    	float G = GeometrySmith(N, V, L, roughness);	
    	float G_Vis = (G * VdotH) / (NdotH * NdotV);	
    	可知,使用BRDF的几何函数处理了采样向量。
    	继续向下
    	vec2 Xi = Hammersley(i, SAMPLE_COUNT);					
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    vec3 H = ImportanceSampleGGX(Xi, N, roughness);
    vec3 L = normalize(2.0 * dot(V, H) * H - V);
    类似于预过滤环境贴图,也是通过低差异序列进行重要性采样获取采样向量。

    在c++部分。
    设置brdf积分贴图为512x512,纹理设置为GL_RG
    texture->setSourceFormat(GL_RG);
    运行结果如下:
    在这里插入图片描述
    代码如下:
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    static const char * vertexShader =
    {
    “in vec3 aPos;\n”
    “in vec2 texcoord;”
    “varying vec2 TexCoords;\n”
    “void main(void)\n”
    “{\n”
    “TexCoords = texcoord;\n”
    “gl_Position = ftransform();\n”
    //“gl_Position = view * view * vec4(aPos,1.0);”
    “}\n”
    };

    static const char psShader =
    {
    “#version 330 core \n”
    “out vec2 FragColor; \n”
    “in vec2 TexCoords; \n”
    " \n"
    “const float PI = 3.14159265359; \n”
    “// ---------------------------------------------------------------------------- \n”
    “// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html \n”
    “// efficient VanDerCorpus calculation. \n”
    “float RadicalInverse_VdC(uint bits) \n”
    “{ \n”
    " bits = (bits << 16u) | (bits >> 16u); \n"
    " bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); \n"
    " bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); \n"
    " bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); \n"
    " bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); \n"
    " return float(bits) * 2.3283064365386963e-10; // / 0x100000000 \n"
    “} \n”
    “// ---------------------------------------------------------------------------- \n”
    “vec2 Hammersley(uint i, uint N) \n”
    “{ \n”
    " return vec2(float(i) / float(N), RadicalInverse_VdC(i)); \n"
    “} \n”
    “// ---------------------------------------------------------------------------- \n”
    “vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) \n”
    “{ \n”
    " float a = roughness
    roughness; \n"
    " \n"
    " float phi = 2.0 * PI * Xi.x; \n"
    " float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (aa - 1.0) * Xi.y)); \n"
    " float sinTheta = sqrt(1.0 - cosTheta
    cosTheta); \n"
    " \n"
    " // from spherical coordinates to cartesian coordinates - halfway vector \n"
    " vec3 H; \n"
    " H.x = cos(phi) * sinTheta; \n"
    " H.y = sin(phi) * sinTheta; \n"
    " H.z = cosTheta; \n"
    " \n"
    " // from tangent-space H vector to world-space sample vector \n"
    " vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); \n"
    " vec3 tangent = normalize(cross(up, N)); \n"
    " vec3 bitangent = cross(N, tangent); \n"
    " \n"
    " vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z; \n"
    " return normalize(sampleVec); \n"
    “} \n”
    “// ---------------------------------------------------------------------------- \n”
    “float GeometrySchlickGGX(float NdotV, float roughness) \n”
    “{ \n”
    " // note that we use a different k for IBL \n"
    " float a = roughness; \n"
    " float k = (a * a) / 2.0; \n"
    " \n"
    " float nom = NdotV; \n"
    " float denom = NdotV * (1.0 - k) + k; \n"
    " \n"
    " return nom / denom; \n"
    “} \n”
    “// ---------------------------------------------------------------------------- \n”
    “float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) \n”
    “{ \n”
    " float NdotV = max(dot(N, V), 0.0); \n"
    " float NdotL = max(dot(N, L), 0.0); \n"
    " float ggx2 = GeometrySchlickGGX(NdotV, roughness); \n"
    " float ggx1 = GeometrySchlickGGX(NdotL, roughness); \n"
    " \n"
    " return ggx1 * ggx2; \n"
    “} \n”
    “// ---------------------------------------------------------------------------- \n”
    “vec2 IntegrateBRDF(float NdotV, float roughness) \n”
    “{ \n”
    " vec3 V; \n"
    " V.x = sqrt(1.0 - NdotV*NdotV); \n"
    " V.y = 0.0; \n"
    " V.z = NdotV; \n"
    " \n"
    " float A = 0.0; \n"
    " float B = 0.0; \n"
    " \n"
    " vec3 N = vec3(0.0, 0.0, 1.0); \n"
    " \n"
    " const uint SAMPLE_COUNT = 1024u; \n"
    " for (uint i = 0u; i < SAMPLE_COUNT; ++i) \n"
    " { \n"
    " // generates a sample vector that’s biased towards the \n"
    " // preferred alignment direction (importance sampling). \n"
    " vec2 Xi = Hammersley(i, SAMPLE_COUNT); \n"
    " vec3 H = ImportanceSampleGGX(Xi, N, roughness); \n"
    " vec3 L = normalize(2.0 * dot(V, H) * H - V); \n"
    " \n"
    " float NdotL = max(L.z, 0.0); \n"
    " float NdotH = max(H.z, 0.0); \n"
    " float VdotH = max(dot(V, H), 0.0); \n"
    " \n"
    " if (NdotL > 0.0) \n"
    " { \n"
    " float G = GeometrySmith(N, V, L, roughness); \n"
    " float G_Vis = (G * VdotH) / (NdotH * NdotV); \n"
    " float Fc = pow(1.0 - VdotH, 5.0); \n"
    " \n"
    " A += (1.0 - Fc) * G_Vis; \n"
    " B += Fc * G_Vis; \n"
    " } \n"
    " } \n"
    " A /= float(SAMPLE_COUNT); \n"
    " B /= float(SAMPLE_COUNT); \n"
    " return vec2(A, B); \n"
    “} \n”
    “// ---------------------------------------------------------------------------- \n”
    “void main() \n”
    “{ \n”
    " vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y); \n"
    " FragColor = integratedBRDF; \n"
    “} \n”
    };

    int main()
    {
    int imageWidth = 512;
    int imageHeight = 512;
    osg::ref_ptrosg::Vec3Array vertices = new osg::Vec3Array;

    vertices->push_back(osg::Vec3(-imageWidth, 0.0f, -imageHeight));
    vertices->push_back(osg::Vec3(imageWidth, 0.0f, -imageHeight));
    vertices->push_back(osg::Vec3(imageWidth, 0.0f, imageHeight));
    vertices->push_back(osg::Vec3(-imageWidth, 0.0f, imageHeight));
    osg::ref_ptr normals = new osg::Vec3Array;
    normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));
    osg::ref_ptr texcoords = new osg::Vec2Array;
    texcoords->push_back(osg::Vec2(0.0f, 0.0f));
    texcoords->push_back(osg::Vec2(1.0f, 0.0f));
    texcoords->push_back(osg::Vec2(1.0f, 1.0f));
    texcoords->push_back(osg::Vec2(0.0f, 1.0f));
    osg::ref_ptr quad = new osg::Geometry;
    quad->setVertexArray(vertices.get());
    
    quad->setNormalArray(normals.get());
    quad->setNormalBinding(osg::Geometry::BIND_OVERALL);
    quad->setTexCoordArray(0, texcoords.get());
    quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
    
    quad->setVertexAttribArray(1, vertices, osg::Array::BIND_PER_VERTEX);
    quad->setVertexAttribArray(2, texcoords, osg::Array::BIND_PER_VERTEX);
    osg::ref_ptr texture = new osg::Texture2D;
    texture->setSourceFormat(GL_RG);
    texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
    texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
    texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
    texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
    osg::ref_ptr geode = new osg::Geode;
    geode->addDrawable(quad.get());
    osg::ref_ptr stateset = geode->getOrCreateStateSet();
    stateset->setTextureAttributeAndModes(0, texture.get());
    
    //shader
    
    osg::ref_ptr vs1 = new osg::Shader(osg::Shader::VERTEX, vertexShader);
    osg::ref_ptr ps1 = new osg::Shader(osg::Shader::FRAGMENT, psShader);
    osg::ref_ptr program1 = new osg::Program;
    program1->addShader(vs1);
    program1->addShader(ps1);
    program1->addBindAttribLocation("aPos", 1);
    program1->addBindAttribLocation("texcoord", 2);
    
    osg::ref_ptr tex0Uniform = new osg::Uniform("tex0", 0);
    stateset->addUniform(tex0Uniform);
    stateset->setAttribute(program1, osg::StateAttribute::ON);
    
    //osgDB::writeImageFile(*image, strBRDFLUTImageName);
    osgViewer::Viewer viewer;
    viewer.setSceneData(geode.get());
    
    bool bPrinted = false;
    return viewer.run();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    }

  • 相关阅读:
    002讲:CAD2024下方任务栏不显示坐标解决方案——CAD知识讲堂
    【深入浅出Spring6】第八期——面向切面编程 AOP
    如何使用Jest生成中文测试报告
    Mysql之用户管理
    基于C语言 --- 自己写一个通讯录
    20年将投资美国约2000亿美元,三星电子财大气粗的样子真好看
    idea构建grpc项目
    太极限了,JDK的这个BUG都能被我踩到
    linux - 文件利用率快满了 - mongo日志
    idea pom导入net.sf.json的jar包失败
  • 原文地址:https://blog.csdn.net/directx3d_beginner/article/details/133384026