Implement 3D drawing support for Sprite, Label, Particle, BatchNode

This commit is contained in:
Nite Luo 2015-01-12 20:06:50 -08:00
parent fee8bc1b28
commit 8591609128
14 changed files with 203 additions and 74 deletions

View File

@ -25,6 +25,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
****************************************************************************/ ****************************************************************************/
#include "2d/CCCamera.h"
#include "CCAtlasNode.h" #include "CCAtlasNode.h"
#include "renderer/CCTextureAtlas.h" #include "renderer/CCTextureAtlas.h"
#include "base/CCDirector.h" #include "base/CCDirector.h"
@ -132,14 +133,31 @@ void AtlasNode::updateAtlasValues()
// AtlasNode - draw // AtlasNode - draw
void AtlasNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) void AtlasNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{ {
_quadCommand.init( //Render as 3D object
_globalZOrder, if (flags & FLAGS_RENDER_AS_3D)
_textureAtlas->getTexture()->getName(), {
getGLProgramState(), float depth = Camera::getVisitingCamera()->getDepthInView(transform);
_blendFunc, _quadCommand.init(
_textureAtlas->getQuads(), depth,
_quadsToDraw, _textureAtlas->getTexture()->getName(),
transform); getGLProgramState(),
_blendFunc,
_textureAtlas->getQuads(),
_quadsToDraw,
transform);
_quadCommand.set3D(true);
}
else
{
_quadCommand.init(
_globalZOrder,
_textureAtlas->getTexture()->getName(),
getGLProgramState(),
_blendFunc,
_textureAtlas->getQuads(),
_quadsToDraw,
transform);
}
renderer->addCommand(&_quadCommand); renderer->addCommand(&_quadCommand);

View File

@ -285,6 +285,14 @@ bool Camera::isVisibleInFrustum(const AABB* aabb) const
return true; return true;
} }
float Camera::getDepthInView(const Mat4& transform) const
{
Mat4 camWorldMat = getNodeToWorldTransform();
const Mat4 &viewMat = camWorldMat.getInversed();
float depth = -(viewMat.m[2] * transform.m[12] + viewMat.m[6] * transform.m[13] + viewMat.m[10] * transform.m[14] + viewMat.m[14]);
return depth;
}
void Camera::onEnter() void Camera::onEnter()
{ {
if (_scene == nullptr) if (_scene == nullptr)

View File

@ -77,7 +77,7 @@ public:
* @param nearPlane The near plane distance. * @param nearPlane The near plane distance.
* @param farPlane The far plane distance. * @param farPlane The far plane distance.
*/ */
static Camera* createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane); static Camera* createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane);
/** /**
* Creates an orthographic camera. * Creates an orthographic camera.
* *
@ -87,7 +87,7 @@ public:
* @param nearPlane The near plane distance. * @param nearPlane The near plane distance.
* @param farPlane The far plane distance. * @param farPlane The far plane distance.
*/ */
static Camera* createOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane); static Camera* createOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane);
/** create default camera, the camera type depends on Director::getProjection */ /** create default camera, the camera type depends on Director::getProjection */
static Camera* create(); static Camera* create();
@ -144,7 +144,12 @@ public:
/** /**
* Is this aabb visible in frustum * Is this aabb visible in frustum
*/ */
bool isVisibleInFrustum(const AABB* aabb)const; bool isVisibleInFrustum(const AABB* aabb) const;
/**
* Get object depth towards camera
*/
float getDepthInView(const Mat4& transform) const;
//override //override
virtual void onEnter() override; virtual void onEnter() override;

View File

@ -23,6 +23,7 @@
THE SOFTWARE. THE SOFTWARE.
****************************************************************************/ ****************************************************************************/
#include "2d/CCCamera.h"
#include "2d/CCLabel.h" #include "2d/CCLabel.h"
#include "2d/CCFontAtlasCache.h" #include "2d/CCFontAtlasCache.h"
#include "2d/CCSprite.h" #include "2d/CCSprite.h"
@ -896,8 +897,18 @@ void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
_insideBounds = transformUpdated ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; _insideBounds = transformUpdated ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
if(_insideBounds) { if(_insideBounds) {
_customCommand.init(_globalZOrder); if (flags & FLAGS_RENDER_AS_3D)
_customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated); {
float depth = Camera::getVisitingCamera()->getDepthInView(transform);
_customCommand.init(depth);
_customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated);
}
else
{
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated);
}
renderer->addCommand(&_customCommand); renderer->addCommand(&_customCommand);
} }
} }

View File

@ -107,6 +107,7 @@ public:
enum { enum {
FLAGS_TRANSFORM_DIRTY = (1 << 0), FLAGS_TRANSFORM_DIRTY = (1 << 0),
FLAGS_CONTENT_SIZE_DIRTY = (1 << 1), FLAGS_CONTENT_SIZE_DIRTY = (1 << 1),
FLAGS_RENDER_AS_3D = (1 << 3),
FLAGS_DIRTY_MASK = (FLAGS_TRANSFORM_DIRTY | FLAGS_CONTENT_SIZE_DIRTY), FLAGS_DIRTY_MASK = (FLAGS_TRANSFORM_DIRTY | FLAGS_CONTENT_SIZE_DIRTY),
}; };

View File

@ -29,7 +29,7 @@
*/ */
#include "2d/CCParticleBatchNode.h" #include "2d/CCParticleBatchNode.h"
#include "2d/CCCamera.h"
#include "2d/CCGrid.h" #include "2d/CCGrid.h"
#include "2d/CCParticleSystem.h" #include "2d/CCParticleSystem.h"
#include "renderer/CCTextureCache.h" #include "renderer/CCTextureCache.h"
@ -403,12 +403,25 @@ void ParticleBatchNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t
return; return;
} }
_batchCommand.init( if (flags & FLAGS_RENDER_AS_3D)
{
float depth = Camera::getVisitingCamera()->getDepthInView(transform);
_batchCommand.init(
depth,
getGLProgram(),
_blendFunc,
_textureAtlas,
_modelViewTransform);
}
else
{
_batchCommand.init(
_globalZOrder, _globalZOrder,
getGLProgram(), getGLProgram(),
_blendFunc, _blendFunc,
_textureAtlas, _textureAtlas,
_modelViewTransform); _modelViewTransform);
}
renderer->addCommand(&_batchCommand); renderer->addCommand(&_batchCommand);
CC_PROFILER_STOP("CCParticleBatchNode - draw"); CC_PROFILER_STOP("CCParticleBatchNode - draw");
} }

View File

@ -31,6 +31,7 @@ THE SOFTWARE.
#include <algorithm> #include <algorithm>
#include "2d/CCCamera.h"
#include "2d/CCSpriteFrame.h" #include "2d/CCSpriteFrame.h"
#include "2d/CCParticleBatchNode.h" #include "2d/CCParticleBatchNode.h"
#include "renderer/CCTextureAtlas.h" #include "renderer/CCTextureAtlas.h"
@ -372,8 +373,17 @@ void ParticleSystemQuad::draw(Renderer *renderer, const Mat4 &transform, uint32_
//quad command //quad command
if(_particleIdx > 0) if(_particleIdx > 0)
{ {
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _quads, _particleIdx, transform); if (flags & FLAGS_RENDER_AS_3D)
renderer->addCommand(&_quadCommand); {
float depth = Camera::getVisitingCamera()->getDepthInView(transform);
_quadCommand.init(depth, _texture->getName(), getGLProgramState(), _blendFunc, _quads, _particleIdx, transform);
renderer->addCommand(&_quadCommand);
}
else
{
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _quads, _particleIdx, transform);
renderer->addCommand(&_quadCommand);
}
} }
} }

View File

@ -29,6 +29,7 @@ THE SOFTWARE.
#include <algorithm> #include <algorithm>
#include "2d/CCCamera.h"
#include "2d/CCSpriteBatchNode.h" #include "2d/CCSpriteBatchNode.h"
#include "2d/CCAnimationCache.h" #include "2d/CCAnimationCache.h"
#include "2d/CCSpriteFrame.h" #include "2d/CCSpriteFrame.h"
@ -592,8 +593,19 @@ void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
if(_insideBounds) if(_insideBounds)
{ {
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform); //Render as 3D object
if (flags & FLAGS_RENDER_AS_3D)
{
float depth = Camera::getVisitingCamera()->getDepthInView(transform);
_quadCommand.init(depth, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform);
_quadCommand.set3D(true);
}
else
{
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform);
}
renderer->addCommand(&_quadCommand); renderer->addCommand(&_quadCommand);
#if CC_SPRITE_DEBUG_DRAW #if CC_SPRITE_DEBUG_DRAW
_debugDrawNode->clear(); _debugDrawNode->clear();
Vec2 vertices[4] = { Vec2 vertices[4] = {

View File

@ -26,6 +26,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
****************************************************************************/ ****************************************************************************/
#include "2d/CCCamera.h"
#include "2d/CCSpriteBatchNode.h" #include "2d/CCSpriteBatchNode.h"
#include "2d/CCSprite.h" #include "2d/CCSprite.h"
#include "base/CCDirector.h" #include "base/CCDirector.h"
@ -369,12 +370,26 @@ void SpriteBatchNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t f
for(const auto &child: _children) for(const auto &child: _children)
child->updateTransform(); child->updateTransform();
_batchCommand.init( //Render as 3D object
if (flags & FLAGS_RENDER_AS_3D)
{
float depth = Camera::getVisitingCamera()->getDepthInView(transform);
_batchCommand.init(
depth,
getGLProgram(),
_blendFunc,
_textureAtlas,
transform);
}
else
{
_batchCommand.init(
_globalZOrder, _globalZOrder,
getGLProgram(), getGLProgram(),
_blendFunc, _blendFunc,
_textureAtlas, _textureAtlas,
transform); transform);
}
renderer->addCommand(&_batchCommand); renderer->addCommand(&_batchCommand);
} }

View File

@ -106,8 +106,15 @@ void BillBoard::visit(Renderer *renderer, const Mat4& parentTransform, uint32_t
uint32_t flags = processParentFlags(parentTransform, parentFlags); uint32_t flags = processParentFlags(parentTransform, parentFlags);
//Add 3D flag so all the children will be rendered as 3D object
flags |= FLAGS_RENDER_AS_3D;
//Update Billboard transform //Update Billboard transform
calculateBillbaordTransform(); bool dirty = calculateBillbaordTransform();
if(dirty)
{
flags |= FLAGS_TRANSFORM_DIRTY;
}
Director* director = Director::getInstance(); Director* director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
@ -126,33 +133,32 @@ void BillBoard::visit(Renderer *renderer, const Mat4& parentTransform, uint32_t
auto node = _children.at(i); auto node = _children.at(i);
if (node && node->getLocalZOrder() < 0) if (node && node->getLocalZOrder() < 0)
node->visit(renderer, _billboardTransform, flags); node->visit(renderer, _modelViewTransform, flags);
else else
break; break;
} }
// self draw // self draw
if (visibleByCamera) if (visibleByCamera)
this->draw(renderer, _billboardTransform, flags); this->draw(renderer, _modelViewTransform, flags);
for(auto it=_children.cbegin()+i; it != _children.cend(); ++it) for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _billboardTransform, flags); (*it)->visit(renderer, _modelViewTransform, flags);
} }
else if (visibleByCamera) else if (visibleByCamera)
{ {
this->draw(renderer, _billboardTransform, flags); this->draw(renderer, _modelViewTransform, flags);
} }
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
} }
void BillBoard::calculateBillbaordTransform() bool BillBoard::calculateBillbaordTransform()
{ {
//Get camera world position //Get camera world position
auto camera = Camera::getVisitingCamera(); auto camera = Camera::getVisitingCamera();
const Mat4& camWorldMat = camera->getNodeToWorldTransform(); const Mat4& camWorldMat = camera->getNodeToWorldTransform();
//TODO: use math lib to calculate math lib //TODO: use math lib to calculate math lib Make it easier to read and maintain
//Make it easier to read
if (memcmp(_camWorldMat.m, camWorldMat.m, sizeof(float) * 16) != 0 || _transformDirty || _modeDirty) if (memcmp(_camWorldMat.m, camWorldMat.m, sizeof(float) * 16) != 0 || _transformDirty || _modeDirty)
{ {
//Rotate based on anchor point //Rotate based on anchor point
@ -204,30 +210,35 @@ void BillBoard::calculateBillbaordTransform()
float ylen = sqrtf(localToWorld.m[4] * localToWorld.m[4] + localToWorld.m[5] * localToWorld.m[5] + localToWorld.m[6] * localToWorld.m[6]); 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]); 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; Mat4 billboardTransform;
_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); 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);
_modelViewTransform = billboardTransform;
_camWorldMat = camWorldMat; _camWorldMat = camWorldMat;
return true;
} }
return false;
} }
void BillBoard::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) void BillBoard::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{ {
const Mat4 &viewMat = _camWorldMat.getInversed(); //Get depth
_zDepthInView = -(viewMat.m[2] * _billboardTransform.m[12] + viewMat.m[6] * _billboardTransform.m[13] + viewMat.m[10] * _billboardTransform.m[14] + viewMat.m[14]); _zDepthInView = Camera::getVisitingCamera()->getDepthInView(transform);
//FIXME: frustum culling here //FIXME: frustum culling here
{ _quadCommand.init(_zDepthInView, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, _modelViewTransform);
_quadCommand.init(_zDepthInView, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, _billboardTransform); _quadCommand.setTransparent(true);
_quadCommand.setTransparent(true); _quadCommand.setSkipBatching(true);
_quadCommand.setSkipBatching(true); _quadCommand.set3D(true);
_quadCommand.set3D(true); renderer->addCommand(&_quadCommand);
renderer->addCommand(&_quadCommand);
}
} }
void BillBoard::setMode( Mode mode ) void BillBoard::setMode( Mode mode )

View File

@ -105,10 +105,9 @@ CC_CONSTRUCTOR_ACCESS:
protected: protected:
void calculateBillbaordTransform(); bool calculateBillbaordTransform();
Mat4 _camWorldMat; Mat4 _camWorldMat;
Mat4 _billboardTransform;
float _zDepthInView; float _zDepthInView;

View File

@ -599,6 +599,54 @@ static Texture2D * getDummyTexture()
} }
#endif #endif
void Sprite3D::visit(cocos2d::Renderer *renderer, const cocos2d::Mat4 &parentTransform, uint32_t parentFlags)
{
// quick return if not visible. children won't be drawn.
if (!_visible)
{
return;
}
uint32_t flags = processParentFlags(parentTransform, parentFlags);
flags &= FLAGS_RENDER_AS_3D;
//
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, _modelViewTransform, flags);
else
break;
}
// self draw
if (visibleByCamera)
this->draw(renderer, _modelViewTransform, flags);
for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, flags);
}
else if (visibleByCamera)
{
this->draw(renderer, _modelViewTransform, flags);
}
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
void Sprite3D::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) void Sprite3D::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{ {
// camera clipping // camera clipping

View File

@ -148,6 +148,12 @@ CC_CONSTRUCTOR_ACCESS:
/** load file and set it to meshedatas, nodedatas and materialdatas, obj file .mtl file should be at the same directory if exist */ /** load file and set it to meshedatas, nodedatas and materialdatas, obj file .mtl file should be at the same directory if exist */
bool loadFromFile(const std::string& path, NodeDatas* nodedatas, MeshDatas* meshdatas, MaterialDatas* materialdatas); bool loadFromFile(const std::string& path, NodeDatas* nodedatas, MeshDatas* meshdatas, MaterialDatas* materialdatas);
/**
* Visits this Sprite3D's children and draw them recursively.
* Note: all its children will rendered as 3D objects
*/
virtual void visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags);
/**draw*/ /**draw*/
virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override; virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;

View File

@ -123,26 +123,6 @@ CameraRotationTest::CameraRotationTest()
_camNode->setPositionZ(Camera::getDefaultCamera()->getPosition3D().z); _camNode->setPositionZ(Camera::getDefaultCamera()->getPosition3D().z);
_camControlNode->addChild(_camNode); _camControlNode->addChild(_camNode);
//Sprites
// auto sp1 = Sprite::create("Images/grossini.png");
// addChild(sp1);
// sp1->setPosition(s.width/2, s.height/2);
// auto sp2 = Sprite::create("Images/grossini.png");
// sp1->addChild(sp2);
//
// //Yellow is at the back
// auto sp4 = Sprite::create("Images/grossinis_sister1.png");
// sp4->setColor(Color3B::YELLOW);
// sp4->setPosition(10, -10);
// sp4->setGlobalZOrder(-2);
// sp1->addChild(sp4);
//
// auto sp3 = Sprite::create("Images/grossinis_sister2.png");
// sp3->setPosition(-10, -5);
// sp3->setGlobalZOrder(2);
// sp1->addChild(sp3);
//Billboards //Billboards
//Yellow is at the back //Yellow is at the back
@ -153,25 +133,19 @@ CameraRotationTest::CameraRotationTest()
addChild(bill1); addChild(bill1);
l1 = Label::create(); l1 = Label::create();
l1->setName("depth");
l1->setPosition(Vec2(0,-10)); l1->setPosition(Vec2(0,-10));
l1->setString("Depth"); l1->setString("Billboard1");
l1->setColor(Color3B::WHITE); l1->setColor(Color3B::WHITE);
l1->setScale(3); l1->setScale(3);
bill1->addChild(l1); bill1->addChild(l1);
// auto sp3Child = Sprite::create("Images/grossinis_sister2.png");
// sp3Child->setPosition(10, 10);
// bill1->addChild(sp3Child);
bill2 = BillBoard::create("Images/Icon.png"); bill2 = BillBoard::create("Images/Icon.png");
bill2->setPosition3D(Vec3(s.width/2 - 50, s.height/2 - 10, 10)); bill2->setPosition3D(Vec3(s.width/2 - 50, s.height/2 - 10, 10));
bill2->setScale(0.6); bill2->setScale(0.6);
addChild(bill2); addChild(bill2);
l2 = Label::create(); l2 = Label::create();
l2->setName("depth"); l2->setString("Billboard2");
l2->setString("Depth");
l2->setPosition(Vec2(0,-10)); l2->setPosition(Vec2(0,-10));
l2->setColor(Color3B::WHITE); l2->setColor(Color3B::WHITE);
l2->setScale(3); l2->setScale(3);
@ -230,8 +204,6 @@ void CameraRotationTest::onExit()
void CameraRotationTest::update(float dt) void CameraRotationTest::update(float dt)
{ {
l1->setString(std::to_string(bill1->getZDepth()));
l2->setString(std::to_string(bill2->getZDepth()));
} }
//------------------------------------------------------------------ //------------------------------------------------------------------