聊聊引擎底层如何实现SSAO渲染

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jxw167/article/details/85054688

网上关于SSAO渲染介绍的很多,本篇博客也是将现有算法应用到我们自己研发的3D引擎中,SSAO被称为屏幕空间环境光遮蔽,它的原理是:对于铺屏四边形(Screen-filled Quad)上的每一个片段,我们都会根据周边深度值计算一个遮蔽因子(Occlusion Factor)。这个遮蔽因子之后会被用来减少或者抵消片段的环境光照分量。遮蔽因子是通过采集片段周围球型核心(Kernel)的多个深度样本,并和当前片段深度值对比而得到的。高于片段深度值样本的个数就是我们想要的遮蔽因子。

SSAO的整体流程示意图:
1、渲染场景中的物体到G-Buffer;
2、利用G-Buffer中的数据,通过TBN矩阵,将采样点从切线空间,变换到视图空间,并在这个空间比较并计算SSAO的值,并写入AmbientOcculction;
3、对AmbielntOcculction Texture进行模糊处理,去掉噪声;
4、利用AmbielntOcculction Texture 获得正确的环境光照遮蔽效果。
根据以上原理我们实现出SSAO的Shader脚本,实现的代码如下所示:
在这里插入图片描述
在第2步中,我们需要采样点,在Shader代码中,使用了for循环64次采样,我们的采样是在切线空间进行的,这也是为了统一处理,最后,计算采样实际位置,再将它们变换到视空间中。这样才能和存储在G-Buffer里面的深度信息进行比较。用采样点的深度值,去和屏幕空间的深度值去比较作为是否被遮挡判断依据。我们在Shader代码中实现了计算采样点深度值和采样点深度值的平滑插值。下面我们再看看在引擎中的C++代码实现如下所示:
在这里插入图片描述
引擎中的代码跟上篇博客中的Deferred延迟渲染类似,我们在引擎中实现的测试效果图如下所示:
在这里插入图片描述
在引擎中最终渲染效果如下图所示:
在这里插入图片描述
总结:
SSAO算法在网上很多人为此写过,但是都没有介绍如何在引擎实现,我们要将单个的知识点整合应用到引擎中,这样就可以实现一个渲染系统,积少成多,逐步完善就形成了一个渲染引擎。

展开阅读全文

QT如何实现底层通信?

09-06

我用QT编写了一个用户界面,用来操作局域网中的设备(网络摄像头之类),rn我通过QUdpSocket组播的方式把我的Mac地址打包成Xml数据报,然后发送出去,rn设备通过嵌入式编程接收并解析我发的数据报,rn然后设备将自己的Mac打包成Xml回执报文,发送到解析得出的Mac地址上(也就是我的网卡上),rn然后我获取到数据解析得到他的Mac地址rn我为设备分配一个IP然后将设置结果以单播形式发送到他的网卡上rnrn目前的问题是,我的数据组播出去,且他已经成功解析并向我发送了回执rn但是我却接收不到他的报文,自然也就无法解析rn我的代码如下:rnsocketxml.h文件rn--------------------------------rn#ifndef SOCKETXML_Hrn#define SOCKETXML_Hrnrn#include rn#include rn#include rn#include rn#include rn#include "global.h"rnrnclass SocketXml : public QThreadrnrn Q_OBJECTrnpublic:rn SocketXml();rn ~SocketXml();rnpublic slots:rn void SendXmlBuf(QString str); //发送Xml数据rn void RecvXmlBuf(); //接收Xml数据rnprotected:rn void run(); //处理收发操作线程rnprivate:rn QUdpSocket *udpsocket;rn;rnrn#endif // SOCKETXML_Hrn************************************************************************************************************rnsocketxml.cpprn----------------------------------------rn#include "socketxml.h"rn#include rnrnSocketXml::SocketXml()rnrn udpsocket= new QUdpSocket(this);rn //udpsocket->bind(QHostAddress::AnyIPv4,Global::Instance().port,QUdpSocket::ReuseAddressHint);rn udpsocket->bind(Global::Instance().port,QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);rn udpsocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption,1);rn udpsocket->setSocketOption(QAbstractSocket::MulticastTtlOption,255);rn udpsocket->joinMulticastGroup(QHostAddress(Global::Instance().Mucst_ip));rnrnSocketXml::~SocketXml()rnrn quit();rn wait();rn delete udpsocket;rnrnrn/*!rn * \brief SocketXml::SendXmlBufrn * \param strrn * 发送数据rn */rnvoid SocketXml::SendXmlBuf(QString str)rnrn int len=udpsocket->writeDatagram( //调用QUdpSocket成员函数writeDatagram()发送数据rn str.toLatin1().data(), //将数据转换成字符串(char*)格式rn str.length(), //发送字符串长度rn //QHostAddress(Global::Instance().Mucst_ip), //发送数据到组播IPrn QHostAddress::Broadcast, //发送到组内所有主机rn Global::Instance().port); //发送端口rn if(len!=-1)rn rn qDebug()<<"writeDatagram已发送"<hasPendingDatagrams())rn rn qDebug()<<"hasPendingDatagrams检测到数据包";rn QByteArray byte;rn QHostAddress getaddr;rn quint16 getport;rn byte.resize(udpsocket->pendingDatagramSize());rn int strsize=udpsocket->readDatagram(rn byte.data(), //数据内容rn byte.size(), //数据大小rn &getaddr, //发送者地址rn &getport); //发送者端口rn qDebug()<<"readDatagram读入"< 论坛

数据控件的底层如何实现的?

01-27

操作Oracle的xmltypern因为可能插入超过4k的数据,所以需要用流rn然后ADOQuery和ADOdataset都用过,发现个问题rn[code=Delphi(Pascal)]rn//Queryrn with ADOQry_1 dorn beginrn Close;rn SQL.Clear;rn SQL.Add('insert into xmltest (id,xmldoc) values ( :id , xmlType(:clobs))');rn Parameters.ParamByName('id').Value := '0001';rn //全部测试不通过rn Parameters.ParamByName('clobs').LoadFromStream(strstream,ftBlob);rn Parameters.ParamByName('clobs').LoadFromStream(strstream,ftOraClob);rn TMemoField(Parameters.ParamByName('clobs')).LoadFromStream(strstream);rn rn Prepared;rn ExecSQL;rn end;rn[/code]rnrn而先查询,再在field里面导入流,然后保存进中间表,再调用存储过程xmltype(clob)强制转换导入却是可以的rn[code=Delphi(Pascal)]rnrn with ADOQry_1 dorn beginrn Close;rn Parameters.Clear;rn SQL.Clear;rn SQL.Add('select * from insertxml_tmp');rn Open;rn end;rnrn with ADOQry_1 dorn beginrn Edit;rn Append;rn FieldByName('id').value := '0001';rn TMemoField(FieldByName('xmlclob')).LoadFromStream(strstream);rn Post;rn ADOQry_1.UpdateStatus;rn end;rnrn with Adsp_1 dorn beginrn Close;rn ProcedureName := 'XmlInsertClob';rn ExecProc;rn end;rnrn[/code]rnrn当时就想能不能调用底层一点的API什么的,控件用着是真不放心啊rn然后又疑惑了,貌似查询操作记录也是调用的语句,流是怎么调用的呢rn[code=SQL]rnselect sql_text as "简略SQL语句",sql_fulltext as "SQL字串",parsing_schema_name as "执行者",module as "执行程序",last_active_time as "作用时间" rnfrom v$sqlarea rnwhere parsing_schema_name = '' and module = '' --执行者为parsing_schema_name ,执行程序为module rnorder by last_active_time descrn[/code] 论坛

没有更多推荐了,返回首页