diff --git a/cocos/2d/CCCamera.cpp b/cocos/2d/CCCamera.cpp index 354bdcdb73..1fa4807f2e 100644 --- a/cocos/2d/CCCamera.cpp +++ b/cocos/2d/CCCamera.cpp @@ -91,13 +91,6 @@ Camera::~Camera() } -void Camera::setPosition3D(const Vec3& position) -{ - Node::setPosition3D(position); - - _transformUpdated = _transformDirty = _inverseDirty = true; -} - const Mat4& Camera::getProjectionMatrix() const { return _projection; diff --git a/cocos/2d/CCCamera.h b/cocos/2d/CCCamera.h index 37fbfeac6a..5e15eb23f8 100644 --- a/cocos/2d/CCCamera.h +++ b/cocos/2d/CCCamera.h @@ -102,10 +102,6 @@ public: /**get & set Camera flag*/ CameraFlag getCameraFlag() const { return (CameraFlag)_cameraFlag; } void setCameraFlag(CameraFlag flag) { _cameraFlag = (unsigned short)flag; } - /** - * Sets the position (X, Y, and Z) in its parent's coordinate system - */ - virtual void setPosition3D(const Vec3& position) override; /** * Make Camera looks at target diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index c933eef593..ebac7333ab 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -609,10 +609,6 @@ void Node::setPositionZ(float positionZ) _transformUpdated = _transformDirty = _inverseDirty = true; _positionZ = positionZ; - - // FIXME: BUG - // Global Z Order should based on the modelViewTransform - setGlobalZOrder(positionZ); } /// position getter diff --git a/cocos/2d/CCNode.h b/cocos/2d/CCNode.h index 89f8d8da82..703c81ad32 100644 --- a/cocos/2d/CCNode.h +++ b/cocos/2d/CCNode.h @@ -1122,7 +1122,7 @@ public: * * @return An Action pointer */ - Action* runAction(Action* action); + virtual Action* runAction(Action* action); /** * Stops and removes all actions from the running action list . diff --git a/cocos/3d/CCSprite3D.cpp b/cocos/3d/CCSprite3D.cpp index 1c28f4c13c..fdf69f6aef 100644 --- a/cocos/3d/CCSprite3D.cpp +++ b/cocos/3d/CCSprite3D.cpp @@ -741,6 +741,10 @@ void Sprite3D::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) } //support tint and fade meshCommand.setDisplayColor(Vec4(color.r, color.g, color.b, color.a)); + if (_forceDepthWrite) + { + meshCommand.setDepthWriteEnabled(true); + } meshCommand.setTransparent(isTransparent); renderer->addCommand(&meshCommand); } @@ -801,6 +805,12 @@ const AABB& Sprite3D::getAABB() const return _aabb; } +Action* Sprite3D::runAction(Action *action) +{ + setForceDepthWrite(true); + return Node::runAction(action); +} + Rect Sprite3D::getBoundingBox() const { AABB aabb = getAABB(); diff --git a/cocos/3d/CCSprite3D.h b/cocos/3d/CCSprite3D.h index cec60085c7..b819c4471d 100644 --- a/cocos/3d/CCSprite3D.h +++ b/cocos/3d/CCSprite3D.h @@ -126,6 +126,22 @@ public: */ const AABB& getAABB() const; + /** + * Executes an action, and returns the action that is executed. For Sprite3D special logic are needed to take care of Fading. + * + * This node becomes the action's target. Refer to Action::getTarget() + * @warning Actions don't retain their target. + * + * @return An Action pointer + */ + virtual Action* runAction(Action* action) override; + + /** + * Force to write to depth buffer, this is useful if you want to achieve effects like fading. + */ + void setForceDepthWrite(bool value) { _forceDepthWrite = value; } + bool isForceDepthWrite() const { return _forceDepthWrite;}; + /** * Returns 2d bounding-box * Note: the bouding-box is just get from the AABB which as Z=0, so that is not very accurate. @@ -200,6 +216,7 @@ protected: bool _aabbDirty; unsigned int _lightMask; bool _shaderUsingLight; // is current shader using light ? + bool _forceDepthWrite; // Always write to depth buffer struct AsyncLoadParam { diff --git a/cocos/renderer/CCMeshCommand.cpp b/cocos/renderer/CCMeshCommand.cpp index 630e6c1294..48685f2c64 100644 --- a/cocos/renderer/CCMeshCommand.cpp +++ b/cocos/renderer/CCMeshCommand.cpp @@ -42,12 +42,6 @@ NS_CC_BEGIN -//render state -static bool s_cullFaceEnabled = false; -static GLenum s_cullFace = 0; -static bool s_depthTestEnabled = false; -static bool s_depthWriteEnabled = false; - static const char *s_dirLightUniformColorName = "u_DirLightSourceColor"; static std::vector s_dirLightUniformColorValues; static const char *s_dirLightUniformDirName = "u_DirLightSourceDirection"; @@ -159,6 +153,7 @@ void MeshCommand::setDepthTestEnabled(bool enable) void MeshCommand::setDepthWriteEnabled(bool enable) { + _forceDepthWrite = enable; _depthWriteEnabled = enable; } @@ -172,7 +167,11 @@ void MeshCommand::setTransparent(bool value) _isTransparent = value; //Skip batching for transparent mesh _skipBatching = value; - setDepthWriteEnabled(!_isTransparent); + + if (!_forceDepthWrite) + { + _depthWriteEnabled = true; + } } MeshCommand::~MeshCommand() @@ -185,46 +184,48 @@ MeshCommand::~MeshCommand() void MeshCommand::applyRenderState() { - if (_cullFaceEnabled && !s_cullFaceEnabled) + _renderStateCullFace = glIsEnabled(GL_CULL_FACE); + _renderStateDepthTest = glIsEnabled(GL_DEPTH_TEST); + glGetBooleanv(GL_DEPTH_WRITEMASK, &_renderStateDepthWrite); + + if (_cullFaceEnabled && !_renderStateCullFace) { glEnable(GL_CULL_FACE); - s_cullFaceEnabled = true; } - if (s_cullFace != _cullFace) - { - glCullFace(_cullFace); - s_cullFace = _cullFace; - } - if (_depthTestEnabled && !s_depthTestEnabled) + + glCullFace(_cullFace); + + if (_depthTestEnabled && !_renderStateDepthTest) { glEnable(GL_DEPTH_TEST); - s_depthTestEnabled = true; } - if (_depthWriteEnabled && !s_depthWriteEnabled) + if (_depthWriteEnabled && !_renderStateDepthWrite) { glDepthMask(GL_TRUE); - s_depthWriteEnabled = true; } } void MeshCommand::restoreRenderState() { - if (s_cullFaceEnabled) + if (_renderStateCullFace) + { + glEnable(GL_CULL_FACE); + } + else { glDisable(GL_CULL_FACE); - s_cullFaceEnabled = false; } - if (s_depthTestEnabled) + + if (_renderStateDepthTest) + { + glEnable(GL_DEPTH_TEST); + } + else { glDisable(GL_DEPTH_TEST); - s_depthTestEnabled = false; } - if (s_depthWriteEnabled) - { - glDepthMask(GL_FALSE); - s_depthWriteEnabled = false; - } - s_cullFace = 0; + + glDepthMask(_renderStateDepthTest); } void MeshCommand::genMaterialID(GLuint texID, void* glProgramState, GLuint vertexBuffer, GLuint indexBuffer, const BlendFunc& blend) diff --git a/cocos/renderer/CCMeshCommand.h b/cocos/renderer/CCMeshCommand.h index 3dfc6937ed..128c294913 100644 --- a/cocos/renderer/CCMeshCommand.h +++ b/cocos/renderer/CCMeshCommand.h @@ -127,6 +127,11 @@ protected: GLenum _cullFace; bool _depthTestEnabled; bool _depthWriteEnabled; + bool _forceDepthWrite; + + bool _renderStateCullFace; + bool _renderStateDepthTest; + GLboolean _renderStateDepthWrite; // ModelView transform Mat4 _mv; diff --git a/cocos/renderer/CCRenderCommand.cpp b/cocos/renderer/CCRenderCommand.cpp index 0a8f3c7ee6..a0affae504 100644 --- a/cocos/renderer/CCRenderCommand.cpp +++ b/cocos/renderer/CCRenderCommand.cpp @@ -35,6 +35,7 @@ RenderCommand::RenderCommand() , _isTransparent(true) , _skipBatching(false) , _is3D(false) +, _depth(0) { } @@ -44,14 +45,16 @@ RenderCommand::~RenderCommand() void RenderCommand::init(float globalZOrder, const cocos2d::Mat4 &transform, uint32_t flags) { + _globalOrder = globalZOrder; if (flags & Node::FLAGS_RENDER_AS_3D) { - _globalOrder = Camera::getVisitingCamera()->getDepthInView(transform); + _depth = Camera::getVisitingCamera()->getDepthInView(transform); set3D(true); } else { - _globalOrder = globalZOrder; + set3D(false); + _depth = 0; } } diff --git a/cocos/renderer/CCRenderCommand.h b/cocos/renderer/CCRenderCommand.h index a127944bcb..88d98c0ae7 100644 --- a/cocos/renderer/CCRenderCommand.h +++ b/cocos/renderer/CCRenderCommand.h @@ -77,7 +77,9 @@ public: inline bool is3D() const { return _is3D; } inline void set3D(bool value) { _is3D = value; } - + + inline float getDepth() const { return _depth; } + protected: RenderCommand(); virtual ~RenderCommand(); @@ -98,6 +100,9 @@ protected: // is the command been rendered on 3D pass bool _is3D; + + // depth + float _depth; }; NS_CC_END diff --git a/cocos/renderer/CCRenderer.cpp b/cocos/renderer/CCRenderer.cpp index e4b087dbc0..9754bea3d5 100644 --- a/cocos/renderer/CCRenderer.cpp +++ b/cocos/renderer/CCRenderer.cpp @@ -53,7 +53,7 @@ static bool compareRenderCommand(RenderCommand* a, RenderCommand* b) static bool compare3DCommand(RenderCommand* a, RenderCommand* b) { - return a->getGlobalOrder() > b->getGlobalOrder(); + return a->getDepth() > b->getDepth(); } // queue @@ -61,74 +61,78 @@ static bool compare3DCommand(RenderCommand* a, RenderCommand* b) void RenderQueue::push_back(RenderCommand* command) { float z = command->getGlobalOrder(); - if(command->is3D()) + if(z < 0) { - if(command->isTransparent()) + _commands[QUEUE_GROUP::GLOBALZ_NEG].push_back(command); + } + else if(z > 0) + { + _commands[QUEUE_GROUP::GLOBALZ_POS].push_back(command); + } + else + { + if(command->is3D()) { - _queue3DTransparent.push_back(command); + if(command->isTransparent()) + { + _commands[QUEUE_GROUP::TRANSPARENT_3D].push_back(command); + } + else + { + _commands[QUEUE_GROUP::OPAQUE_3D].push_back(command); + } } else { - _queue3DOpaque.push_back(command); + _commands[QUEUE_GROUP::GLOBALZ_ZERO].push_back(command); } } - else if(z < 0) - _queueNegZ.push_back(command); - else if(z > 0) - _queuePosZ.push_back(command); - else - _queue0.push_back(command); } ssize_t RenderQueue::size() const { - return _queue3DOpaque.size() + _queue3DTransparent.size() + _queueNegZ.size() + _queue0.size() + _queuePosZ.size(); + ssize_t result(0); + for(int index = 0; index < QUEUE_GROUP::QUEUE_COUNT; ++index) + { + result += _commands[index].size(); + } + + return result; } void RenderQueue::sort() { // Don't sort _queue0, it already comes sorted - std::sort(std::begin(_queue3DTransparent), std::end(_queue3DTransparent), compare3DCommand); - std::sort(std::begin(_queueNegZ), std::end(_queueNegZ), compareRenderCommand); - std::sort(std::begin(_queuePosZ), std::end(_queuePosZ), compareRenderCommand); + std::sort(std::begin(_commands[QUEUE_GROUP::TRANSPARENT_3D]), std::end(_commands[QUEUE_GROUP::TRANSPARENT_3D]), compare3DCommand); + std::sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_NEG]), std::end(_commands[QUEUE_GROUP::GLOBALZ_NEG]), compareRenderCommand); + std::sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_POS]), std::end(_commands[QUEUE_GROUP::GLOBALZ_POS]), compareRenderCommand); } RenderCommand* RenderQueue::operator[](ssize_t index) const { - if(index < static_cast(_queue3DOpaque.size())) - return _queue3DOpaque[index]; - - index -= _queue3DOpaque.size(); - - if(index < static_cast(_queue3DTransparent.size())) - return _queue3DTransparent[index]; + for(int queIndex = 0; queIndex < QUEUE_GROUP::QUEUE_COUNT; ++queIndex) + { + if(index < static_cast(_commands[queIndex].size())) + return _commands[queIndex][index]; + else + { + index -= _commands[queIndex].size(); + } + } - index -= _queue3DTransparent.size(); - - if(index < static_cast(_queueNegZ.size())) - return _queueNegZ[index]; - - index -= _queueNegZ.size(); - - if(index < static_cast(_queue0.size())) - return _queue0[index]; - - index -= _queue0.size(); - - if(index < static_cast(_queuePosZ.size())) - return _queuePosZ[index]; - CCASSERT(false, "invalid index"); return nullptr; + + } void RenderQueue::clear() { - _queue3DOpaque.clear(); - _queue3DTransparent.clear(); - _queueNegZ.clear(); - _queue0.clear(); - _queuePosZ.clear(); + _commands.clear(); + for(int index = 0; index < QUEUE_COUNT; ++index) + { + _commands.push_back(std::vector()); + } } void RenderQueue::saveRenderState() @@ -502,48 +506,104 @@ void Renderer::processRenderCommand(RenderCommand* command) void Renderer::visitRenderQueue(RenderQueue& queue) { - ssize_t size = queue.size(); - queue.saveRenderState(); - //Process Opaque Object - const std::vector& opaqueQueue = queue.getOpaqueCommands(); - if (opaqueQueue.size() > 0) + // + //Process Global-Z < 0 Objects + // + const auto& zNegQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::GLOBALZ_NEG); + if (zNegQueue.size() > 0) { - glDepthMask(true); - glEnable(GL_DEPTH_TEST); - - for (auto it = opaqueQueue.cbegin(); it != opaqueQueue.cend(); ++it) { + if(_isDepthTestFor2D) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + } + else + { + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + } + for (auto it = zNegQueue.cbegin(); it != zNegQueue.cend(); ++it) + { processRenderCommand(*it); } - - glDisable(GL_DEPTH_TEST); - glDepthMask(false); + flush(); } - flush(); - //Setup Transparent rendering + // + //Process Opaque Object + // + const auto& opaqueQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::OPAQUE_3D); if (opaqueQueue.size() > 0) { - glEnable(GL_DEPTH_TEST); - } - else - { - glDisable(GL_DEPTH_TEST); - } - - if(_isDepthTestFor2D) - { - glEnable(GL_DEPTH_TEST); + //Clear depth to achieve layered rendering glDepthMask(true); + glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + + for (auto it = opaqueQueue.cbegin(); it != opaqueQueue.cend(); ++it) + { + processRenderCommand(*it); + } + flush(); } - //Process Transparent Object - for (ssize_t index = queue.getOpaqueQueueSize(); index < size; ++index) + // + //Process 3D Transparent object + // + const auto& transQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::TRANSPARENT_3D); + if (transQueue.size() > 0) { - processRenderCommand(queue[index]); + glEnable(GL_DEPTH_TEST); + glDepthMask(false); + + for (auto it = transQueue.cbegin(); it != transQueue.cend(); ++it) + { + processRenderCommand(*it); + } + flush(); + } + + // + //Process Global-Z = 0 Queue + // + const auto& zZeroQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::GLOBALZ_ZERO); + if (zZeroQueue.size() > 0) + { + if(_isDepthTestFor2D) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + } + else + { + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + } + for (auto it = zZeroQueue.cbegin(); it != zZeroQueue.cend(); ++it) + { + processRenderCommand(*it); + } + flush(); + + glDepthMask(true); + glClear(GL_DEPTH_BUFFER_BIT); + glDepthMask(false); + } + + // + //Process Global-Z > 0 Queue + // + const auto& zPosQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::GLOBALZ_POS); + if (zPosQueue.size() > 0) + { + for (auto it = zPosQueue.cbegin(); it != zPosQueue.cend(); ++it) + { + processRenderCommand(*it); + } + flush(); } - flush(); queue.restoreRenderState(); } diff --git a/cocos/renderer/CCRenderer.h b/cocos/renderer/CCRenderer.h index b0c206b167..de8f3fbe1d 100644 --- a/cocos/renderer/CCRenderer.h +++ b/cocos/renderer/CCRenderer.h @@ -47,25 +47,36 @@ class MeshCommand; are the ones that have `z < 0` and `z > 0`. */ class RenderQueue { +public: + enum QUEUE_GROUP + { + GLOBALZ_NEG = 0, + OPAQUE_3D = 1, + TRANSPARENT_3D = 2, + GLOBALZ_ZERO = 3, + GLOBALZ_POS = 4, + QUEUE_COUNT = 5, + }; public: + RenderQueue() + { + clear(); + } void push_back(RenderCommand* command); ssize_t size() const; void sort(); RenderCommand* operator[](ssize_t index) const; void clear(); - ssize_t getOpaqueQueueSize() const { return _queue3DOpaque.size(); } - const std::vector& getOpaqueCommands() const { return _queue3DOpaque; } + inline std::vector& getSubQueue(QUEUE_GROUP group) { return _commands[group]; } + inline ssize_t getSubQueueSize(QUEUE_GROUP group) const { return _commands[group].size();} void saveRenderState(); void restoreRenderState(); protected: - std::vector _queue3DOpaque; - std::vector _queue3DTransparent; - std::vector _queueNegZ; - std::vector _queue0; - std::vector _queuePosZ; + + std::vector> _commands; //Render State related bool _isCullEnabled; diff --git a/tests/cpp-tests/Classes/Camera3DTest/Camera3DTest.cpp b/tests/cpp-tests/Classes/Camera3DTest/Camera3DTest.cpp index 42d29d5969..0408ea92dd 100644 --- a/tests/cpp-tests/Classes/Camera3DTest/Camera3DTest.cpp +++ b/tests/cpp-tests/Classes/Camera3DTest/Camera3DTest.cpp @@ -130,7 +130,6 @@ CameraRotationTest::CameraRotationTest() auto sp3d = Sprite3D::create(); sp3d->setPosition(s.width/2, s.height/2); - sp3d->setRotation3D(Vec3(90,90,0)); addChild(sp3d); auto lship = Label::create(); diff --git a/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.cpp b/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.cpp index 1e1faad178..b633f9252d 100644 --- a/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.cpp +++ b/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.cpp @@ -2212,6 +2212,7 @@ void UseCaseSprite3D::switchCase() { auto layer = LayerColor::create(Color4B(0, 0, 100, 255), s.width / 2.f, s.height / 2.f); layer->setPosition(s.width * 0.25f, s.height * 0.25f); + layer->setGlobalZOrder(-1); addChild(layer); std::string filename = "Sprite3DTest/girl.c3b";