十六,镜面IBL--预滤波环境贴图

又到了开心的公式时刻了。
先看看渲染方程
在这里插入图片描述
现在关注第二部分,镜面反射。
在这里插入图片描述
其中在这里插入图片描述
这里很棘手,与输入wi和输出w0都有关系,所以,再近似
在这里插入图片描述
其中第一部分,就是预滤波环境贴图,形式上与前面的辐照度图很相似,那么能不能用同样的方法呢?
先看看镜面反射和漫反射的图
在这里插入图片描述
可以看到,镜面反射是绕着出射向量的一个范围(成为波瓣),而漫反射是绕着法线方向均匀分布的。
再想想积分辐照度图时,是以法线向量为中心,进行积分的。在这里插入图片描述
那很自然的想到,积分镜面反射的预滤波环境贴图可以以出射向量为中心,在波瓣范围内积分。

然而, 波瓣有大有小,是因为粗糙度不同,
在这里插入图片描述
所以,不能只积分一次,而是多次,按照不同粗糙度积分后写到mipmap,或者单独的纹理中。这里为了方便,分别写到不同的纹理中。

那么该如何积分呢?辐照度图是在经度0到360,纬度0到90内均匀积分。
在这里插入图片描述

而镜面反射中,给定入射方向,波瓣指向方向就是微平面半向量的反射方向。所以,只在波瓣内积分就可以了,即重要性采样。
这时就可以使用蒙特卡洛积分,即在大数定律基础上,采取N样本即可。N越大越准。pdf为概率密度函数。
在这里插入图片描述
比如
在这里插入图片描述
采样样本越多,越靠近中间范围。因为中间范围概率大。

以上为均匀采样,

如果采样样本有偏,则会更快收敛。比如通过低差异序列获取样本。
float RadicalInverse_VdC(uint bits)
{
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}

vec2 Hammersley(uint i, uint N)
{
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
}
或者无位运算的
"float VanDerCorpus(uint n, uint base) "
"{ "
" float invBase = 1.0 / float(base); "
" float denom = 1.0; "
" float result = 0.0; "
" for (uint i = 0u; i < 32u; ++i) "
" { "
" if (n > 0u) "
" { "
" denom = mod(float(n), 2.0); "
" result += denom * invBase; "
" invBase = invBase / 2.0; "
" n = uint(float(n) / 2.0); "
" } "
" } "
"return result; "
"} "
" "
"vec2 HammersleyNoBitOps(uint i, uint N) "
"{ "
" return vec2(float(i) / float(N), VanDerCorpus(i, 2u)); "
"} "

然后根据法线方向,粗糙度和低差异序列生成采样向量,该向量大体围绕着预估的波瓣方向。
“vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)”
“{”
“float a = roughness * roughness;”
“float phi = 2.0 * PI * Xi.x;”
“float cosTheta = sqrt((1.0 - Xi.y)/(1.0+(a*a-1.0) * Xi.y));”
“float sinTheta = sqrt(1.0 - cosTheta * cosTheta);”
“vec3 H;”
“H.x = cos(phi) * sinTheta;”
“H.y = sin(phi) * sinTheta;”
“H.z = cosTheta;”
“vec3 up = abs(N.z) < 0.999 ? vec3(0.0,0.0,1.0) : vec3(1.0,0.0,0.0);”
“vec3 tangent = normalize(cross(up,N));”
“vec3 bitangent = cross(N,tangent);”
“vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;”
“return normalize(sampleVec);”
“}”
运行结果如下
在这里插入图片描述
代码如下
#include <osg/TextureCubeMap>
#include <osg/TexGen>
#include <osg/TexEnvCombine>
#include <osgUtil/ReflectionMapGenerator>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/NodeVisitor>
#include <osg/ShapeDrawable>

static const char * vertexShader =
{
//“#version 120 core\n”
“in vec3 aPos;\n”
“varying vec3 localPos;\n”
“void main(void)\n”
“{\n”
“localPos = aPos;\n”
" gl_Position = ftransform();\n"
//“gl_Position = view * view * vec4(aPos,1.0);”
“}\n”
};

static const char psShader =
{
“varying vec3 localPos;\n”
“uniform samplerCube environmentMap;”
“uniform float roughness;”
“const float PI = 3.1415926;”
“float VanDerCorpus(uint n, uint base) "
“{ "
" float invBase = 1.0 / float(base); "
" float denom = 1.0; "
" float result = 0.0; "
" for (uint i = 0u; i < 32u; ++i) "
" { "
" if (n > 0u) "
" { "
" denom = mod(float(n), 2.0); "
" result += denom * invBase; "
" invBase = invBase / 2.0; "
" n = uint(float(n) / 2.0); "
" } "
" } "
“return result; "
“} "
" "
“vec2 HammersleyNoBitOps(uint i, uint N) "
“{ "
" return vec2(float(i) / float(N), VanDerCorpus(i, 2u)); "
“} "
//“float RadicalInverse_Vdc(uint bits)\n”
//”{”
//“bits = (bits << 16u) | (bits >> 16u);”
//“bits = ((bits & 0x55555555u) << 1u ) | (bits & 0xAAAAAAAAu) >> 1u);”
//“bits = ((bits & 0x33333333u) << 2u ) | (bits & 0xCCCCCCCCu) >> 2u);”
//“bits = ((bits & 0x0F0F0F0Fu) << 4u ) | (bits & 0xF0F0F0F0u) >> 4u);”
//“bits = ((bits & 0x00FF00FFu) << 8u ) | (bits & 0xFF00FF00u) >> 8u);”
//“return float(bits) * 2.3283064365386963e-10;”
//”}”
//“vec2 Hammersley(uint i, uint N)”
//”{”
//“return vec2(float(i) / float(N), RadicalInverse_Vdc(i));”
//”}"
“vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)”
“{”
“float a = roughness * roughness;”
“float phi = 2.0 * PI * Xi.x;”
"float cosTheta = sqrt((1.0 - Xi.y)/(1.0+(a
a-1.0) * Xi.y));"
“float sinTheta = sqrt(1.0 - cosTheta * cosTheta);”
“vec3 H;”
“H.x = cos(phi) * sinTheta;”
“H.y = sin(phi) * sinTheta;”
“H.z = cosTheta;”
“vec3 up = abs(N.z) < 0.999 ? vec3(0.0,0.0,1.0) : vec3(1.0,0.0,0.0);”
“vec3 tangent = normalize(cross(up,N));”
“vec3 bitangent = cross(N,tangent);”
“vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;”
“return normalize(sampleVec);”
“}”
"void main() "
"{ "
" vec3 N = normalize(localPos); "
" vec3 R = N; "
" vec3 V = R; "
" "
" const uint SAMPLE_COUNT = 1024u; "
" float totalWeight = 0.0; "
" vec3 prefilteredColor = vec3(0.0); "
" for (uint i = 0u; i < SAMPLE_COUNT; ++i) "
" { "
" vec2 Xi = HammersleyNoBitOps(i, SAMPLE_COUNT); "
" vec3 H = ImportanceSampleGGX(Xi, N, roughness); "
" vec3 L = normalize(2.0 * dot(V, H) * H - V); "
" "
" float NdotL = max(dot(N, L), 0.0); "
" if (NdotL > 0.0) "
" { "
" prefilteredColor += texture(environmentMap, L).rgb * NdotL; "
" totalWeight += NdotL; "
" } "
" } "
" prefilteredColor = prefilteredColor / totalWeight; "
" "
" gl_FragColor = vec4(prefilteredColor, 1.0); "
"} "
};
class MyNodeVisitor : public osg::NodeVisitor
{
public:
MyNodeVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{

}
void apply(osg::Geode& geode)
{int count = geode.getNumDrawables();for (int i = 0; i < count; i++){osg::ref_ptr<osg::Geometry> geometry = geode.getDrawable(i)->asGeometry();if (!geometry.valid()){continue;}osg::Array* vertexArray = geometry->getVertexArray();geometry->setVertexAttribArray(1, vertexArray);}traverse(geode);
}

};

int main()
{

osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;osg::ref_ptr<osg::TextureCubeMap> tcm = new osg::TextureCubeMap;
tcm->setTextureSize(128, 128);
tcm->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
tcm->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
tcm->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
tcm->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
tcm->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);std::string strImagePosX = "D:/hdr/Right face camera.bmp";
osg::ref_ptr<osg::Image> imagePosX = osgDB::readImageFile(strImagePosX);
tcm->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX);
std::string strImageNegX = "D:/hdr/Left face camera.bmp";
osg::ref_ptr<osg::Image> imageNegX = osgDB::readImageFile(strImageNegX);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX);std::string strImagePosY = "D:/hdr/Front face camera.bmp";;
osg::ref_ptr<osg::Image> imagePosY = osgDB::readImageFile(strImagePosY);
tcm->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY);
std::string strImageNegY = "D:/hdr/Back face camera.bmp";;
osg::ref_ptr<osg::Image> imageNegY = osgDB::readImageFile(strImageNegY);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY);std::string strImagePosZ = "D:/hdr/Top face camera.bmp";
osg::ref_ptr<osg::Image> imagePosZ = osgDB::readImageFile(strImagePosZ);
tcm->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ);std::string strImageNegZ = "D:/hdr/Bottom face camera.bmp";
osg::ref_ptr<osg::Image> imageNegZ = osgDB::readImageFile(strImageNegZ);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ);
tcm->setUseHardwareMipMapGeneration(true);
float minMipMapLevel = 0.0;
float maxMipMapLevel = 4.0;
tcm->setMinLOD(minMipMapLevel);
tcm->setMaxLOD(maxMipMapLevel);osg::ref_ptr<osg::Box> box = new osg::Box(osg::Vec3(0, 0, 0), 10);
osg::ref_ptr<osg::ShapeDrawable> drawable = new osg::ShapeDrawable(box);
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(drawable);
MyNodeVisitor nv;
geode->accept(nv);
osg::ref_ptr<osg::StateSet> stateset = geode->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(0, tcm, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);//shaderosg::ref_ptr<osg::Shader> vs1 = new osg::Shader(osg::Shader::VERTEX, vertexShader);
osg::ref_ptr<osg::Shader> ps1 = new osg::Shader(osg::Shader::FRAGMENT, psShader);
osg::ref_ptr<osg::Program> program1 = new osg::Program;
program1->addShader(vs1);
program1->addShader(ps1);
program1->addBindAttribLocation("aPos", 1);osg::ref_ptr<osg::Uniform> environmentMapUniform = new osg::Uniform("environmentMap", 0);
stateset->addUniform(environmentMapUniform);
float theMip = 3.0;
float roughness = theMip / maxMipMapLevel;
osg::ref_ptr<osg::Uniform> roughnessUniform = new osg::Uniform("roughness", roughness);
stateset->addUniform(roughnessUniform);stateset->setAttribute(program1, osg::StateAttribute::ON);viewer->setSceneData(geode);
viewer->realize();
return viewer->run();

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/143288.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

uni-app:实现页面效果2(canvas绘制,根据页面宽度调整元素位置)

效果 代码 <template><view><!-- 车搭配指示器-双显 --><view class"content_position"><view class"content"><view class"SN"><view class"SN_title">设备1</view><view class…

【考研数学】概率论与数理统计 —— 第三章 | 二维随机变量及其分布(3,二维随机变量函数的分布)

文章目录 七、二维随机变量函数的分布7.1 二维随机变量函数分布的基本情形 ( X , Y ) (X,Y) (X,Y) 为二维离散型随机变量 ( X , Y ) (X,Y) (X,Y) 为二维连续型随机变量 X X X 为离散型变量&#xff0c; Y Y Y 为连续型变量 7.2 常见二维随机变量的函数及其分布 Z min ⁡ { X ,…

【IDEA】idea恢复pom.xml文件显示灰色并带有删除线

通过idea打开spring boot项目后&#xff0c;发现每个服务中的pom.xml文件显示灰色并带有删除线&#xff0c;下面为解决方案 问题截图 解决方案 打开file——settings——build,execution,deployment——Ignored Files&#xff0c;把pom.xml前面的复选框去掉&#xff0c;去掉之…

虹科分享 | 网络保险:有效承保网络风险解决方案

文章来源&#xff1a;虹科网络安全 点击阅读原文&#xff1a;https://mp.weixin.qq.com/s/myCFPYtVVz5TPSFQaKqvLg 网络风险似乎往往很难量化&#xff0c;这使得保险公司很难适当地承保其网络风险政策。威胁载体的数量和不断发展的威胁&#xff0c;如新型恶意软件/勒索软件&…

PSINS工具箱学习(二)姿态的表示:姿态阵、四元数、欧拉角、等效旋转矢量的概念和转换

原始 Markdown文档、Visio流程图、XMind思维导图见&#xff1a;https://github.com/LiZhengXiao99/Navigation-Learning 文章目录 一、基础概念1、坐标系定义1. 惯性坐标系&#xff08; i 系 &#xff09;2. 地心地固坐标系&#xff08; e 系 )3. 导航坐标系&#xff08; n 系&…

Nginx WEB访问与Linux授权约束

看到所有文件的权限都是没有的&#xff0c;即便所有的权限都没有即使nginx做了配置&#xff0c;这些都是正确的。那么在浏览器真正去访问的时候是不能访问的。 [rootjenkins html]# ls -l total 4 drwxr-xr-x 2 root root 23 Sep 16 17:43 dist ---------- 1 root root 33 Sep …

【算法练习Day7】反转字符串替换空格反转字符串中的单词左旋转字符串

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 反转字符串反转字符串 I…

十三,打印辐照度图

上节HDR环境贴图进行卷积后&#xff0c;得到的就是辐照度图&#xff0c;表示的是周围环境间接漫反射光的积分。 现在也进行下打印&#xff0c;和前面打印HDR环境贴图一样&#xff0c;只是由于辐照度图做了平均&#xff0c;失去了大量高频部分&#xff0c;因此&#xff0c;可以…

游戏开发过程中需要注意哪些问题呢?

游戏开发是一个复杂的过程&#xff0c;需要注意多个方面的问题。以下是一些需要特别关注的关键问题&#xff1a; 游戏设计&#xff1a; 确定游戏的核心玩法和目标受众。 制定详细的游戏设计文档&#xff0c;包括角色、关卡设计、游戏机制和故事情节。 技术选择&#xff1a;…

react项目优化

随着项目体积增大&#xff0c;打包的文件体积会越来越大&#xff0c;需要优化&#xff0c;原因无非就是引入的第三方插件比较大导致&#xff0c;下面我们先介绍如何分析各个文件占用体积的大小。 1.webpack-bundle-analyzer插件 如果是webpack作为打包工具的项目可以使用&…

晨控CK-FR08系列读写器与LS可编程逻辑控制器MODBUSRTU连接手册

晨控CK-FR08系列读写器与LS可编程逻辑控制器MODBUSRTU连接手册 晨控CK-FR08是一款基于射频识别技术的高频RFID标签读卡器&#xff0c;读卡器工作频率为13.56MHZ&#xff0c;支持对I-CODE 2、I-CODE SLI等符合ISO15693国际标准协议格式标签的读取。读卡器内部集成了射频部分通信…

开源框架中的责任链模式实践

作者&#xff1a;vivo 互联网服务器团队-Wang Zhi 责任链模式作为常用的设计模式而被大家熟知和使用。本文介绍责任链的常见实现方式&#xff0c;并结合开源框架如Dubbo、Sentinel等进行延伸探讨。 一、责任链介绍 在GoF 的《设计模式》一书中对责任链模定义的&#xff1a;将…

一个关于IntroductionAdvisor的bug

一个关于IntroductionAdvisor的bug public class TestMain {public static void main(String[] args) {// 1. 准备被代理的目标对象People peo new People();// 2. 准备代理工厂ProxyFactory pf new ProxyFactory();// 3. 准备introduction advice,advice 持有需要额外添加的…

Go 围炉札记

文章目录 一、安装二、文档三、使用 一、安装 VSCode 和 CLion 为 Go 开发配置Visual Studio Code | Microsoft Learn VScode下配置Go语言开发环境【2023最新】 基础篇&#xff1a;新手使用vs code新建go项目 vscode里安装Go插件和配置Go环境 GO 笔记 Golang 配置代理 golang…

得物API元数据中心探索与思考

一、背景 目前市面上针对API的管理平台很多&#xff0c;但由于各种客观因素&#xff0c;这些平台的功能都更多聚焦在API文档的消费侧。而对于API文档的生成都非常依赖开发人员的手动创建&#xff0c;很难保障文档的实时性和有效性。市面上常见的API管理平台&#xff0c;由于缺…

【RabbitMQ实战】04 RabbitMQ的基本概念:Exchange,Queue,Channel等

一、简介 Message Queue的需求由来已久&#xff0c;80年代最早在金融交易中&#xff0c;高盛等公司采用Teknekron公司的产品&#xff0c;当时的Message queuing软件叫做&#xff1a;the information bus&#xff08;TIB&#xff09;。 TIB被电信和通讯公司采用&#xff0c;路透…

Java基础知识

目录 声明 JVM功能说明 功能1&#xff1a;实现Java程序的跨平台性 功能2&#xff1a;自动内存管理(内存分配、内存回收) 相关面试题 关键字和保留字 相关面试题 变量和数据类型 自动类型提升 强制类型转换 基本数据类型转换成字符串 使用String类的valueOf方法&…

怎么把一个音频平均拆分成多个?3个方法快速拆分

怎么把一个音频平均拆分成多个&#xff1f;近年来&#xff0c;随着音频文件在日常生活和工作中的广泛应用&#xff0c;人们对于对音频进行编辑、处理和转换的需求也越来越高。由此&#xff0c;音频编辑软件应运而生&#xff0c;可帮助我们轻松地剪辑、切分、编辑和转换音频文件…

用CRM系统协助销售跟踪客户

客户跟踪对销售来说非常重要&#xff0c;销售不及时跟进很容易导致潜在客户流失。那么对于销售来说&#xff0c;该如何做好客户跟踪呢&#xff1f;或许可以使用CRM客户管理系统。下面来说说&#xff0c;CRM系统如何协助销售跟踪客户&#xff1f; 智能联系客户提醒 销售人员通…

探索视听新纪元: ChatGPT的最新语音和图像功能全解析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f916; 人工智能 AI: &#x1f9e0; Machine …