diff --git a/cocos/3d/CCBillBoard.cpp b/cocos/3d/CCBillBoard.cpp index 8c63b9931c..4ed9e857b3 100644 --- a/cocos/3d/CCBillBoard.cpp +++ b/cocos/3d/CCBillBoard.cpp @@ -96,42 +96,102 @@ BillBoard* BillBoard::create(Mode mode) return nullptr; } -void BillBoard::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) +void BillBoard::visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags) { + // quick return if not visible. children won't be drawn. + if (!_visible) + { + return; + } + + uint32_t flags = processParentFlags(parentTransform, parentFlags); + + //Update Billboard transform + calculateBillbaordTransform(); + + Director* director = Director::getInstance(); + director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); + director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform); + + bool visibleByCamera = isVisitableByVisitingCamera(); + + int i = 0; + + if(!_children.empty()) + { + sortAllChildren(); + // draw children zOrder < 0 + for( ; i < _children.size(); i++ ) + { + auto node = _children.at(i); + + if (node && node->getLocalZOrder() < 0) + node->visit(renderer, _billboardTransform, flags); + else + break; + } + // self draw + if (visibleByCamera) + this->draw(renderer, _billboardTransform, flags); + + for(auto it=_children.cbegin()+i; it != _children.cend(); ++it) + (*it)->visit(renderer, _billboardTransform, flags); + } + else if (visibleByCamera) + { + this->draw(renderer, _billboardTransform, flags); + } + + director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); +} + +void BillBoard::calculateBillbaordTransform() +{ + //Get camera world position auto camera = Camera::getVisitingCamera(); const Mat4& camWorldMat = camera->getNodeToWorldTransform(); - if (memcmp(_camWorldMat.m, camWorldMat.m, sizeof(float) * 16) != 0 || memcmp(_mvTransform.m, transform.m, sizeof(float) * 16) != 0 || _modeDirty) + + //TODO: use math lib to calculate math lib + //Make it easier to read + if (memcmp(_camWorldMat.m, camWorldMat.m, sizeof(float) * 16) != 0 || _transformDirty || _modeDirty) { + //Rotate based on anchor point Vec3 anchorPoint(_anchorPointInPoints.x , _anchorPointInPoints.y , 0.0f); - Mat4 localToWorld = transform; + Mat4 localToWorld = _modelViewTransform; localToWorld.translate(anchorPoint); + + //Decide billboard mode Vec3 camDir; switch (_mode) { - case Mode::VIEW_POINT_ORIENTED: - camDir = Vec3(localToWorld.m[12] - camWorldMat.m[12], localToWorld.m[13] - camWorldMat.m[13], localToWorld.m[14] - camWorldMat.m[14]); - break; - case Mode::VIEW_PLANE_ORIENTED: - camWorldMat.transformVector(Vec3(0.0f, 0.0f, -1.0f), &camDir); - break; - default: + case Mode::VIEW_POINT_ORIENTED: + camDir = Vec3(localToWorld.m[12] - camWorldMat.m[12], localToWorld.m[13] - camWorldMat.m[13], localToWorld.m[14] - camWorldMat.m[14]); + break; + case Mode::VIEW_PLANE_ORIENTED: + camWorldMat.transformVector(Vec3(0.0f, 0.0f, -1.0f), &camDir); + break; + default: CCASSERT(false, "invalid billboard mode"); - break; + break; } _modeDirty = false; + if (camDir.length() < MATH_TOLERANCE) { camDir.set(camWorldMat.m[8], camWorldMat.m[9], camWorldMat.m[10]); } camDir.normalize(); + Quaternion rotationQuaternion; this->getNodeToWorldTransform().getRotation(&rotationQuaternion); + // fetch the rotation angle of z float rotationZ = atan2(2*(rotationQuaternion.w*rotationQuaternion.z + rotationQuaternion.x*rotationQuaternion.y), - (1 - 2* (rotationQuaternion.y*rotationQuaternion.y + rotationQuaternion.z *rotationQuaternion.z))); + (1 - 2* (rotationQuaternion.y*rotationQuaternion.y + rotationQuaternion.z *rotationQuaternion.z))); Mat4 rotationMatrix; rotationMatrix.setIdentity(); rotationMatrix.rotateZ(rotationZ); + Vec3 upAxis = Vec3(rotationMatrix.m[4],rotationMatrix.m[5],rotationMatrix.m[6]); Vec3 x, y; camWorldMat.transformVector(upAxis, &y); @@ -139,23 +199,26 @@ void BillBoard::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) x.normalize(); Vec3::cross(x, camDir, &y); y.normalize(); - + float xlen = sqrtf(localToWorld.m[0] * localToWorld.m[0] + localToWorld.m[1] * localToWorld.m[1] + localToWorld.m[2] * localToWorld.m[2]); float ylen = sqrtf(localToWorld.m[4] * localToWorld.m[4] + localToWorld.m[5] * localToWorld.m[5] + localToWorld.m[6] * localToWorld.m[6]); float zlen = sqrtf(localToWorld.m[8] * localToWorld.m[8] + localToWorld.m[9] * localToWorld.m[9] + localToWorld.m[10] * localToWorld.m[10]); - + _billboardTransform.m[0] = x.x * xlen; _billboardTransform.m[1] = x.y * xlen; _billboardTransform.m[2] = x.z * xlen; _billboardTransform.m[4] = y.x * ylen; _billboardTransform.m[5] = y.y * ylen; _billboardTransform.m[6] = y.z * ylen; _billboardTransform.m[8] = -camDir.x * zlen; _billboardTransform.m[9] = -camDir.y * zlen; _billboardTransform.m[10] = -camDir.z * zlen; _billboardTransform.m[12] = localToWorld.m[12]; _billboardTransform.m[13] = localToWorld.m[13]; _billboardTransform.m[14] = localToWorld.m[14]; - + _billboardTransform.translate(-anchorPoint); - - const Mat4 &viewMat = camWorldMat.getInversed(); - _zDepthInView = -(viewMat.m[2] * _billboardTransform.m[12] + viewMat.m[6] * _billboardTransform.m[13] + viewMat.m[10] * _billboardTransform.m[14] + viewMat.m[14]); - _mvTransform = transform; + _camWorldMat = camWorldMat; } +} + +void BillBoard::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) +{ + const Mat4 &viewMat = _camWorldMat.getInversed(); + _zDepthInView = -(viewMat.m[2] * _billboardTransform.m[12] + viewMat.m[6] * _billboardTransform.m[13] + viewMat.m[10] * _billboardTransform.m[14] + viewMat.m[14]); //FIXME: frustum culling here { diff --git a/cocos/3d/CCBillBoard.h b/cocos/3d/CCBillBoard.h index e010cc8afe..fbedbb0aaa 100644 --- a/cocos/3d/CCBillBoard.h +++ b/cocos/3d/CCBillBoard.h @@ -88,6 +88,10 @@ public: Mode getMode() const; //override + + /** update billboard's transform and turn it towards camera */ + virtual void visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags); + /** draw BillBoard object */ virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override; @@ -101,8 +105,9 @@ CC_CONSTRUCTOR_ACCESS: protected: + void calculateBillbaordTransform(); + Mat4 _camWorldMat; - Mat4 _mvTransform; Mat4 _billboardTransform; float _zDepthInView; diff --git a/cocos/renderer/CCRenderer.cpp b/cocos/renderer/CCRenderer.cpp index 47327762f1..b5bc86dac6 100644 --- a/cocos/renderer/CCRenderer.cpp +++ b/cocos/renderer/CCRenderer.cpp @@ -131,32 +131,6 @@ void RenderQueue::clear() _queuePosZ.clear(); } -// helper -static bool compareTransparentRenderCommand(RenderCommand* a, RenderCommand* b) -{ - return a->getGlobalOrder() > b->getGlobalOrder(); -} - -void TransparentRenderQueue::push_back(RenderCommand* command) -{ - _queueCmd.push_back(command); -} - -void TransparentRenderQueue::sort() -{ - std::sort(std::begin(_queueCmd), std::end(_queueCmd), compareTransparentRenderCommand); -} - -RenderCommand* TransparentRenderQueue::operator[](ssize_t index) const -{ - return _queueCmd[index]; -} - -void TransparentRenderQueue::clear() -{ - _queueCmd.clear(); -} - // // // @@ -531,65 +505,6 @@ void Renderer::visitRenderQueue(const RenderQueue& queue) flush(); } -void Renderer::visitTransparentRenderQueue(const TransparentRenderQueue& queue) -{ - // do not batch for transparent objects - ssize_t size = queue.size(); - - _batchedCommands.clear(); - _filledVertex = 0; - _filledIndex = 0; - - for (ssize_t index = 0; index < size; ++index) - { - auto command = queue[index]; - auto commandType = command->getType(); - if( RenderCommand::Type::TRIANGLES_COMMAND == commandType) - { - auto cmd = static_cast(command); - _batchedCommands.push_back(cmd); - fillVerticesAndIndices(cmd); - drawBatchedTriangles(); - } - else if(RenderCommand::Type::QUAD_COMMAND == commandType) - { - auto cmd = static_cast(command); - _batchQuadCommands.push_back(cmd); - fillQuads(cmd); - drawBatchedQuads(); - } - else if(RenderCommand::Type::GROUP_COMMAND == commandType) - { - int renderQueueID = (static_cast(command))->getRenderQueueID(); - visitRenderQueue(_renderGroups[renderQueueID]); - } - else if(RenderCommand::Type::CUSTOM_COMMAND == commandType) - { - auto cmd = static_cast(command); - cmd->execute(); - } - else if(RenderCommand::Type::BATCH_COMMAND == commandType) - { - auto cmd = static_cast(command); - cmd->execute(); - } - else if(RenderCommand::Type::PRIMITIVE_COMMAND == commandType) - { - auto cmd = static_cast(command); - cmd->execute(); - } - else if (RenderCommand::Type::MESH_COMMAND == commandType) - { - auto cmd = static_cast(command); - cmd->execute(); - } - else - { - CCLOGERROR("Unknown commands in renderQueue"); - } - } -} - void Renderer::render() { //Uncomment this once everything is rendered by new renderer @@ -607,16 +522,6 @@ void Renderer::render() renderqueue.sort(); } visitRenderQueue(_renderGroups[0]); - - //Process render commands - //draw transparent objects here, do not batch for transparent objects - if (0 < _transparentRenderGroups.size()) - { - _transparentRenderGroups.sort(); - glEnable(GL_DEPTH_TEST); - visitTransparentRenderQueue(_transparentRenderGroups); - glDisable(GL_DEPTH_TEST); - } } clean(); _isRendering = false; @@ -643,8 +548,6 @@ void Renderer::clean() _numberQuads = 0; _lastMaterialID = 0; _lastBatchedMeshCommand = nullptr; - - _transparentRenderGroups.clear(); } void Renderer::clear() diff --git a/cocos/renderer/CCRenderer.h b/cocos/renderer/CCRenderer.h index e47ee90b58..f0db7ba502 100644 --- a/cocos/renderer/CCRenderer.h +++ b/cocos/renderer/CCRenderer.h @@ -65,22 +65,6 @@ protected: std::vector _queuePosZ; }; -//render queue for transparency object, NOTE that the _globalOrder of RenderCommand is the distance to the camera when added to the transparent queue -class TransparentRenderQueue { -public: - void push_back(RenderCommand* command); - ssize_t size() const - { - return _queueCmd.size(); - } - void sort(); - RenderCommand* operator[](ssize_t index) const; - void clear(); - -protected: - std::vector _queueCmd; -}; - struct RenderStackElement { int renderQueueID; @@ -172,8 +156,6 @@ protected: void processRenderCommand(RenderCommand* command); void visitRenderQueue(const RenderQueue& queue); - - void visitTransparentRenderQueue(const TransparentRenderQueue& queue); void fillVerticesAndIndices(const TrianglesCommand* cmd); void fillQuads(const QuadCommand* cmd); @@ -184,7 +166,6 @@ protected: std::stack _commandGroupStack; std::vector _renderGroups; - TransparentRenderQueue _transparentRenderGroups; //transparency objects uint32_t _lastMaterialID; diff --git a/tests/cpp-tests/Classes/BillBoardTest/BillBoardTest.cpp b/tests/cpp-tests/Classes/BillBoardTest/BillBoardTest.cpp index 293794ef66..a7462ba2c7 100644 --- a/tests/cpp-tests/Classes/BillBoardTest/BillBoardTest.cpp +++ b/tests/cpp-tests/Classes/BillBoardTest/BillBoardTest.cpp @@ -99,7 +99,6 @@ BillBoardTest::BillBoardTest() auto billboard = BillBoard::create(imgs[(unsigned int)(CCRANDOM_0_1() * 1 + 0.5)]); billboard->setScale(0.5f); billboard->setPosition3D(Vec3(0.0f, 0.0f, CCRANDOM_MINUS1_1() * 150.0f)); - billboard->setBlendFunc(cocos2d::BlendFunc::ALPHA_NON_PREMULTIPLIED); billboard->setOpacity(CCRANDOM_0_1() * 128 + 128); _billboards.push_back(billboard); layer->addChild(billboard); @@ -204,7 +203,6 @@ void BillBoardTest::addNewBillBoradWithCoords(Vec3 p) auto billborad = BillBoard::create(imgs[(unsigned int)(CCRANDOM_0_1() * 1 + 0.5)]); billborad->setScale(0.5f); billborad->setPosition3D(Vec3(p.x, p.y, -150.0f + 30 * i)); - billborad->setBlendFunc(cocos2d::BlendFunc::ALPHA_NON_PREMULTIPLIED); billborad->setOpacity(CCRANDOM_0_1() * 128 + 128); _layerBillBorad->addChild(billborad); @@ -233,7 +231,6 @@ void BillBoardTest::addNewAniBillBoradWithCoords(Vec3 p) auto action = Animate::create(animation); billboardAni->runAction(RepeatForever::create(action)); - billboardAni->setBlendFunc(cocos2d::BlendFunc::ALPHA_NON_PREMULTIPLIED); billboardAni->setOpacity(CCRANDOM_0_1() * 128 + 128); _billboards.push_back(billboardAni); }