ComopositorManager是ResourceManager的子类,负责管理Compositor,Compositor本身是Resource的子类,CompositorManager还持有两个重要的成员,分别是CompositorLogic和CompositorChain:
typedef map<string,CompositorLogic*> CompositorLogicMap; CompositorLogicMap m_mCompositorLogics; typedef map<Viewport*,CompositorChain*> CompositorChainMap; CompositorChainMap m_mChains;展开讲解之前,先看看图,
原始图:
只做横向模糊:
只做纵向模糊,
横纵模糊的效果图:
可以看到每张图的特征还是比较明显的。
CompositorChain是最核心的一个类,它负责管理一条CompositorInstance的链表,渲染一帧的时候依次执行每一个CompositorInstance各自的CompositorInstance::RenderSystemOperation。
程序渲染时,每一帧的渲染顺序是
RenderTarget::UpdateImpl -> FirePreUpdate ->
CompositorChain::PreRenderTargetUpdate ->
CompositorChain::Compile->
CompositorInstance::TargetOperation::RenderSystemOperation::Execute
在CompositorChain::Compile产生全部需要render的TargetOperation,但是不包括最后渲染到默认FBO的那一步,最后的target_output那一步在RenderTarget::UpdateImpl函数里面FirePreUpdate后面的部分,
在Execute里面执行绘制一个Rentangle2D(继承自SimpleRenderable),绘制这个Rect的时候根据指定的材质Ogre/Compositor/HDR/GaussianBloom根据Pass里面的shader进行模糊处理。
GaussianBlur对应的合成器配置文件Example.compositor:
// Gaussian blur effect
compositor "Gaussian Blur"
{
technique
{
compositor_logic GaussianBlur
// Temporary textures
texture rt0 target_width target_height PF_A8R8G8B8
texture rt1 target_width target_height PF_A8R8G8B8
target rt0
{
// Render output from previous compositor (or original scene)
input previous
}
target rt1
{
// Blur horizontally
input none
pass render_quad
{
material Ogre/Compositor/HDR/GaussianBloom
input 0 rt0
identifier 700
}
}
target_output
{
// Start with clear output
input none
// Blur vertically
pass render_quad
{
// Renders a fullscreen quad with a material
material Ogre/Compositor/HDR/GaussianBloom
input 0 rt1
identifier 701
}
}
}
}
里面所用到的material是Ogre/Compositor/HDR/GaussianBloom,对应配置文件如下:
material Ogre/Compositor/HDR/GaussianBloom
{
technique
{
pass
{
vertex_program_ref Ogre/Compositor/StdQuad_vs
{
}
fragment_program_ref Ogre/Compositor/HDR/bloom_fs
{
}
// Input
texture_unit
{
}
}
}
}
下面是执行流程的跟踪:
void RenderTarget::UpdateImpl() { FirePreUpdate(); //update viewport if(m_pActiveViewport){ FireViewportPreUpdate(m_pActiveViewport); m_pActiveViewport->Update(); FireViewportPostUpdate(m_pActiveViewport); } }
<pre name="code" class="cpp"> void RenderTarget::FirePreUpdate() { for(RenderTargetListenerList::iterator it = m_vListeners.begin(); it != m_vListeners.end(); ++it){ (*it)->PreRenderTargetUpdate(this); } }
void CompositorChain::PreRenderTargetUpdate(RenderTarget* target) { if(m_bDirty) Compile(); //else // return ; if(!m_bAnyCompositorEnabled) return ; Camera* cam = m_pViewport->GetCamera(); for(CompositorInstance::CompileState::iterator it = m_CompileState.begin(); it != m_CompileState.end(); ++it){ //if(it->onlyInitial)//it->hasBeenRendered) // continue; //it->hasBeenRendered = true; PreTargetOperation((*it),it->target->GetViewport(),cam); it->target->Update(false); PostTargetOperation((*it),it->target->GetViewport(),cam); } }
void RSQuadOperation::Execute(SceneManager* sm,RenderSystem* rs) { Pass* pass = technqiue->GetPass(0); if(pass){ Rectangle2D* rect = static_cast<Rectangle2D*>(CompositorManager::GetSingleton().GetTexturedRectangle2D()); // sm->InjectRenderWithPass(pass,rect); } }
void CompositorInstance::CollectPasses(TargetOperation& targetOp,CompositionTargetPass* target) { MaterialPtr mat,srcmat; Technique* srctech; Pass* targetpass,*srcpass; CompositionTargetPass::Passes& passes = target->GetPasses(); for(CompositionTargetPass::Passes::iterator it = passes.begin(); it != passes.end(); ++it){ CompositionPass* pass = *it; switch(pass->GetType()){ case CompositionPass::PT_CLEAR: QueueRenderSystemOp(targetOp, new RSClearOperation(pass->GetClearBuffers(), pass->GetClearColor(), pass->GetClearDepth(), pass->GetClearStencil())); break; case CompositionPass::PT_RENDERSCENE: // targetOp.currentQueueGroupID = pass->GetLastRenderQueue()+1; targetOp.findVisibleObjects = true; break; case CompositionPass::PT_RENDERQUAD: srcmat = pass->GetMaterial(); if(srcmat.IsNull()){ LOGERROR("CompositorInstance::CollectPasses material is null"); return ; } //srcmat->Load(); srctech = srcmat->GetTechnique(0); srcpass = srctech->GetPass(0); MaterialPtr mat = CreateLocalMaterial(srcmat->GetName()); Technique* tech = mat->CreateTechnique(); targetpass = tech->CreatePass(); //use srcpass *targetpass = *srcpass; //set input tex const CompositionPass::InputTex& inTex = pass->GetInput(0); string texName = m_pCompositor->GetName()+"/"+inTex.name; targetpass->GetTextureUnitState()->SetTextureName(texName,TEX_TYPE_2D); //queue QueueRenderSystemOp(targetOp,new RSQuadOperation(this,pass->GetIdentifier(),mat)); break; } } }最后是所用到的shader文件(glsl),
vertex:
#version 400
in vec3 vertex;
in vec3 normal;
in vec2 uv0;
uniform mat4 MVP;
out vec2 uv;
out vec3 outNormal;
//out vec2 outUV;
void main()
{
gl_Position = MVP * vec4(vertex,1.0);
//vec2 inPos = sign(vertex.xy);
//uv = (vec2(inPos.x, inPos.y) + 1.0)/2.0;
uv = uv0;
outNormal = normal;
}
fragment:
#version 400
uniform sampler2D inRTT;
uniform vec4 sampleOffsets[15];
uniform vec4 sampleWeights[15];
in vec2 uv;
void main(void)
{
vec4 accum = vec4(0.0, 0.0, 0.0, 1.0);
vec2 sampleUV;
for( int i = 0; i < 15; i++ )
{
// Sample from adjacent points, 7 each side and central
sampleUV = uv + sampleOffsets[i].xy;
accum += sampleWeights[i] * texture2D(inRTT, sampleUV);
}
gl_FragColor = accum;
}