[bugfix] ClippingNode & CameraBackgroundBrush render order (#19496)

* add groupcommand as a barrier to reorder clipping node renderring

* add comments
This commit is contained in:
Arnold 2019-03-12 15:41:32 +08:00 committed by minggo
parent ac6d3f10f0
commit 475b6e63a5
9 changed files with 164 additions and 155 deletions

View File

@ -121,9 +121,6 @@ CameraBackgroundDepthBrush* CameraBackgroundDepthBrush::create(float depth)
bool CameraBackgroundDepthBrush::init()
{
_beforeCommand.func = CC_CALLBACK_0(CameraBackgroundDepthBrush::onBeforeDraw, this);
_afterCommand.func = CC_CALLBACK_0(CameraBackgroundDepthBrush::onAfterDraw, this);
CC_SAFE_RELEASE_NULL(_programState);
_programState = new backend::ProgramState(cameraClear_vert, cameraClear_frag);
@ -135,7 +132,7 @@ bool CameraBackgroundDepthBrush::init()
auto &layout = pipelineDescriptor.vertexLayout;
layout.setAtrribute("a_position", 0, backend::VertexFormat::FLOAT3, offsetof(V3F_C4B_T2F, vertices), false);
layout.setAtrribute("a_color", 1, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true);
layout.setAtrribute("a_color", 1, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true);
layout.setAtrribute("a_texCoord", 2, backend::VertexFormat::FLOAT2, offsetof(V3F_C4B_T2F, texCoords), true);
layout.setLayout(sizeof(_vertices[0]), backend::VertexStepMode::VERTEX);
@ -152,6 +149,8 @@ bool CameraBackgroundDepthBrush::init()
_vertices[2].texCoords = Tex2F(1, 1);
_vertices[3].texCoords = Tex2F(0, 1);
_customCommand.setBeforeCallback(CC_CALLBACK_0(CameraBackgroundDepthBrush::onBeforeDraw, this));
_customCommand.setAfterCallback(CC_CALLBACK_0(CameraBackgroundDepthBrush::onAfterDraw, this));
initBuffer();
return true;
@ -169,34 +168,37 @@ void CameraBackgroundDepthBrush::initBuffer()
void CameraBackgroundDepthBrush::drawBackground(Camera* /*camera*/)
{
_beforeCommand.init(0.0f);
// `clear screen` should be executed before other commands
_groupCommand.init(-1.0f);
_customCommand.init(0.0f);
_afterCommand.init(0.0f);
auto *renderer = Director::getInstance()->getRenderer();
auto &pipelineDescriptor = _customCommand.getPipelineDescriptor();
auto& blend = pipelineDescriptor.blendDescriptor;
blend.writeMask = _clearColor ? backend::ColorWriteMask::ALL : backend::ColorWriteMask::NONE;
renderer->addCommand(&_groupCommand);
renderer->pushGroup(_groupCommand.getRenderQueueID());
renderer->setStencilWriteMask(0);
renderer->setDepthTest(true);
renderer->setDepthCompareFunction(backend::CompareFunction::ALWAYS);
auto &pipelineDescriptor = _customCommand.getPipelineDescriptor();
auto &blend = pipelineDescriptor.blendDescriptor;
blend.writeMask = _clearColor ? backend::ColorWriteMask::ALL : backend::ColorWriteMask::NONE;
//draw
_programState->setUniform(_locDepth, &_depth, sizeof(_depth));
renderer->addCommand(&_beforeCommand);
renderer->addCommand(&_customCommand);
renderer->addCommand(&_afterCommand);
renderer->popGroup();
}
void CameraBackgroundDepthBrush::onBeforeDraw()
{
auto *renderer = Director::getInstance()->getRenderer();
_stateBlock.stencilWriteMask = renderer->getStencilWriteMask();
_stateBlock.depthTest = renderer->getDepthTest();
_stateBlock.compareFunc = renderer->getDepthCompareFunction();
_stateBlock.stencilWriteMask = renderer->getStencilWriteMask();
_stateBlock.depthTest = renderer->getDepthTest();
_stateBlock.compareFunc = renderer->getDepthCompareFunction();
renderer->setStencilWriteMask(0);
renderer->setDepthTest(true);
renderer->setDepthCompareFunction(backend::CompareFunction::ALWAYS);
}
void CameraBackgroundDepthBrush::onAfterDraw()
@ -229,7 +231,12 @@ bool CameraBackgroundColorBrush::init()
void CameraBackgroundColorBrush::drawBackground(Camera* camera)
{
utils::setBlending(BlendFunc::ALPHA_NON_PREMULTIPLIED.src, BlendFunc::ALPHA_NON_PREMULTIPLIED.dst);
BlendFunc op = { BlendFunc::ALPHA_NON_PREMULTIPLIED.src, BlendFunc::ALPHA_NON_PREMULTIPLIED.dst };
auto &blend = _customCommand.getPipelineDescriptor().blendDescriptor;
blend.sourceRGBBlendFactor = blend.sourceAlphaBlendFactor = op.src;
blend.destinationRGBBlendFactor = blend.destinationAlphaBlendFactor = op.dst;
blend.blendEnabled = true;
CameraBackgroundDepthBrush::drawBackground(camera);
}
@ -313,8 +320,8 @@ CameraBackgroundSkyBoxBrush* CameraBackgroundSkyBoxBrush::create(
Texture2D::TexParams tRepeatParams;
tRepeatParams.magFilter = GL_LINEAR;
tRepeatParams.minFilter = GL_LINEAR;
tRepeatParams.wrapS = GL_CLAMP_TO_EDGE;
tRepeatParams.wrapT = GL_CLAMP_TO_EDGE;
tRepeatParams.wrapS = GL_CLAMP_TO_EDGE;
tRepeatParams.wrapT = GL_CLAMP_TO_EDGE;
texture->setTexParameters(tRepeatParams);
ret = new (std::nothrow) CameraBackgroundSkyBoxBrush;
@ -352,10 +359,9 @@ CameraBackgroundSkyBoxBrush* CameraBackgroundSkyBoxBrush::create()
void CameraBackgroundSkyBoxBrush::drawBackground(Camera* camera)
{
_beforeCommand.init(0.0f);
// `clear screen` should be executed before other commands
_groupCommand.init(-1.0f);
_customCommand.init(0.0f);
_afterCommand.init(0.0f);
if (!_actived)
return;
@ -373,9 +379,12 @@ void CameraBackgroundSkyBoxBrush::drawBackground(Camera* camera)
auto *renderer = Director::getInstance()->getRenderer();
renderer->addCommand(&_beforeCommand);
renderer->addCommand(&_groupCommand);
renderer->pushGroup(_groupCommand.getRenderQueueID());
renderer->addCommand(&_customCommand);
renderer->addCommand(&_afterCommand);
renderer->popGroup();
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 8);
@ -384,23 +393,22 @@ void CameraBackgroundSkyBoxBrush::drawBackground(Camera* camera)
bool CameraBackgroundSkyBoxBrush::init()
{
_beforeCommand.func = CC_CALLBACK_0(CameraBackgroundSkyBoxBrush::onBeforeDraw, this);
_afterCommand.func = CC_CALLBACK_0(CameraBackgroundSkyBoxBrush::onAfterDraw, this);
_customCommand.setBeforeCallback(CC_CALLBACK_0(CameraBackgroundSkyBoxBrush::onBeforeDraw, this));
_customCommand.setAfterCallback(CC_CALLBACK_0(CameraBackgroundSkyBoxBrush::onAfterDraw, this));
CC_SAFE_RELEASE_NULL(_programState);
_programState = new backend::ProgramState(CC3D_skybox_vert, CC3D_skybox_frag);
_uniformColorLoc = _programState->getUniformLocation("u_color");
_uniformCameraRotLoc = _programState->getUniformLocation("u_cameraRot");
_uniformEnvLoc = _programState->getUniformLocation("u_Env");
_programState = new backend::ProgramState(CC3D_skybox_vert, CC3D_skybox_frag);
_uniformColorLoc = _programState->getUniformLocation("u_color");
_uniformCameraRotLoc = _programState->getUniformLocation("u_cameraRot");
_uniformEnvLoc = _programState->getUniformLocation("u_Env");
auto &pipelineDescriptor = _customCommand.getPipelineDescriptor();
auto &layout = pipelineDescriptor.vertexLayout;
pipelineDescriptor.programState = _programState;
auto &pipelineDescriptor = _customCommand.getPipelineDescriptor();
auto &layout = pipelineDescriptor.vertexLayout;
pipelineDescriptor.programState = _programState;
// disable blend
pipelineDescriptor.blendDescriptor.blendEnabled = false;
pipelineDescriptor.blendDescriptor.blendEnabled = false;
layout.setAtrribute(shaderinfos::attribute::ATTRIBUTE_NAME_POSITION, 0, backend::VertexFormat::FLOAT3, 0, false);
layout.setLayout(sizeof(Vec3), backend::VertexStepMode::VERTEX);
@ -422,7 +430,8 @@ void CameraBackgroundSkyBoxBrush::initBuffer()
_customCommand.updateVertexBuffer(vexBuf, sizeof(vexBuf));
// init index buffer object
uint16_t idxBuf[] = { 2, 1, 0, 3, 2, 0, // font
uint16_t idxBuf[] = {
2, 1, 0, 3, 2, 0, // font
1, 5, 4, 1, 4, 0, // right
4, 5, 6, 4, 6, 7, // back
7, 6, 2, 7, 2, 3, // left
@ -447,12 +456,12 @@ bool CameraBackgroundSkyBoxBrush::isActived() const
}
void CameraBackgroundSkyBoxBrush::setActived(bool actived)
{
_actived = actived;
_actived = actived;
}
void CameraBackgroundSkyBoxBrush::setTextureValid(bool valid)
{
_textureValid = valid;
_textureValid = valid;
}
bool CameraBackgroundSkyBoxBrush::isValid()
@ -463,10 +472,10 @@ bool CameraBackgroundSkyBoxBrush::isValid()
void CameraBackgroundSkyBoxBrush::onBeforeDraw()
{
auto *renderer = Director::getInstance()->getRenderer();
_stateBlock.depthTest = renderer->getDepthTest();
_stateBlock.depthWrite = renderer->getDepthWrite();
_stateBlock.depthFunc = renderer->getDepthCompareFunction();
_stateBlock.cullMode = renderer->getCullMode();
_stateBlock.depthTest = renderer->getDepthTest();
_stateBlock.depthWrite = renderer->getDepthWrite();
_stateBlock.depthFunc = renderer->getDepthCompareFunction();
_stateBlock.cullMode = renderer->getCullMode();
}
void CameraBackgroundSkyBoxBrush::onAfterDraw()

View File

@ -23,8 +23,7 @@
THE SOFTWARE.
****************************************************************************/
#ifndef _CCCAMERA_BACKGROUND_BRUSH_H__
#define _CCCAMERA_BACKGROUND_BRUSH_H__
#pragma once
#include "base/ccTypes.h"
#include "base/CCRef.h"
@ -32,7 +31,7 @@
#include "3d/CCFrustum.h"
#include "renderer/CCQuadCommand.h"
#include "renderer/CCCustomCommand.h"
#include "renderer/CCCallbackCommand.h"
#include "renderer/CCGroupCommand.h"
#include "renderer/backend/Types.h"
#include <vector>
@ -171,8 +170,8 @@ protected:
float _depth;
backend::UniformLocation _locDepth;
CustomCommand _customCommand;
CallbackCommand _beforeCommand;
CallbackCommand _afterCommand;
GroupCommand _groupCommand;
GLboolean _clearColor;
std::vector<V3F_C4B_T2F> _vertices;
struct {
@ -299,8 +298,7 @@ private:
bool _textureValid;
CustomCommand _customCommand;
CallbackCommand _beforeCommand;
CallbackCommand _afterCommand;
GroupCommand _groupCommand;
backend::UniformLocation _uniformColorLoc;
backend::UniformLocation _uniformCameraRotLoc;
@ -316,4 +314,3 @@ private:
NS_CC_END
#endif// _CCCAMERA_BACKGROUND_BRUSH_H__

View File

@ -46,7 +46,6 @@ NS_CC_BEGIN
ClippingNode::ClippingNode()
: _stencil(nullptr)
, _originStencilProgram(nullptr)
, _stencilStateManager(new StencilStateManager())
{
}
@ -196,10 +195,10 @@ void ClippingNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32
//Add group command
_groupCommand.init(_globalZOrder);
renderer->addCommand(&_groupCommand);
_groupCommandStencil.init(_globalZOrder);
renderer->addCommand(&_groupCommandStencil);
renderer->pushGroup(_groupCommand.getRenderQueueID());
renderer->pushGroup(_groupCommandStencil.getRenderQueueID());
// _beforeVisitCmd.init(_globalZOrder);
// _beforeVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onBeforeVisit, _stencilStateManager);
@ -231,6 +230,14 @@ void ClippingNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32
int i = 0;
bool visibleByCamera = isVisitableByVisitingCamera();
// `_groupCommandChildren` is used as a barrier
// to ensure commands above be executed before children nodes
_groupCommandChildren.init(_globalZOrder);
renderer->addCommand(&_groupCommandChildren);
renderer->pushGroup(_groupCommandChildren.getRenderQueueID());
if(!_children.empty())
{
sortAllChildren();
@ -256,6 +263,9 @@ void ClippingNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32
this->draw(renderer, _modelViewTransform, flags);
}
renderer->popGroup();
_afterVisitCmd.init(_globalZOrder);
_afterVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterVisit, _stencilStateManager);
renderer->addCommand(&_afterVisitCmd);

View File

@ -154,13 +154,11 @@ CC_CONSTRUCTOR_ACCESS:
virtual bool init(Node *stencil);
protected:
Node* _stencil;
GLProgram* _originStencilProgram;
StencilStateManager* _stencilStateManager;
Node* _stencil = nullptr;
StencilStateManager* _stencilStateManager = nullptr;
GroupCommand _groupCommand;
CallbackCommand _beforeVisitCmd;
GroupCommand _groupCommandStencil;
GroupCommand _groupCommandChildren;
CallbackCommand _afterDrawStencilCmd;
CallbackCommand _afterVisitCmd;

View File

@ -72,7 +72,7 @@ void StencilStateManager::drawFullScreenQuadClearStencil(float globalZOrder)
{
_customCommand.init(globalZOrder);
Director::getInstance()->getRenderer()->addCommand(&_customCommand);
_customCommand.getPipelineDescriptor().programState->setUniform(_mvpMatrixLocaiton, Mat4::IDENTITY.m, sizeof(Mat4::IDENTITY.m));
_programState->setUniform(_mvpMatrixLocaiton, Mat4::IDENTITY.m, sizeof(Mat4::IDENTITY.m));
}
@ -110,70 +110,68 @@ void StencilStateManager::onBeforeVisit(float globalZOrder)
// mask of all layers less than or equal to the current (ie: for layer 3: 00000111)
_mask_layer_le = mask_layer | mask_layer_l;
_beforeDrawQuadCmd.init(globalZOrder);
_beforeDrawQuadCmd.func = [=]() -> void {
// manually save the stencil state
_currentStencilEnabled = renderer->getStencilTest();
_currentStencilWriteMask = renderer->getStencilWriteMask();
_currentStencilFunc = renderer->getStencilCompareFunction();
_currentStencilRef = renderer->getStencilReferenceValue();
_currentStencilReadMask = renderer->getStencilReadMask();
_currentStencilFail = renderer->getStencilFailureOperation();
_currentStencilPassDepthFail = renderer->getStencilPassDepthFailureOperation();
_currentStencilPassDepthPass = renderer->getStencilDepthPassOperation();
// enable stencil use
renderer->setStencilTest(true);
// all bits on the stencil buffer are readonly, except the current layer bit,
// this means that operation like glClear or glStencilOp will be masked with this value
renderer->setStencilWriteMask(mask_layer);
// manually save the depth test state
_currentDepthWriteMask = renderer->getDepthWrite();
// disable update to the depth buffer while drawing the stencil,
// as the stencil is not meant to be rendered in the real scene,
// it should never prevent something else to be drawn,
// only disabling depth buffer update should do
renderer->setDepthWrite(false);
///////////////////////////////////
// CLEAR STENCIL BUFFER
// manually clear the stencil buffer by drawing a fullscreen rectangle on it
// setup the stencil test func like this:
// for each pixel in the fullscreen rectangle
// never draw it into the frame buffer
// if not in inverted mode: set the current layer value to 0 in the stencil buffer
// if in inverted mode: set the current layer value to 1 in the stencil buffer
renderer->setStencilCompareFunction(backend::CompareFunction::NEVER, mask_layer, mask_layer);
renderer->setStencilOperation(!_inverted ? backend::StencilOperation::ZERO : backend::StencilOperation::REPLACE,
backend::StencilOperation::KEEP,
backend::StencilOperation::KEEP);
};
renderer->addCommand(&_beforeDrawQuadCmd);
_customCommand.setBeforeCallback(CC_CALLBACK_0(StencilStateManager::onBeforeDrawQuadCmd, this, (int)mask_layer));
_customCommand.setAfterCallback(CC_CALLBACK_0(StencilStateManager::onAfterDrawQuadCmd, this, (int)mask_layer));
// draw a fullscreen solid rectangle to clear the stencil buffer
drawFullScreenQuadClearStencil(globalZOrder);
_afterDrawQuadCmd.init(globalZOrder);
_afterDrawQuadCmd.func = [=]() -> void {
// setup the stencil test func like this:
// for each pixel in the stencil node
// never draw it into the frame buffer
// if not in inverted mode: set the current layer value to 1 in the stencil buffer
// if in inverted mode: set the current layer value to 0 in the stencil buffer
auto renderer = Director::getInstance()->getRenderer();
renderer->setStencilCompareFunction(backend::CompareFunction::NEVER, mask_layer, mask_layer);
}
renderer->setStencilOperation(!_inverted ? backend::StencilOperation::REPLACE : backend::StencilOperation::ZERO,
backend::StencilOperation::KEEP,
backend::StencilOperation::KEEP);
};
renderer->addCommand(&_afterDrawQuadCmd);
void StencilStateManager::onBeforeDrawQuadCmd(int mask_layer)
{
auto renderer = Director::getInstance()->getRenderer();
// manually save the stencil state
_currentStencilEnabled = renderer->getStencilTest();
_currentStencilWriteMask = renderer->getStencilWriteMask();
_currentStencilFunc = renderer->getStencilCompareFunction();
_currentStencilRef = renderer->getStencilReferenceValue();
_currentStencilReadMask = renderer->getStencilReadMask();
_currentStencilFail = renderer->getStencilFailureOperation();
_currentStencilPassDepthFail = renderer->getStencilPassDepthFailureOperation();
_currentStencilPassDepthPass = renderer->getStencilDepthPassOperation();
// enable stencil use
renderer->setStencilTest(true);
// all bits on the stencil buffer are readonly, except the current layer bit,
// this means that operation like glClear or glStencilOp will be masked with this value
renderer->setStencilWriteMask(mask_layer);
// manually save the depth test state
_currentDepthWriteMask = renderer->getDepthWrite();
// disable update to the depth buffer while drawing the stencil,
// as the stencil is not meant to be rendered in the real scene,
// it should never prevent something else to be drawn,
// only disabling depth buffer update should do
renderer->setDepthWrite(false);
///////////////////////////////////
// CLEAR STENCIL BUFFER
// manually clear the stencil buffer by drawing a fullscreen rectangle on it
// setup the stencil test func like this:
// for each pixel in the fullscreen rectangle
// never draw it into the frame buffer
// if not in inverted mode: set the current layer value to 0 in the stencil buffer
// if in inverted mode: set the current layer value to 1 in the stencil buffer
renderer->setStencilCompareFunction(backend::CompareFunction::NEVER, mask_layer, mask_layer);
renderer->setStencilOperation(!_inverted ? backend::StencilOperation::ZERO : backend::StencilOperation::REPLACE,
backend::StencilOperation::KEEP,
backend::StencilOperation::KEEP);
}
void StencilStateManager::onAfterDrawQuadCmd(int mask_layer)
{
auto renderer = Director::getInstance()->getRenderer();
renderer->setStencilCompareFunction(backend::CompareFunction::NEVER, mask_layer, mask_layer);
renderer->setStencilOperation(!_inverted ? backend::StencilOperation::REPLACE : backend::StencilOperation::ZERO,
backend::StencilOperation::KEEP,
backend::StencilOperation::KEEP);
}
void StencilStateManager::onAfterDrawStencil()

View File

@ -56,6 +56,8 @@ private:
*/
void drawFullScreenQuadClearStencil(float globalZOrder);
void onBeforeDrawQuadCmd(int maskLayer);
void onAfterDrawQuadCmd(int maskLayer);
float _alphaThreshold = 1.f;
bool _inverted = false;
@ -77,8 +79,6 @@ private:
unsigned int _mask_layer_le = 0;
CustomCommand _customCommand;
CallbackCommand _beforeDrawQuadCmd;
CallbackCommand _afterDrawQuadCmd;
CallbackCommand _afterDrawStencilCmd;
CallbackCommand _afterVisitCmd;

View File

@ -62,7 +62,10 @@ public:
cases.
*/
using IndexFormat = backend::IndexFormat;
typedef std::function<void()> CallBackFunc;
/**Constructor.*/
CustomCommand();
/**Destructor.*/
@ -192,6 +195,20 @@ public:
//TODO:minggo: should remove it.
std::function<void()> func;
/**
* set a callback which will be invoke before rendering
*/
void setBeforeCallback(const CallBackFunc &before) { _beforeCallback = before; }
/**
* set a callback which will be invoke after rendering
*/
void setAfterCallback(const CallBackFunc &after) { _afterCallback = after; }
const CallBackFunc &getBeforeCallback() { return _beforeCallback; }
const CallBackFunc &getAfterCallback() { return _afterCallback; }
protected:
unsigned int computeIndexSize() const;
@ -214,6 +231,10 @@ protected:
unsigned int _vertexCapacity = 0;
unsigned int _indexCapacity = 0;
CallBackFunc _beforeCallback = nullptr;
CallBackFunc _afterCallback = nullptr;
};
NS_CC_END

View File

@ -23,8 +23,7 @@
THE SOFTWARE.
****************************************************************************/
#ifndef _CC_MESHCOMMAND_H_
#define _CC_MESHCOMMAND_H_
#pragma once
#include <unordered_map>
#include "renderer/CCRenderCommand.h"
@ -57,8 +56,6 @@ public:
*/
using IndexFormat = backend::IndexFormat;
typedef std::function<void()> CallBackFunc;
MeshCommand();
virtual ~MeshCommand();
@ -68,29 +65,11 @@ public:
*/
void init(float globalZOrder);
/**
* set a callback which will be invoke before rendering
*/
void setBeforeCallback(const CallBackFunc &before) { _beforeCallback = before; }
/**
* set a callback which will be invoke after rendering
*/
void setAfterCallback(const CallBackFunc &after){ _afterCallback = after; }
const CallBackFunc &getBeforeCallback() { return _beforeCallback; }
const CallBackFunc &getAfterCallback() { return _afterCallback; }
#if CC_ENABLE_CACHE_TEXTURE_DATA
void listenRendererRecreated(EventCustom* event);
#endif
protected:
CallBackFunc _beforeCallback = nullptr;
CallBackFunc _afterCallback = nullptr;
#if CC_ENABLE_CACHE_TEXTURE_DATA
EventListenerCustom* _rendererRecreatedListener;
#endif
@ -98,4 +77,3 @@ protected:
NS_CC_END
#endif //_CC_MESHCOMMAND_H_

View File

@ -642,7 +642,9 @@ void Renderer::drawBatchedTriangles()
void Renderer::drawCustomCommand(RenderCommand *command)
{
auto cmd = static_cast<CustomCommand*>(command);
if (cmd->getBeforeCallback()) cmd->getBeforeCallback()();
beginRenderPass(command);
_commandBuffer->setVertexBuffer(0, cmd->getVertexBuffer());
_commandBuffer->setProgramState(cmd->getPipelineDescriptor().programState);
@ -667,18 +669,14 @@ void Renderer::drawCustomCommand(RenderCommand *command)
}
_drawnBatches++;
_commandBuffer->endRenderPass();
if (cmd->getAfterCallback()) cmd->getAfterCallback()();
}
void Renderer::drawMeshCommand(RenderCommand *command)
{
auto cmd = static_cast<MeshCommand*>(command);
if (cmd->getBeforeCallback()) cmd->getBeforeCallback()();
//MeshCommand and CustomCommand are identical while rendering.
drawCustomCommand(command);
if (cmd->getAfterCallback()) cmd->getAfterCallback()();
}