Merge pull request #11159 from super626/v3

node animation support
This commit is contained in:
minggo 2015-03-30 09:32:36 +08:00
commit 30db8ab7fa
12 changed files with 13884 additions and 36 deletions

View File

@ -29,9 +29,9 @@
NS_CC_BEGIN NS_CC_BEGIN
std::unordered_map<Sprite3D*, Animate3D*> Animate3D::s_fadeInAnimates; std::unordered_map<Node*, Animate3D*> Animate3D::s_fadeInAnimates;
std::unordered_map<Sprite3D*, Animate3D*> Animate3D::s_fadeOutAnimates; std::unordered_map<Node*, Animate3D*> Animate3D::s_fadeOutAnimates;
std::unordered_map<Sprite3D*, Animate3D*> Animate3D::s_runningAnimates; std::unordered_map<Node*, Animate3D*> Animate3D::s_runningAnimates;
float Animate3D::_transTime = 0.1f; float Animate3D::_transTime = 0.1f;
//create Animate3D using Animation. //create Animate3D using Animation.
@ -120,26 +120,98 @@ Animate3D* Animate3D::reverse() const
return animate; return animate;
} }
Node* findChildByNameRecursively(Node* node, const std::string &childName)
{
const std::string& name = node->getName();
if (name == childName)
return node;
const Vector<Node*>& children = node->getChildren();
for (const auto& child : children)
{
Node* findNode = findChildByNameRecursively(child, childName);
if (findNode)
return findNode;
}
return nullptr;
}
//! called before the action start. It will also set the target. //! called before the action start. It will also set the target.
void Animate3D::startWithTarget(Node *target) void Animate3D::startWithTarget(Node *target)
{ {
Sprite3D* sprite = dynamic_cast<Sprite3D*>(target);
CCASSERT(sprite && sprite->getSkeleton() && _animation, "Animate3D apply to Sprite3D only");
ActionInterval::startWithTarget(target); ActionInterval::startWithTarget(target);
_boneCurves.clear(); _boneCurves.clear();
auto skin = sprite->getSkeleton(); _nodeCurves.clear();
bool hasCurve = false; bool hasCurve = false;
for (int i = 0; i < skin->getBoneCount(); i++) { Sprite3D* sprite = dynamic_cast<Sprite3D*>(target);
auto bone = skin->getBoneByIndex(static_cast<unsigned int>(i));
auto curve = _animation->getBoneCurveByName(bone->getName()); if(sprite)
if (curve)
{ {
if (_animation)
{
const std::unordered_map<std::string, Animation3D::Curve*>& boneCurves = _animation->getBoneCurves();
for (const auto& iter: boneCurves)
{
const std::string& boneName = iter.first;
auto skin = sprite->getSkeleton();
if(skin)
{
auto bone = skin->getBoneByName(boneName);
if (bone)
{
auto curve = _animation->getBoneCurveByName(boneName);
_boneCurves[bone] = curve; _boneCurves[bone] = curve;
hasCurve = true; hasCurve = true;
} }
else
{
Node* node = nullptr;
if (target->getName() == boneName)
node = target;
else
node = findChildByNameRecursively(target, boneName);
if (node)
{
auto curve = _animation->getBoneCurveByName(boneName);
if (curve)
{
_nodeCurves[node] = curve;
hasCurve = true;
} }
}
}
}
}
}
}
else
{
const std::unordered_map<std::string, Animation3D::Curve*>& boneCurves = _animation->getBoneCurves();
for (const auto& iter: boneCurves)
{
const std::string& boneName = iter.first;
Node* node = nullptr;
if (target->getName() == boneName)
node = target;
else
node = findChildByNameRecursively(target, boneName);
if (node)
{
auto curve = _animation->getBoneCurveByName(boneName);
if (curve)
{
_nodeCurves[node] = curve;
hasCurve = true;
}
}
}
}
if (!hasCurve) if (!hasCurve)
{ {
CCLOG("warning: no animation finde for the skeleton"); CCLOG("warning: no animation finde for the skeleton");
@ -238,6 +310,8 @@ void Animate3D::update(float t)
t = 1 - t; t = 1 - t;
t = _start + t * _last; t = _start + t * _last;
for (const auto& it : _boneCurves)
{
for (const auto& it : _boneCurves) { for (const auto& it : _boneCurves) {
auto bone = it.first; auto bone = it.first;
auto curve = it.second; auto curve = it.second;
@ -259,6 +333,31 @@ void Animate3D::update(float t)
bone->setAnimationValue(trans, rot, scale, this, _weight); bone->setAnimationValue(trans, rot, scale, this, _weight);
} }
} }
for (const auto& it : _nodeCurves)
{
auto node = it.first;
auto curve = it.second;
Mat4 transform;
if (curve->translateCurve)
{
curve->translateCurve->evaluate(t, transDst, EvaluateType::INT_LINEAR);
transform.translate(transDst[0], transDst[1], transDst[2]);
}
if (curve->rotCurve)
{
curve->rotCurve->evaluate(t, rotDst, EvaluateType::INT_QUAT_SLERP);
Quaternion qua(rotDst[0], rotDst[1], rotDst[2], rotDst[3]);
transform.rotate(qua);
}
if (curve->scaleCurve)
{
curve->scaleCurve->evaluate(t, scaleDst, EvaluateType::INT_LINEAR);
transform.scale(scaleDst[0], scaleDst[1], scaleDst[2]);
}
node->setAdditionalTransform(&transform);
}
}
} }
} }

View File

@ -138,11 +138,12 @@ protected:
float _lastTime; // last t (0 - 1) float _lastTime; // last t (0 - 1)
float _originInterval;// save origin interval time float _originInterval;// save origin interval time
std::unordered_map<Bone3D*, Animation3D::Curve*> _boneCurves; //weak ref std::unordered_map<Bone3D*, Animation3D::Curve*> _boneCurves; //weak ref
std::unordered_map<Node*, Animation3D::Curve*> _nodeCurves;
//sprite animates //sprite animates
static std::unordered_map<Sprite3D*, Animate3D*> s_fadeInAnimates; static std::unordered_map<Node*, Animate3D*> s_fadeInAnimates;
static std::unordered_map<Sprite3D*, Animate3D*> s_fadeOutAnimates; static std::unordered_map<Node*, Animate3D*> s_fadeOutAnimates;
static std::unordered_map<Sprite3D*, Animate3D*> s_runningAnimates; static std::unordered_map<Node*, Animate3D*> s_runningAnimates;
}; };
// end of actions group // end of actions group

View File

@ -73,6 +73,8 @@ public:
/**get bone curve*/ /**get bone curve*/
Curve* getBoneCurveByName(const std::string& name) const; Curve* getBoneCurveByName(const std::string& name) const;
const std::unordered_map<std::string, Curve*>& getBoneCurves() const {return _boneCurves;}
CC_CONSTRUCTOR_ACCESS: CC_CONSTRUCTOR_ACCESS:
Animation3D(); Animation3D();
virtual ~Animation3D(); virtual ~Animation3D();

View File

@ -1616,7 +1616,7 @@ bool Bundle3D::loadNodesJson(NodeDatas& nodedatas)
{ {
const rapidjson::Value& jnode = nodes[i]; const rapidjson::Value& jnode = nodes[i];
std::string id = jnode[ID].GetString(); std::string id = jnode[ID].GetString();
NodeData* nodedata = parseNodesRecursivelyJson(jnode); NodeData* nodedata = parseNodesRecursivelyJson(jnode, nodes.Size() == 1);
bool isSkeleton = jnode[SKELETON].GetBool(); bool isSkeleton = jnode[SKELETON].GetBool();
if (isSkeleton) if (isSkeleton)
@ -1626,22 +1626,24 @@ bool Bundle3D::loadNodesJson(NodeDatas& nodedatas)
} }
return true; return true;
} }
NodeData* Bundle3D::parseNodesRecursivelyJson(const rapidjson::Value& jvalue) NodeData* Bundle3D::parseNodesRecursivelyJson(const rapidjson::Value& jvalue, bool singleSprite)
{ {
NodeData* nodedata = new (std::nothrow) NodeData();; NodeData* nodedata = new (std::nothrow) NodeData();;
// id // id
nodedata->id = jvalue[ID].GetString(); nodedata->id = jvalue[ID].GetString();
// transform // transform
Mat4 tranform; Mat4 transform;
const rapidjson::Value& jtransform = jvalue[TRANSFORM]; const rapidjson::Value& jtransform = jvalue[TRANSFORM];
for (rapidjson::SizeType j = 0; j < jtransform.Size(); j++) for (rapidjson::SizeType j = 0; j < jtransform.Size(); j++)
{ {
tranform.m[j] = jtransform[j].GetDouble(); transform.m[j] = jtransform[j].GetDouble();
} }
nodedata->transform = tranform; nodedata->transform = transform;
bool isSkin = false;
// parts // parts
if (jvalue.HasMember(PARTS)) if (jvalue.HasMember(PARTS))
@ -1690,11 +1692,31 @@ NodeData* Bundle3D::parseNodesRecursivelyJson(const rapidjson::Value& jvalue)
//invbindpos.inverse(); //invbindpos.inverse();
modelnodedata->invBindPose.push_back(invbindpos); modelnodedata->invBindPose.push_back(invbindpos);
} }
if (bones.Size() > 0)
isSkin = true;
} }
nodedata->modelNodeDatas.push_back(modelnodedata); nodedata->modelNodeDatas.push_back(modelnodedata);
} }
} }
// set transform
if(_version == "0.1" || _version == "0.2" || _version == "0.3" || _version == "0.4" || _version == "0.5" || _version == "0.6")
{
if(isSkin || singleSprite)
{
nodedata->transform = Mat4::IDENTITY;
}
else
{
nodedata->transform = transform;
}
}
else
{
nodedata->transform = transform;
}
if (jvalue.HasMember(CHILDREN)) if (jvalue.HasMember(CHILDREN))
{ {
const rapidjson::Value& children = jvalue[CHILDREN]; const rapidjson::Value& children = jvalue[CHILDREN];
@ -1702,7 +1724,7 @@ NodeData* Bundle3D::parseNodesRecursivelyJson(const rapidjson::Value& jvalue)
{ {
const rapidjson::Value& child = children[i]; const rapidjson::Value& child = children[i];
NodeData* tempdata = parseNodesRecursivelyJson(child); NodeData* tempdata = parseNodesRecursivelyJson(child, singleSprite);
nodedata->children.push_back(tempdata); nodedata->children.push_back(tempdata);
} }
} }
@ -1725,7 +1747,7 @@ bool Bundle3D::loadNodesBinary(NodeDatas& nodedatas)
for (rapidjson::SizeType i = 0; i < nodeSize; i++) for (rapidjson::SizeType i = 0; i < nodeSize; i++)
{ {
bool skeleton = false; bool skeleton = false;
NodeData* nodedata = parseNodesRecursivelyBinary(skeleton); NodeData* nodedata = parseNodesRecursivelyBinary(skeleton, nodeSize == 1);
if (skeleton) if (skeleton)
nodedatas.skeleton.push_back(nodedata); nodedatas.skeleton.push_back(nodedata);
@ -1734,7 +1756,7 @@ bool Bundle3D::loadNodesBinary(NodeDatas& nodedatas)
} }
return true; return true;
} }
NodeData* Bundle3D::parseNodesRecursivelyBinary(bool& skeleton) NodeData* Bundle3D::parseNodesRecursivelyBinary(bool& skeleton, bool singleSprite)
{ {
// id // id
std::string id = _binaryReader.readString(); std::string id = _binaryReader.readString();
@ -1765,7 +1787,9 @@ NodeData* Bundle3D::parseNodesRecursivelyBinary(bool& skeleton)
NodeData* nodedata = new (std::nothrow) NodeData(); NodeData* nodedata = new (std::nothrow) NodeData();
nodedata->id = id; nodedata->id = id;
nodedata->transform = transform;
bool isSkin = false;
if (partsSize > 0) if (partsSize > 0)
{ {
for (unsigned int i = 0; i < partsSize; i++) for (unsigned int i = 0; i < partsSize; i++)
@ -1804,6 +1828,7 @@ NodeData* Bundle3D::parseNodesRecursivelyBinary(bool& skeleton)
modelnodedata->invBindPose.push_back(invbindpos); modelnodedata->invBindPose.push_back(invbindpos);
} }
isSkin = true;
} }
unsigned int uvMapping = 0; unsigned int uvMapping = 0;
if (_binaryReader.read(&uvMapping, 4, 1) != 1) if (_binaryReader.read(&uvMapping, 4, 1) != 1)
@ -1832,6 +1857,23 @@ NodeData* Bundle3D::parseNodesRecursivelyBinary(bool& skeleton)
} }
} }
// set transform
if(_version == "0.1" || _version == "0.2" || _version == "0.3" || _version == "0.4" || _version == "0.5" || _version == "0.6")
{
if(isSkin || singleSprite)
{
nodedata->transform = Mat4::IDENTITY;
}
else
{
nodedata->transform = transform;
}
}
else
{
nodedata->transform = transform;
}
unsigned int childrenSize = 0; unsigned int childrenSize = 0;
if (_binaryReader.read(&childrenSize, 4, 1) != 1) if (_binaryReader.read(&childrenSize, 4, 1) != 1)
{ {
@ -1842,7 +1884,7 @@ NodeData* Bundle3D::parseNodesRecursivelyBinary(bool& skeleton)
{ {
for (unsigned int i = 0; i < childrenSize; i++) for (unsigned int i = 0; i < childrenSize; i++)
{ {
NodeData* tempdata = parseNodesRecursivelyBinary(skeleton); NodeData* tempdata = parseNodesRecursivelyBinary(skeleton, singleSprite);
nodedata->children.push_back(tempdata); nodedata->children.push_back(tempdata);
} }
} }

View File

@ -121,13 +121,13 @@ protected:
* load nodes of json * load nodes of json
*/ */
bool loadNodesJson(NodeDatas& nodedatas); bool loadNodesJson(NodeDatas& nodedatas);
NodeData* parseNodesRecursivelyJson(const rapidjson::Value& jvalue); NodeData* parseNodesRecursivelyJson(const rapidjson::Value& jvalue, bool singleSprite);
/** /**
* load nodes of binary * load nodes of binary
*/ */
bool loadNodesBinary(NodeDatas& nodedatas); bool loadNodesBinary(NodeDatas& nodedatas);
NodeData* parseNodesRecursivelyBinary(bool& skeleton); NodeData* parseNodesRecursivelyBinary(bool& skeleton, bool singleSprite);
/** /**
* get define data type * get define data type

View File

@ -613,6 +613,8 @@ std::string ObjLoader::LoadObj(shapes_t& shapes, const char* filename, const cha
// use mtl // use mtl
if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6])))
{ {
exportFaceGroupToShape(vertexCache, shapes, v, vn, vt, faceGroup, material, name);
faceGroup.clear();
char namebuf[4096]; char namebuf[4096];
token += 7; token += 7;

View File

@ -478,6 +478,7 @@ void Sprite3D::createNode(NodeData* nodedata, Node* root, const MaterialDatas& m
{ {
if(it->bones.size() > 0 || singleSprite) if(it->bones.size() > 0 || singleSprite)
{ {
this->setName(nodedata->id);
auto mesh = Mesh::create(nodedata->id, getMeshIndexData(it->subMeshId)); auto mesh = Mesh::create(nodedata->id, getMeshIndexData(it->subMeshId));
if(mesh) if(mesh)
{ {
@ -518,6 +519,17 @@ void Sprite3D::createNode(NodeData* nodedata, Node* root, const MaterialDatas& m
} }
} }
} }
Vec3 pos;
Quaternion qua;
Vec3 scale;
nodedata->transform.decompose(&scale, &qua, &pos);
setPosition3D(pos);
setRotationQuat(qua);
setScaleX(scale.x);
setScaleY(scale.y);
setScaleZ(scale.z);
} }
} }
else else

View File

@ -74,7 +74,8 @@ static std::function<Layer*()> createFunctions[] =
CL(Sprite3DEmptyTest), CL(Sprite3DEmptyTest),
CL(UseCaseSprite3D), CL(UseCaseSprite3D),
CL(Sprite3DForceDepthTest), CL(Sprite3DForceDepthTest),
CL(Sprite3DCubeMapTest) CL(Sprite3DCubeMapTest),
CL(NodeAnimationTest)
}; };
#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) #define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0]))
@ -2340,6 +2341,104 @@ void UseCaseSprite3D::update(float delta)
} }
} }
/////////////////////////////////////////////
// Node Frame Animation
NodeAnimationTest::NodeAnimationTest()
:_vectorIndex(0)
{
auto s = Director::getInstance()->getWinSize();
auto itemPrev = MenuItemImage::create("Images/b1.png", "Images/b2.png",
[&](Ref *sender) {
_sprites[_vectorIndex]->setVisible(false);
int tIndex = _vectorIndex - 1;
if(tIndex < 0)
_vectorIndex = _sprites.size()-1;
else
_vectorIndex--;
_sprites[_vectorIndex]->setVisible(true);
});
auto itemNext = MenuItemImage::create("Images/f1.png", "Images/f2.png",
[&](Ref *sender) {
_sprites[_vectorIndex]->setVisible(false);
int tIndex = _vectorIndex + 1;
if(tIndex >= _sprites.size())
_vectorIndex = 0;
else
_vectorIndex++;
_sprites[_vectorIndex]->setVisible(true);
});
auto menu = Menu::create(itemPrev, itemNext, nullptr);
menu->alignItemsHorizontally();
menu->setScale(0.5);
menu->setAnchorPoint(Vec2(0,0));
menu->setPosition(Vec2(s.width/2,70));
addChild(menu);
addNewSpriteWithCoords(Vec2(s.width / 2.f, s.height / 2.f));
}
std::string NodeAnimationTest::title() const
{
return "Node Animation Test";
}
std::string NodeAnimationTest::subtitle() const
{
return "Jumping animation";
}
void NodeAnimationTest::addNewSpriteWithCoords(Vec2 p)
{
auto s = Director::getInstance()->getWinSize();
// add jumping ball
std::string fileName = "Sprite3DTest/ball.c3b";
auto sprite = Sprite3D::create(fileName);
sprite->setRotation3D(Vec3(0, 180, 0));
sprite->setScale(3);
sprite->setPosition(Vec2(s.width / 2.f, s.height / 3.f));
sprite->setTexture("Sprite3DTest/teapot.png");
auto light1 = PointLight::create(Vec3(s.width * 0.2f, s.height * 0.8f, 100.0f), Color3B(200, 200, 200), 10000.0f);
addChild(light1);
auto light2 = AmbientLight::create(Color3B(100, 100, 100));
addChild(light2);
auto animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);
auto act = RepeatForever::create(animate);
act->setTag(0);
sprite->runAction(act);
}
addChild(sprite);
_sprites.push_back(sprite);
// add jumping orc
fileName = "Sprite3DTest/orc_jump.c3t";
sprite = Sprite3D::create(fileName);
sprite->setRotation3D(Vec3(0, 180, 0));
sprite->setScale(3);
sprite->setPosition(Vec2(s.width / 2.f, s.height / 3.f));
sprite->setVisible(false);
animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);
auto act = RepeatForever::create(animate);
act->setTag(0);
sprite->runAction(act);
}
addChild(sprite);
_sprites.push_back(sprite);
}
Sprite3DCubeMapTest::Sprite3DCubeMapTest() : Sprite3DCubeMapTest::Sprite3DCubeMapTest() :
_textureCube(nullptr), _textureCube(nullptr),
_skyBox(nullptr), _skyBox(nullptr),

View File

@ -491,6 +491,21 @@ protected:
std::string _useCaseTitles[(int)USECASE::MAX_CASE_NUM]; std::string _useCaseTitles[(int)USECASE::MAX_CASE_NUM];
}; };
// node animation test, cocos2d-x supports both skeletal animation and node animation
class NodeAnimationTest : public Sprite3DTestDemo
{
public:
CREATE_FUNC(NodeAnimationTest);
NodeAnimationTest();
virtual std::string title() const override;
virtual std::string subtitle() const override;
void addNewSpriteWithCoords(Vec2 p);
protected:
std::vector<Sprite3D*> _sprites;
int _vectorIndex;
};
class Sprite3DTestScene : public TestScene class Sprite3DTestScene : public TestScene
{ {
public: public:

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,7 @@ classes = Animate3D Sprite3D Animation3D Skeleton3D ^Mesh$ AttachNode BillBoard
skip = Mesh::[create getAABB getVertexBuffer hasVertexAttrib getSkin getMeshIndexData getGLProgramState getPrimitiveType getIndexCount getIndexFormat getIndexBuffer], skip = Mesh::[create getAABB getVertexBuffer hasVertexAttrib getSkin getMeshIndexData getGLProgramState getPrimitiveType getIndexCount getIndexFormat getIndexBuffer],
Sprite3D::[getSkin getAABB getMeshArrayByName createAsync], Sprite3D::[getSkin getAABB getMeshArrayByName createAsync],
Skeleton3D::[create], Skeleton3D::[create],
Animation3D::[getBoneCurveByName], Animation3D::[getBoneCurveByName getBoneCurves],
BillBoard::[draw], BillBoard::[draw],
Sprite3DCache::[addSprite3DData getSpriteData] Sprite3DCache::[addSprite3DData getSpriteData]