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.
****************************************************************************/
#include "2d/CCCamera.h"
#include "CCAtlasNode.h"
#include "renderer/CCTextureAtlas.h"
#include "base/CCDirector.h"
@ -132,15 +133,32 @@ void AtlasNode::updateAtlasValues()
// AtlasNode - draw
void AtlasNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
_quadCommand.init(
_globalZOrder,
_textureAtlas->getTexture()->getName(),
getGLProgramState(),
_blendFunc,
_textureAtlas->getQuads(),
_quadsToDraw,
transform);
//Render as 3D object
if (flags & FLAGS_RENDER_AS_3D)
{
float depth = Camera::getVisitingCamera()->getDepthInView(transform);
_quadCommand.init(
depth,
_textureAtlas->getTexture()->getName(),
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);
}

View File

@ -285,6 +285,14 @@ bool Camera::isVisibleInFrustum(const AABB* aabb) const
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()
{
if (_scene == nullptr)

View File

@ -77,7 +77,7 @@ public:
* @param nearPlane The near 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.
*
@ -87,7 +87,7 @@ public:
* @param nearPlane The near 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 */
static Camera* create();
@ -144,7 +144,12 @@ public:
/**
* 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
virtual void onEnter() override;

View File

@ -23,6 +23,7 @@
THE SOFTWARE.
****************************************************************************/
#include "2d/CCCamera.h"
#include "2d/CCLabel.h"
#include "2d/CCFontAtlasCache.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;
if(_insideBounds) {
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated);
if (flags & FLAGS_RENDER_AS_3D)
{
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);
}
}

View File

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

View File

@ -29,7 +29,7 @@
*/
#include "2d/CCParticleBatchNode.h"
#include "2d/CCCamera.h"
#include "2d/CCGrid.h"
#include "2d/CCParticleSystem.h"
#include "renderer/CCTextureCache.h"
@ -403,12 +403,25 @@ void ParticleBatchNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t
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,
getGLProgram(),
_blendFunc,
_textureAtlas,
_modelViewTransform);
}
renderer->addCommand(&_batchCommand);
CC_PROFILER_STOP("CCParticleBatchNode - draw");
}

View File

@ -31,6 +31,7 @@ THE SOFTWARE.
#include <algorithm>
#include "2d/CCCamera.h"
#include "2d/CCSpriteFrame.h"
#include "2d/CCParticleBatchNode.h"
#include "renderer/CCTextureAtlas.h"
@ -372,8 +373,17 @@ void ParticleSystemQuad::draw(Renderer *renderer, const Mat4 &transform, uint32_
//quad command
if(_particleIdx > 0)
{
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _quads, _particleIdx, transform);
renderer->addCommand(&_quadCommand);
if (flags & FLAGS_RENDER_AS_3D)
{
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 "2d/CCCamera.h"
#include "2d/CCSpriteBatchNode.h"
#include "2d/CCAnimationCache.h"
#include "2d/CCSpriteFrame.h"
@ -592,8 +593,19 @@ void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
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);
#if CC_SPRITE_DEBUG_DRAW
_debugDrawNode->clear();
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.
****************************************************************************/
#include "2d/CCCamera.h"
#include "2d/CCSpriteBatchNode.h"
#include "2d/CCSprite.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)
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,
getGLProgram(),
_blendFunc,
_textureAtlas,
transform);
}
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);
//Add 3D flag so all the children will be rendered as 3D object
flags |= FLAGS_RENDER_AS_3D;
//Update Billboard transform
calculateBillbaordTransform();
bool dirty = calculateBillbaordTransform();
if(dirty)
{
flags |= FLAGS_TRANSFORM_DIRTY;
}
Director* director = Director::getInstance();
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);
if (node && node->getLocalZOrder() < 0)
node->visit(renderer, _billboardTransform, flags);
node->visit(renderer, _modelViewTransform, flags);
else
break;
}
// self draw
if (visibleByCamera)
this->draw(renderer, _billboardTransform, flags);
this->draw(renderer, _modelViewTransform, flags);
for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _billboardTransform, flags);
(*it)->visit(renderer, _modelViewTransform, flags);
}
else if (visibleByCamera)
{
this->draw(renderer, _billboardTransform, flags);
this->draw(renderer, _modelViewTransform, flags);
}
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
void BillBoard::calculateBillbaordTransform()
bool BillBoard::calculateBillbaordTransform()
{
//Get camera world position
auto camera = Camera::getVisitingCamera();
const Mat4& camWorldMat = camera->getNodeToWorldTransform();
//TODO: use math lib to calculate math lib
//Make it easier to read
//TODO: use math lib to calculate math lib Make it easier to read and maintain
if (memcmp(_camWorldMat.m, camWorldMat.m, sizeof(float) * 16) != 0 || _transformDirty || _modeDirty)
{
//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 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];
Mat4 billboardTransform;
_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;
return true;
}
return false;
}
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]);
//Get depth
_zDepthInView = Camera::getVisitingCamera()->getDepthInView(transform);
//FIXME: frustum culling here
{
_quadCommand.init(_zDepthInView, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, _billboardTransform);
_quadCommand.setTransparent(true);
_quadCommand.setSkipBatching(true);
_quadCommand.set3D(true);
renderer->addCommand(&_quadCommand);
}
_quadCommand.init(_zDepthInView, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, _modelViewTransform);
_quadCommand.setTransparent(true);
_quadCommand.setSkipBatching(true);
_quadCommand.set3D(true);
renderer->addCommand(&_quadCommand);
}
void BillBoard::setMode( Mode mode )

View File

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

View File

@ -599,6 +599,54 @@ static Texture2D * getDummyTexture()
}
#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)
{
// 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 */
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*/
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);
_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
//Yellow is at the back
@ -153,25 +133,19 @@ CameraRotationTest::CameraRotationTest()
addChild(bill1);
l1 = Label::create();
l1->setName("depth");
l1->setPosition(Vec2(0,-10));
l1->setString("Depth");
l1->setString("Billboard1");
l1->setColor(Color3B::WHITE);
l1->setScale(3);
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->setPosition3D(Vec3(s.width/2 - 50, s.height/2 - 10, 10));
bill2->setScale(0.6);
addChild(bill2);
l2 = Label::create();
l2->setName("depth");
l2->setString("Depth");
l2->setString("Billboard2");
l2->setPosition(Vec2(0,-10));
l2->setColor(Color3B::WHITE);
l2->setScale(3);
@ -230,8 +204,6 @@ void CameraRotationTest::onExit()
void CameraRotationTest::update(float dt)
{
l1->setString(std::to_string(bill1->getZDepth()));
l2->setString(std::to_string(bill2->getZDepth()));
}
//------------------------------------------------------------------