osg使用整理(11):延迟渲染
osg使用整理(11):延迟渲染
一、基础概念
-
前向渲染流程:顶点着色器->图元装配成点线三角形->几何着色器->裁剪剔除->光栅化(片元着色器)->透明度测试、深度测试。
-
延迟渲染流程:顶点着色器->图元装配成点线三角形->几何着色器->裁剪剔除->光栅化输出G-Buffer,存储每个像素的属性信息(位置、法线、颜色)->深度测试->光照计算->片元着色器->透明度测试。
-
渲染管线的差异:
a. 延迟渲染需要两个pass,先生成G-Buffer后进行光照计算。
b. 延迟渲染不能使用MSAA算法抗锯齿。
-
优劣势:
a. 延迟渲染先进行深度测试,确定了可见像素后再进行光照计算,而不是对所有图元进行光栅化再光照计算,避免了大量无效计算。
b. 延迟渲染在一个Pass中处理多光源计算,提高了渲染效率。
c. 延迟渲染的G-Buffer占用带宽较大,需要合并一些纹理通道、减少buffer位数、将两个pass合并为OnePassDeferred。
d. 延迟渲染通常只能使用相同光照的效果,灵活性低。
e. 延迟渲染中透明物体需要单独的Pass来处理。
二、G-Buffer
如下图所示,延迟渲染首先生成称为G-Buffer的一系列纹理,常包含世界坐标系下的位置向量、颜色向量、顶点法线向量等等。
osg中要实现延迟渲染,首先准备离屏相机:
osg::ref_ptr<RttCamera> createRTTCamera(osg::Camera::BufferComponent buffer,osg::Texture* tex,int width,int height) { osg::ref_ptr<RttCamera> camera=new RttCamera(width,height); camera->setRenderTargetImplementation(osg::Camera::RenderTargetImplementation::FRAME_BUFFER_OBJECT); camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); camera->setPostDrawCallBack(new FBOPostDrawCallback); camera->setRenderOrder(osg::Camera::PRE_RENDER,20); camera->setViewPort(0,0,width,height); if(tex) { tex->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINER_MIPMAP_NEAREST); tex->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINER_MIPMAP_NEAREST); camera->setViewPort(0,0,tex->getTextureWidth(),tex->getTextureHeight()); camera->attach(buffer,tex); } return camera; }
注意到,离屏相机渲染目标设置为FBO,同时渲染次序设置为PRE_RENDER。然后准备附着在离屏相机上的颜色和深度纹理,简单认为有三维位置坐标纹理、法线方向纹理、基础颜色纹理三个。为了提高纹理精度,实现HDR渲染,我们可以使用浮点数缓冲,其内部格式通常设为GL_RGB16F, GL_RGBA16F, GL_RGB32F 或者GL_RGBA32F。浮点数缓冲可以存储超过0.0到1.0范围的浮点值。
//创建颜色附着纹理 osg::ref_ptr<osg::Texture2D> createColorTexture(int width,int height) { osg::ref_ptr<osg::Texture2D> texture=new osg::Texture2D; texture->setTextureSize(width,height); texture->setInternalFormat(GL_RGBA32F); texture->setSourceFormat(GL_RGBA); texture->setSourceType(GL_FLOAT);//浮点数精度更高 tex->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); tex->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); return texture; } //创建深度附着纹理 osg::ref_ptr<osg::Texture2D> createDepthTexture(int width,int height) { osg::ref_ptr<osg::Texture2D> texture=new osg::Texture2D; texture->setTextureSize(width,height); texture->setInternalFormat(GL_DEPTH_COMPONENT32F); texture->setSourceFormat(GL_DEPTH_COMPONENT32F); texture->setSourceType(GL_FLOAT); tex->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); tex->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); return texture; }
创建延迟渲染相机,首先渲染到G-buffer上,然后创建HUD相机渲染到和屏幕同样大小的矩形上。
/*延迟渲染相机*/ osg::ref_ptr<RttCamera> createDeferCamera(osg::Camera::BufferComponent buffer1,osg::Texture* tex1, osg::Camera::BufferComponent buffer2,osg::Texture* tex2, osg::Camera::BufferComponent buffer3,osg::Texture* tex3,int width,int height) { osg::ref_ptr<RttCamera> camera=new RttCamera(width,height); camera->setRenderTargetImplementation(osg::Camera::RenderTargetImplementation::FRAME_BUFFER_OBJECT); camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); camera->setPostDrawCallBack(new FBOPostDrawCallback); camera->setRenderOrder(osg::Camera::PRE_RENDER,20); camera->setViewPort(0,0,width,height); if(tex1) { tex1->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINER_MIPMAP_NEAREST); tex1->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINER_MIPMAP_NEAREST); camera->attach(buffer1,tex1); } if(tex2) { tex2->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINER_MIPMAP_NEAREST); tex2->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINER_MIPMAP_NEAREST); camera->attach(buffer2,tex2); } if(tex3) { tex3->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINER_MIPMAP_NEAREST); tex3->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINER_MIPMAP_NEAREST); camera->attach(buffer3,tex3); } ///顶点着色器 const char* vertCode=R"( #version 330 layout(location = 0) in vec3 Position; layout(location = 2) in vec3 normal; layout(location = 3) in vec3 TexCoord; uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewMatrix; uniform mat4 osg_NormalMatrix; out vec3 vNormal; out vec2 texCoord; out vec4 fragPos; void main() { texCoord=TexCoord; fragPos=osg_ModelViewMatrix*vec4(Position,1.0); vec4 viewNorm=transpose(inverse(osg_ModelViewMatrix))*vec4(-normal,1.0); vNormal=normalize(viewNorm.xyz); gl_Position=osg_ModelViewProjectionMatrix*vec4(Position,1.0); } )"; const char* fragCode=R"( #version 330 core uniform vec3 frontCol=vec3(1.0,0.0,0.2); layout (location = 0) out vec4 gColor; layout (location = 1) out vec4 gNormal; layout (location = 2) out vec4 gPosition; in vec2 texCoord; in vec4 fragPos; in vec3 vNormal; void main() { // Store the fragment position vector in the first gbuffer texture gPosition.xyz = fragPos.xyz; // Also store the per-fragment normals into the gbuffer gNormal = vec4(vNormal,1.0); gColor=vec4(frontCol,1.0); } )"; osg::ref_ptr<osg::Shader> vertShader=new osg::Shader(osg::Shader::VERTEX,vertCode); osg::ref_ptr<osg::Shader> fragShader=new osg::Shader(osg::Shader::FRAGMENT,fragCode); osg::ref_ptr<osg::Program> program=new osg::Program; program->addShader(vertShader); program->addShader(fragShader); camera->getOrCreateStateSet()->setAttributeAndModes(program,OVERRIDE_ON); return camera; }
HUD相机用于将纹理混合结果输出到屏幕上,需要注意绑定一个矩形几何为子节点,并正确设置渲染目标,设置RenderOrder为POST_RENDER。
/*延迟HUD相机*/ osg::ref_ptr<RttCamera> createHUDCamera(osg::Texture* tex1,osg::Texture* tex2,int width,int height) { osg::ref_ptr<RttCamera> camera=new RttCamera(width,height); camera->setClearMask(GL_DEPTH_BUFFER_BIT); camera->setPostDrawCallBack(new FBOPostDrawCallback); camera->setRenderOrder(osg::Camera::POST_RENDER,100); camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF) camera->setProjectMatrix(osg::Matrix::ortho2D(width,-width,-height,height)) camera->setViewPort(0,0,width,height); camera->addChild(createQuadGeode(tex1,tex2,width,height)); return camera; } /*平铺的四边形几何*/ osg::ref_ptr<osg::Geode> createQuadGeode(osg::Texture* baseTexture,osg::Texture* modelTexture,int width,int height) { ///创建四边形顶点 osg::ref_ptr<osg:Vec3Array> vertices= new osg::Vec3Array; vertices->push_back(osg::Vec3(-width,-height,0.f)); vertices->push_back(osg::Vec3(width,-height,0.f)); vertices->push_back(osg::Vec3(width,height,0.f)); vertices->push_back(osg::Vec3(width,-height,0.f)); ///创建四边形法线 osg::ref_ptr<osg:Vec3Array> normals= new osg::Vec3Array; normals->push_back(osg::Vec3(0.0,0.0,2.f)); ///创建四边形纹理坐标 osg::ref_ptr<osg:Vec2Array> texCoords= new osg::Vec2Array; texCoords->push_back(osg::Vec2(1.0,0.f)); texCoords->push_back(osg::Vec2(0.0,0.f)); texCoords->push_back(osg::Vec2(0.0,1.f)); texCoords->push_back(osg::Vec2(1.0,1.f)); ///创建四边形几何 osg::ref_ptr<osg:Geometry> quad= new osg::Geometry; quad->setVertexArray(vertices); quad->setNormalArray(normals); quad->setTexCoordArray(0,texCoords); quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,4)); ///创建四边形节点 osg::ref_ptr<osg::Geode> quadGeode=new osg::Geode; quadGeode->addDrawable(quad); quadGeode->getOrCreateStateSet()->addUniform(new osg::Uniform("baseTexture",0))); quadGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0,baseTexture); quadGeode->getOrCreateStateSet()->addUniform(new osg::Uniform("modelTexture",1))); quadGeode->getOrCreateStateSet()->setTextureAttributeAndModes(1,modelTexture); const char* vertCode=R"( #version 330 layout(location = 0) in vec3 Position; layout(location = 2) in vec3 normal; layout(location = 3) in vec3 TexCoord; uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewMatrix; uniform mat4 osg_NormalMatrix; out vec2 texCoord; void main() { texCoord=TexCoord; gl_Position=osg_ModelViewProjectionMatrix*vec4(Position,1.0); } )"; const char* fragCode=R"( uniform sampler2D baseTexture; uniform sampler2D modelTexture; in vec2 texCoord; out vec4 fragColor; void main() { vec4 modelCol=texture(modelTexture,texCoord); vec4 baseCol=texture(baseTexture,texCoord); fragColor=vec4(mix(modelCol.rgb,baseCol.rgb,baseCol.a),baseCol.a+modelCol.a); } )"; osg::ref_ptr<osg::Shader> vertShader=new osg::Shader(osg::Shader::VERTEX,vertCode); osg::ref_ptr<osg::Shader> fragShader=new osg::Shader(osg::Shader::FRAGMENT,fragCode); osg::ref_ptr<osg::Program> program=new osg::Program; program->addShader(vertShader); program->addShader(fragShader); quadGeode->getOrCreateStateSet()->setAttributeAndModes(program,OVERRIDE_ON); return quadGeode; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?