mirror of https://github.com/axmolengine/axmol.git
Merge branch 'quaternion' of https://github.com/super626/cocos2d-x into v3
This commit is contained in:
commit
7db279220c
|
@ -336,6 +336,8 @@ void Node::setRotation(float rotation)
|
|||
updatePhysicsBodyRotation(getScene());
|
||||
}
|
||||
#endif
|
||||
|
||||
updateRotationQuat();
|
||||
}
|
||||
|
||||
float Node::getRotationSkewX() const
|
||||
|
@ -357,6 +359,8 @@ void Node::setRotation3D(const Vec3& rotation)
|
|||
|
||||
// rotation Z is decomposed in 2 to simulate Skew for Flash animations
|
||||
_rotationZ_Y = _rotationZ_X = rotation.z;
|
||||
|
||||
updateRotationQuat();
|
||||
|
||||
#if CC_USE_PHYSICS
|
||||
if (_physicsBody != nullptr)
|
||||
|
@ -374,6 +378,44 @@ Vec3 Node::getRotation3D() const
|
|||
return Vec3(_rotationX,_rotationY,_rotationZ_X);
|
||||
}
|
||||
|
||||
void Node::updateRotationQuat()
|
||||
{
|
||||
// convert Euler angle to quaternion
|
||||
// when _rotationZ_X == _rotationZ_Y, _rotationQuat = RotationZ_X * RotationY * RotationX
|
||||
// when _rotationZ_X != _rotationZ_Y, _rotationQuat = RotationY * RotationX
|
||||
float halfRadx = CC_DEGREES_TO_RADIANS(_rotationX / 2.f), halfRady = CC_DEGREES_TO_RADIANS(_rotationY / 2.f), halfRadz = _rotationZ_X == _rotationZ_Y ? -CC_DEGREES_TO_RADIANS(_rotationZ_X / 2.f) : 0;
|
||||
float coshalfRadx = cosf(halfRadx), sinhalfRadx = sinf(halfRadx), coshalfRady = cosf(halfRady), sinhalfRady = sinf(halfRady), coshalfRadz = cosf(halfRadz), sinhalfRadz = sinf(halfRadz);
|
||||
_rotationQuat.x = sinhalfRadx * coshalfRady * coshalfRadz - coshalfRadx * sinhalfRady * sinhalfRadz;
|
||||
_rotationQuat.y = coshalfRadx * sinhalfRady * coshalfRadz + sinhalfRadx * coshalfRady * sinhalfRadz;
|
||||
_rotationQuat.z = coshalfRadx * coshalfRady * sinhalfRadz - sinhalfRadx * sinhalfRady * coshalfRadz;
|
||||
_rotationQuat.w = coshalfRadx * coshalfRady * coshalfRadz + sinhalfRadx * sinhalfRady * sinhalfRadz;
|
||||
}
|
||||
|
||||
void Node::updateRotation3D()
|
||||
{
|
||||
//convert quaternion to Euler angle
|
||||
float x = _rotationQuat.x, y = _rotationQuat.y, z = _rotationQuat.z, w = _rotationQuat.w;
|
||||
_rotationX = atan2f(2.f * (w * x + y * z), 1.f - 2.f * (x * x + y * y));
|
||||
_rotationY = asinf(2.f * (w * y - z * x));
|
||||
_rotationZ_X = atanf(2.f * (w * z + x * y) / (1.f - 2.f * (y * y + z * z)));
|
||||
|
||||
_rotationX = CC_RADIANS_TO_DEGREES(_rotationX);
|
||||
_rotationY = CC_RADIANS_TO_DEGREES(_rotationY);
|
||||
_rotationZ_X = _rotationZ_Y = -CC_RADIANS_TO_DEGREES(_rotationZ_X);
|
||||
}
|
||||
|
||||
void Node::setRotationQuat(const Quaternion& quat)
|
||||
{
|
||||
_rotationQuat = quat;
|
||||
updateRotation3D();
|
||||
_transformUpdated = _transformDirty = _inverseDirty = true;
|
||||
}
|
||||
|
||||
Quaternion Node::getRotationQuat() const
|
||||
{
|
||||
return _rotationQuat;
|
||||
}
|
||||
|
||||
void Node::setRotationSkewX(float rotationX)
|
||||
{
|
||||
if (_rotationZ_X == rotationX)
|
||||
|
@ -388,6 +430,8 @@ void Node::setRotationSkewX(float rotationX)
|
|||
|
||||
_rotationZ_X = rotationX;
|
||||
_transformUpdated = _transformDirty = _inverseDirty = true;
|
||||
|
||||
updateRotationQuat();
|
||||
}
|
||||
|
||||
float Node::getRotationSkewY() const
|
||||
|
@ -409,6 +453,8 @@ void Node::setRotationSkewY(float rotationY)
|
|||
|
||||
_rotationZ_Y = rotationY;
|
||||
_transformUpdated = _transformDirty = _inverseDirty = true;
|
||||
|
||||
updateRotationQuat();
|
||||
}
|
||||
|
||||
/// scale getter
|
||||
|
@ -1708,11 +1754,12 @@ const Mat4& Node::getNodeToParentTransform() const
|
|||
y += _anchorPointInPoints.y;
|
||||
}
|
||||
|
||||
bool needsSkewMatrix = ( _skewX || _skewY );
|
||||
// Rotation values
|
||||
// Change rotation code to handle X and Y
|
||||
// If we skew with the exact same value for both x and y then we're simply just rotating
|
||||
float cx = 1, sx = 0, cy = 1, sy = 0;
|
||||
if (_rotationZ_X || _rotationZ_Y)
|
||||
if (_rotationZ_X != _rotationZ_Y || (! needsSkewMatrix && !_anchorPointInPoints.equals(Vec2::ZERO)))
|
||||
{
|
||||
float radiansX = -CC_DEGREES_TO_RADIANS(_rotationZ_X);
|
||||
float radiansY = -CC_DEGREES_TO_RADIANS(_rotationZ_Y);
|
||||
|
@ -1722,8 +1769,6 @@ const Mat4& Node::getNodeToParentTransform() const
|
|||
sy = sinf(radiansY);
|
||||
}
|
||||
|
||||
bool needsSkewMatrix = ( _skewX || _skewY );
|
||||
|
||||
Vec2 anchorPoint(_anchorPointInPoints.x * _scaleX, _anchorPointInPoints.y * _scaleY);
|
||||
|
||||
// optimization:
|
||||
|
@ -1737,39 +1782,26 @@ const Mat4& Node::getNodeToParentTransform() const
|
|||
|
||||
// Build Transform Matrix
|
||||
// Adjusted transform calculation for rotational skew
|
||||
float mat[] = {
|
||||
cy * _scaleX, sy * _scaleX, 0, 0,
|
||||
-sx * _scaleY, cx * _scaleY, 0, 0,
|
||||
0, 0, _scaleZ, 0,
|
||||
x, y, z, 1 };
|
||||
|
||||
_transform.set(mat);
|
||||
|
||||
if(!_ignoreAnchorPointForPosition)
|
||||
Mat4::createRotation(_rotationQuat, &_transform);
|
||||
if (_rotationZ_X != _rotationZ_Y)
|
||||
{
|
||||
_transform.translate(anchorPoint.x, anchorPoint.y, 0);
|
||||
float m0 = _transform.m[0], m1 = _transform.m[1], m4 = _transform.m[4], m5 = _transform.m[5], m8 = _transform.m[8], m9 = _transform.m[9];
|
||||
_transform.m[0] = cy * m0 - sx * m1, _transform.m[4] = cy * m4 - sx * m5, _transform.m[8] = cy * m8 - sx * m9;
|
||||
_transform.m[1] = sy * m0 + cx * m1, _transform.m[5] = sy * m4 + cx * m5, _transform.m[9] = sy * m8 + cx * m9;
|
||||
}
|
||||
|
||||
// FIXME:
|
||||
// FIX ME: Expensive operation.
|
||||
// FIX ME: It should be done together with the rotationZ
|
||||
if(_rotationY)
|
||||
if (_scaleX != 1.f)
|
||||
{
|
||||
Mat4 rotY;
|
||||
Mat4::createRotationY(CC_DEGREES_TO_RADIANS(_rotationY), &rotY);
|
||||
_transform = _transform * rotY;
|
||||
_transform.m[0] *= _scaleX, _transform.m[1] *= _scaleX, _transform.m[2] *= _scaleX;
|
||||
}
|
||||
if(_rotationX)
|
||||
if (_scaleY != 1.f)
|
||||
{
|
||||
Mat4 rotX;
|
||||
Mat4::createRotationX(CC_DEGREES_TO_RADIANS(_rotationX), &rotX);
|
||||
_transform = _transform * rotX;
|
||||
_transform.m[4] *= _scaleY, _transform.m[5] *= _scaleY, _transform.m[6] *= _scaleY;
|
||||
}
|
||||
|
||||
if(!_ignoreAnchorPointForPosition)
|
||||
if (_scaleZ != 1.f)
|
||||
{
|
||||
_transform.translate(-anchorPoint.x, -anchorPoint.y, 0);
|
||||
_transform.m[8] *= _scaleZ, _transform.m[9] *= _scaleZ, _transform.m[10] *= _scaleZ;
|
||||
}
|
||||
_transform.m[12] = x, _transform.m[13] = y, _transform.m[14] = z;
|
||||
|
||||
// FIXME:: Try to inline skew
|
||||
// If skew is needed, apply skew and then anchor point
|
||||
|
|
|
@ -541,6 +541,17 @@ public:
|
|||
* returns the rotation (X,Y,Z) in degrees.
|
||||
*/
|
||||
virtual Vec3 getRotation3D() const;
|
||||
|
||||
/**
|
||||
* set rotation by quaternion
|
||||
*/
|
||||
virtual void setRotationQuat(const Quaternion& quat);
|
||||
|
||||
/**
|
||||
* return the rotation by quaternion, Note that when _rotationZ_X == _rotationZ_Y, the returned quaternion equals to RotationZ_X * RotationY * RotationX,
|
||||
* it equals to RotationY * RotationX otherwise
|
||||
*/
|
||||
virtual Quaternion getRotationQuat() const;
|
||||
|
||||
/**
|
||||
* Sets the X rotation (angle) of the node in degrees which performs a horizontal rotational skew.
|
||||
|
@ -1596,6 +1607,11 @@ protected:
|
|||
//check whether this camera mask is visible by the current visiting camera
|
||||
bool isVisitableByVisitingCamera() const;
|
||||
|
||||
// update quaternion from Rotation3D
|
||||
void updateRotationQuat();
|
||||
// update Rotation3D from quaternion
|
||||
void updateRotation3D();
|
||||
|
||||
#if CC_USE_PHYSICS
|
||||
void updatePhysicsBodyTransform(Scene* layer);
|
||||
virtual void updatePhysicsBodyPosition(Scene* layer);
|
||||
|
@ -1614,6 +1630,8 @@ protected:
|
|||
// rotation Z is decomposed in 2 to simulate Skew for Flash animations
|
||||
float _rotationZ_X; ///< rotation angle on Z-axis, component X
|
||||
float _rotationZ_Y; ///< rotation angle on Z-axis, component Y
|
||||
|
||||
Quaternion _rotationQuat; ///rotation using quaternion, if _rotationZ_X == _rotationZ_Y, _rotationQuat = RotationZ_X * RotationY * RotationX, else _rotationQuat = RotationY * RotationX
|
||||
|
||||
float _scaleX; ///< scaling factor on x-axis
|
||||
float _scaleY; ///< scaling factor on y-axis
|
||||
|
|
|
@ -2328,6 +2328,49 @@ tolua_lerror:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int lua_cocos2dx_Node_setRotationQuat(lua_State* tolua_S)
|
||||
{
|
||||
int argc = 0;
|
||||
cocos2d::Node* cobj = nullptr;
|
||||
bool ok = true;
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_Error tolua_err;
|
||||
#endif
|
||||
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
if (!tolua_isusertype(tolua_S,1,"cc.Node",0,&tolua_err)) goto tolua_lerror;
|
||||
#endif
|
||||
cobj = (cocos2d::Node*)tolua_tousertype(tolua_S,1,0);
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
if (!cobj)
|
||||
{
|
||||
tolua_error(tolua_S,"invalid 'cobj' in function 'lua_cocos2dx_Node_setRotationQuat'", nullptr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
argc = lua_gettop(tolua_S)-1;
|
||||
do{
|
||||
if (argc == 1) {
|
||||
cocos2d::Quaternion arg0;
|
||||
ok &= luaval_to_quaternion(tolua_S, 2, &arg0, "cc.Node:setRotationQuat");
|
||||
|
||||
if (!ok) { break; }
|
||||
cobj->setRotationQuat(arg0);
|
||||
return 0;
|
||||
}
|
||||
}while(0);
|
||||
|
||||
luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "cc.Node:setRotationQuat",argc, 1);
|
||||
return 0;
|
||||
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_Node_setRotationQuat'.",&tolua_err);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_cocos2d_Spawn_create(lua_State* tolua_S)
|
||||
{
|
||||
if (NULL == tolua_S)
|
||||
|
@ -4403,6 +4446,9 @@ static void extendNode(lua_State* tolua_S)
|
|||
lua_pushstring(tolua_S, "setAdditionalTransform");
|
||||
lua_pushcfunction(tolua_S, lua_cocos2dx_Node_setAdditionalTransform);
|
||||
lua_rawset(tolua_S, -3);
|
||||
lua_pushstring(tolua_S, "setRotationQuat");
|
||||
lua_pushcfunction(tolua_S, lua_cocos2dx_Node_setRotationQuat);
|
||||
lua_rawset(tolua_S, -3);
|
||||
}
|
||||
lua_pop(tolua_S, 1);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,8 @@ static std::function<Layer*()> createFunctions[] =
|
|||
CL(AttachmentTest),
|
||||
CL(Sprite3DReskinTest),
|
||||
CL(Sprite3DWithOBBPerfromanceTest),
|
||||
CL(Sprite3DMirrorTest)
|
||||
CL(Sprite3DMirrorTest),
|
||||
CL(QuaternionTest)
|
||||
};
|
||||
|
||||
#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0]))
|
||||
|
@ -1951,3 +1952,53 @@ void Sprite3DMirrorTest::addNewSpriteWithCoords(Vec2 p)
|
|||
}
|
||||
_mirrorSprite = sprite;
|
||||
}
|
||||
|
||||
QuaternionTest::QuaternionTest()
|
||||
: _arcSpeed(CC_DEGREES_TO_RADIANS(90))
|
||||
, _radius(100.f)
|
||||
, _accAngle(0.f)
|
||||
{
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
addNewSpriteWithCoords(Vec2(s.width / 2.f, s.height / 2.f));
|
||||
scheduleUpdate();
|
||||
}
|
||||
std::string QuaternionTest::title() const
|
||||
{
|
||||
return "Test Rotation With Quaternion";
|
||||
}
|
||||
std::string QuaternionTest::subtitle() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
void QuaternionTest::addNewSpriteWithCoords(Vec2 p)
|
||||
{
|
||||
std::string fileName = "Sprite3DTest/tortoise.c3b";
|
||||
auto sprite = Sprite3D::create(fileName);
|
||||
sprite->setScale(0.1f);
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
sprite->setPosition(Vec2(s.width / 2.f + _radius * cosf(_accAngle), s.height / 2.f + _radius * sinf(_accAngle)));
|
||||
addChild(sprite);
|
||||
_sprite = sprite;
|
||||
auto animation = Animation3D::create(fileName);
|
||||
if (animation)
|
||||
{
|
||||
auto animate = Animate3D::create(animation, 0.f, 1.933f);
|
||||
sprite->runAction(RepeatForever::create(animate));
|
||||
}
|
||||
}
|
||||
|
||||
void QuaternionTest::update(float delta)
|
||||
{
|
||||
_accAngle += delta * _arcSpeed;
|
||||
const float pi = 3.1415926f;
|
||||
if (_accAngle >= 2 * pi)
|
||||
_accAngle -= 2 * pi;
|
||||
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
_sprite->setPosition(Vec2(s.width / 2.f + _radius * cosf(_accAngle), s.height / 2.f + _radius * sinf(_accAngle)));
|
||||
|
||||
Quaternion quat;
|
||||
Quaternion::createFromAxisAngle(Vec3(0.f, 0.f, 1.f), _accAngle - pi * 0.5f, &quat);
|
||||
_sprite->setRotationQuat(quat);
|
||||
}
|
||||
|
|
|
@ -408,6 +408,24 @@ protected:
|
|||
cocos2d::Sprite3D* _mirrorSprite;
|
||||
};
|
||||
|
||||
class QuaternionTest : public Sprite3DTestDemo
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(QuaternionTest);
|
||||
QuaternionTest();
|
||||
virtual std::string title() const override;
|
||||
virtual std::string subtitle() const override;
|
||||
|
||||
void addNewSpriteWithCoords(Vec2 p);
|
||||
virtual void update(float delta) override;
|
||||
|
||||
protected:
|
||||
cocos2d::Sprite3D* _sprite;
|
||||
float _arcSpeed;
|
||||
float _radius;
|
||||
float _accAngle;
|
||||
};
|
||||
|
||||
class Sprite3DTestScene : public TestScene
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -35,7 +35,7 @@ classes = New.* Sprite.* Scene Node.* Director Layer.* Menu.* Touch .*Action.* M
|
|||
# will apply to all class names. This is a convenience wildcard to be able to skip similar named
|
||||
# functions from all classes.
|
||||
|
||||
skip = Node::[setGLServerState description getUserObject .*UserData getGLServerState .*schedule getPosition$ setContentSize setAnchorPoint enumerateChildren getonEnterTransitionDidFinishCallback getOnEnterCallback getOnExitCallback getonExitTransitionDidStartCallback setAdditionalTransform],
|
||||
skip = Node::[setGLServerState description getUserObject .*UserData getGLServerState .*schedule getPosition$ setContentSize setAnchorPoint enumerateChildren getonEnterTransitionDidFinishCallback getOnEnterCallback getOnExitCallback getonExitTransitionDidStartCallback setAdditionalTransform setRotationQuat getRotationQuat],
|
||||
Sprite::[getQuad getBlendFunc ^setPosition$ setBlendFunc],
|
||||
SpriteBatchNode::[getBlendFunc setBlendFunc getDescendants],
|
||||
MotionStreak::[getBlendFunc setBlendFunc draw update],
|
||||
|
|
Loading…
Reference in New Issue