From bdc12dce8bd357d3754d5f54c7a1ccb08c08d097 Mon Sep 17 00:00:00 2001 From: yangxiao Date: Mon, 22 Dec 2014 15:14:18 +0800 Subject: [PATCH 01/10] add quaternion property --- cocos/2d/CCNode.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cocos/2d/CCNode.h b/cocos/2d/CCNode.h index f177184848..a19b6e5373 100644 --- a/cocos/2d/CCNode.h +++ b/cocos/2d/CCNode.h @@ -1614,6 +1614,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 _rotation_quat; ///rotation using quaternion float _scaleX; ///< scaling factor on x-axis float _scaleY; ///< scaling factor on y-axis From e8c7f305419aab4be401119bf59af98ddc299024 Mon Sep 17 00:00:00 2001 From: yangxiao Date: Mon, 22 Dec 2014 17:23:44 +0800 Subject: [PATCH 02/10] add quaternion --- cocos/2d/CCNode.cpp | 38 ++++++++++++++++++++++++++++++++++++++ cocos/2d/CCNode.h | 15 +++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index e756ae32ba..e298ea0e00 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -357,6 +357,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 +376,42 @@ Vec3 Node::getRotation3D() const return Vec3(_rotationX,_rotationY,_rotationZ_X); } +void Node::updateRotationQuat() +{ + // convert Euler angle to quaternion + float halfRadx = CC_DEGREES_TO_RADIANS(_rotationX / 2.f), halfRady = CC_DEGREES_TO_RADIANS(_rotationY / 2.f), halfRadz = -CC_DEGREES_TO_RADIANS(_rotationZ_X / 2.f); + float coshalfRadx = cosf(halfRadx), sinhalfRadx = sinf(halfRady), coshalfRady = cosf(halfRady), sinhalfRady = sinf(halfRady), coshalfRadz = cosf(halfRadz), sinhalfRadz = sinf(halfRadz); + _rotation_quat.x = sinhalfRadx * coshalfRady * coshalfRadz - coshalfRadx * sinhalfRady * sinhalfRadz; + _rotation_quat.y = coshalfRadx * sinhalfRady * coshalfRadz + sinhalfRadx * coshalfRady * sinhalfRadz; + _rotation_quat.z = coshalfRadx * coshalfRady * sinhalfRadz - sinhalfRadx * sinhalfRady * coshalfRadz; + _rotation_quat.w = coshalfRadx * coshalfRady * coshalfRadz + sinhalfRadx * sinhalfRady * sinhalfRadz; +} + +void Node::updateRotation3D() +{ + //convert quaternion to Euler angle + float x = _rotation_quat.x, y = _rotation_quat.y, z = _rotation_quat.z, w = _rotation_quat.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) +{ + _rotation_quat = quat; + updateRotation3D(); + _transformUpdated = _transformDirty = _inverseDirty = true; +} + +Quaternion Node::getRotationQuat() +{ + return _rotation_quat; +} + void Node::setRotationSkewX(float rotationX) { if (_rotationZ_X == rotationX) diff --git a/cocos/2d/CCNode.h b/cocos/2d/CCNode.h index a19b6e5373..cf9ec83d56 100644 --- a/cocos/2d/CCNode.h +++ b/cocos/2d/CCNode.h @@ -541,6 +541,16 @@ 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 + */ + virtual Quaternion getRotationQuat(); /** * Sets the X rotation (angle) of the node in degrees which performs a horizontal rotational skew. @@ -1596,6 +1606,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); From 22ae384edf2fd80bb2e02a25c76cbda7858a91b1 Mon Sep 17 00:00:00 2001 From: yangxiao Date: Wed, 24 Dec 2014 17:07:54 +0800 Subject: [PATCH 03/10] Rotation representation with quaternion fix #9510 --- cocos/2d/CCNode.cpp | 93 ++++++++++++------- cocos/2d/CCNode.h | 7 +- .../Classes/SpriteTest/SpriteTest.cpp | 1 + 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index e298ea0e00..8695d4b6aa 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -336,6 +336,8 @@ void Node::setRotation(float rotation) updatePhysicsBodyRotation(getScene()); } #endif + + updateRotationQuat(); } float Node::getRotationSkewX() const @@ -379,7 +381,9 @@ Vec3 Node::getRotation3D() const void Node::updateRotationQuat() { // convert Euler angle to quaternion - float halfRadx = CC_DEGREES_TO_RADIANS(_rotationX / 2.f), halfRady = CC_DEGREES_TO_RADIANS(_rotationY / 2.f), halfRadz = -CC_DEGREES_TO_RADIANS(_rotationZ_X / 2.f); + // when _rotationZ_X == _rotationZ_Y, _rotation_quat = RotationZ_X * RotationY * RotationX + // when _rotationZ_X != _rotationZ_Y, _rotation_quat = 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(halfRady), coshalfRady = cosf(halfRady), sinhalfRady = sinf(halfRady), coshalfRadz = cosf(halfRadz), sinhalfRadz = sinf(halfRadz); _rotation_quat.x = sinhalfRadx * coshalfRady * coshalfRadz - coshalfRadx * sinhalfRady * sinhalfRadz; _rotation_quat.y = coshalfRadx * sinhalfRady * coshalfRadz + sinhalfRadx * coshalfRady * sinhalfRadz; @@ -397,7 +401,7 @@ void Node::updateRotation3D() _rotationX = CC_RADIANS_TO_DEGREES(_rotationX); _rotationY = CC_RADIANS_TO_DEGREES(_rotationY); - _rotationZ_X = _rotationZ_Y = CC_RADIANS_TO_DEGREES(_rotationZ_X); + _rotationZ_X = _rotationZ_Y = -CC_RADIANS_TO_DEGREES(_rotationZ_X); } void Node::setRotationQuat(const Quaternion& quat) @@ -407,7 +411,7 @@ void Node::setRotationQuat(const Quaternion& quat) _transformUpdated = _transformDirty = _inverseDirty = true; } -Quaternion Node::getRotationQuat() +Quaternion Node::getRotationQuat() const { return _rotation_quat; } @@ -426,6 +430,8 @@ void Node::setRotationSkewX(float rotationX) _rotationZ_X = rotationX; _transformUpdated = _transformDirty = _inverseDirty = true; + + updateRotationQuat(); } float Node::getRotationSkewY() const @@ -447,6 +453,8 @@ void Node::setRotationSkewY(float rotationY) _rotationZ_Y = rotationY; _transformUpdated = _transformDirty = _inverseDirty = true; + + updateRotationQuat(); } /// scale getter @@ -1741,11 +1749,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); @@ -1755,8 +1764,6 @@ const Mat4& Node::getNodeToParentTransform() const sy = sinf(radiansY); } - bool needsSkewMatrix = ( _skewX || _skewY ); - Vec2 anchorPoint; anchorPoint.x = _anchorPointInPoints.x * _scaleX; anchorPoint.y = _anchorPointInPoints.y * _scaleY; @@ -1772,37 +1779,57 @@ 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(_rotation_quat, &_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) { - Mat4 rotY; - Mat4::createRotationY(CC_DEGREES_TO_RADIANS(_rotationY), &rotY); - _transform = _transform * rotY; - } - if(_rotationX) { - Mat4 rotX; - Mat4::createRotationX(CC_DEGREES_TO_RADIANS(_rotationX), &rotX); - _transform = _transform * rotX; - } - - if(!_ignoreAnchorPointForPosition) + if (_scaleX != 1.f) { - _transform.translate(-anchorPoint.x, -anchorPoint.y, 0); + _transform.m[0] *= _scaleX, _transform.m[4] *= _scaleX, _transform.m[8] *= _scaleX; } + if (_scaleY) + { + _transform.m[1] *= _scaleY, _transform.m[5] *= _scaleY, _transform.m[9] *= _scaleY; + } + if (_scaleZ) + { + _transform.m[2] *= _scaleZ, _transform.m[6] *= _scaleZ, _transform.m[10] *= _scaleZ; + } + _transform.m[12] = x, _transform.m[13] = y, _transform.m[14] = z; +// 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) +// { +// _transform.translate(anchorPoint.x, anchorPoint.y, 0); +// } +// +// // FIXME: +// // FIX ME: Expensive operation. +// // FIX ME: It should be done together with the rotationZ +// if(_rotationY) { +// Mat4 rotY; +// Mat4::createRotationY(CC_DEGREES_TO_RADIANS(_rotationY), &rotY); +// _transform = _transform * rotY; +// } +// if(_rotationX) { +// Mat4 rotX; +// Mat4::createRotationX(CC_DEGREES_TO_RADIANS(_rotationX), &rotX); +// _transform = _transform * rotX; +// } +// +// if(!_ignoreAnchorPointForPosition) +// { +// _transform.translate(-anchorPoint.x, -anchorPoint.y, 0); +// } // FIXME:: Try to inline skew // If skew is needed, apply skew and then anchor point diff --git a/cocos/2d/CCNode.h b/cocos/2d/CCNode.h index cf9ec83d56..dbd76532d4 100644 --- a/cocos/2d/CCNode.h +++ b/cocos/2d/CCNode.h @@ -548,9 +548,10 @@ public: virtual void setRotationQuat(const Quaternion& quat); /** - * return the rotation by quaternion + * 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(); + virtual Quaternion getRotationQuat() const; /** * Sets the X rotation (angle) of the node in degrees which performs a horizontal rotational skew. @@ -1630,7 +1631,7 @@ protected: float _rotationZ_X; ///< rotation angle on Z-axis, component X float _rotationZ_Y; ///< rotation angle on Z-axis, component Y - Quaternion _rotation_quat; ///rotation using quaternion + Quaternion _rotation_quat; ///rotation using quaternion, if _rotationZ_X == _rotationZ_Y, _rotation_quat = RotationZ_X * RotationY * RotationX, else _rotation_quat = RotationY * RotationX float _scaleX; ///< scaling factor on x-axis float _scaleY; ///< scaling factor on y-axis diff --git a/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp b/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp index 5ce1bc0b20..775842b8e4 100644 --- a/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp +++ b/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp @@ -3884,6 +3884,7 @@ SpriteOffsetAnchorSkew::SpriteOffsetAnchorSkew() auto seq_skew = Sequence::create(skewX, skewX_back, skewY, skewY_back, nullptr); sprite->runAction(RepeatForever::create(seq_skew)); + sprite->ignoreAnchorPointForPosition(true); addChild(sprite, 0); } } From 88e0f025eff652cb6dccfa9353063fe28126a6d3 Mon Sep 17 00:00:00 2001 From: yangxiao Date: Wed, 24 Dec 2014 17:18:09 +0800 Subject: [PATCH 04/10] make it clean --- cocos/2d/CCNode.cpp | 31 ------------------- .../Classes/SpriteTest/SpriteTest.cpp | 1 - 2 files changed, 32 deletions(-) diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index 8695d4b6aa..76c6d416f0 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -1799,37 +1799,6 @@ const Mat4& Node::getNodeToParentTransform() const _transform.m[2] *= _scaleZ, _transform.m[6] *= _scaleZ, _transform.m[10] *= _scaleZ; } _transform.m[12] = x, _transform.m[13] = y, _transform.m[14] = z; -// 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) -// { -// _transform.translate(anchorPoint.x, anchorPoint.y, 0); -// } -// -// // FIXME: -// // FIX ME: Expensive operation. -// // FIX ME: It should be done together with the rotationZ -// if(_rotationY) { -// Mat4 rotY; -// Mat4::createRotationY(CC_DEGREES_TO_RADIANS(_rotationY), &rotY); -// _transform = _transform * rotY; -// } -// if(_rotationX) { -// Mat4 rotX; -// Mat4::createRotationX(CC_DEGREES_TO_RADIANS(_rotationX), &rotX); -// _transform = _transform * rotX; -// } -// -// if(!_ignoreAnchorPointForPosition) -// { -// _transform.translate(-anchorPoint.x, -anchorPoint.y, 0); -// } // FIXME:: Try to inline skew // If skew is needed, apply skew and then anchor point diff --git a/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp b/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp index 775842b8e4..5ce1bc0b20 100644 --- a/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp +++ b/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp @@ -3884,7 +3884,6 @@ SpriteOffsetAnchorSkew::SpriteOffsetAnchorSkew() auto seq_skew = Sequence::create(skewX, skewX_back, skewY, skewY_back, nullptr); sprite->runAction(RepeatForever::create(seq_skew)); - sprite->ignoreAnchorPointForPosition(true); addChild(sprite, 0); } } From 6eed142e03cfc432b4e32c99e2018cecc9671204 Mon Sep 17 00:00:00 2001 From: yangxiao Date: Wed, 24 Dec 2014 18:12:00 +0800 Subject: [PATCH 05/10] rename _rotation_quat to _rotationQuat --- cocos/2d/CCNode.cpp | 20 ++++++++++---------- cocos/2d/CCNode.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index 0ddf93acd2..ffd2440a96 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -381,20 +381,20 @@ Vec3 Node::getRotation3D() const void Node::updateRotationQuat() { // convert Euler angle to quaternion - // when _rotationZ_X == _rotationZ_Y, _rotation_quat = RotationZ_X * RotationY * RotationX - // when _rotationZ_X != _rotationZ_Y, _rotation_quat = RotationY * RotationX + // 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(halfRady), coshalfRady = cosf(halfRady), sinhalfRady = sinf(halfRady), coshalfRadz = cosf(halfRadz), sinhalfRadz = sinf(halfRadz); - _rotation_quat.x = sinhalfRadx * coshalfRady * coshalfRadz - coshalfRadx * sinhalfRady * sinhalfRadz; - _rotation_quat.y = coshalfRadx * sinhalfRady * coshalfRadz + sinhalfRadx * coshalfRady * sinhalfRadz; - _rotation_quat.z = coshalfRadx * coshalfRady * sinhalfRadz - sinhalfRadx * sinhalfRady * coshalfRadz; - _rotation_quat.w = coshalfRadx * coshalfRady * coshalfRadz + sinhalfRadx * sinhalfRady * sinhalfRadz; + _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 = _rotation_quat.x, y = _rotation_quat.y, z = _rotation_quat.z, w = _rotation_quat.w; + 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))); @@ -406,14 +406,14 @@ void Node::updateRotation3D() void Node::setRotationQuat(const Quaternion& quat) { - _rotation_quat = quat; + _rotationQuat = quat; updateRotation3D(); _transformUpdated = _transformDirty = _inverseDirty = true; } Quaternion Node::getRotationQuat() const { - return _rotation_quat; + return _rotationQuat; } void Node::setRotationSkewX(float rotationX) @@ -1782,7 +1782,7 @@ const Mat4& Node::getNodeToParentTransform() const // Build Transform Matrix // Adjusted transform calculation for rotational skew - Mat4::createRotation(_rotation_quat, &_transform); + Mat4::createRotation(_rotationQuat, &_transform); if (_rotationZ_X != _rotationZ_Y) { 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]; diff --git a/cocos/2d/CCNode.h b/cocos/2d/CCNode.h index dbd76532d4..84d26dba42 100644 --- a/cocos/2d/CCNode.h +++ b/cocos/2d/CCNode.h @@ -1631,7 +1631,7 @@ protected: float _rotationZ_X; ///< rotation angle on Z-axis, component X float _rotationZ_Y; ///< rotation angle on Z-axis, component Y - Quaternion _rotation_quat; ///rotation using quaternion, if _rotationZ_X == _rotationZ_Y, _rotation_quat = RotationZ_X * RotationY * RotationX, else _rotation_quat = RotationY * RotationX + 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 From 510633ba72f601c78c0ecc9b80f2e69ab0242847 Mon Sep 17 00:00:00 2001 From: yangxiao Date: Thu, 25 Dec 2014 10:33:49 +0800 Subject: [PATCH 06/10] wrong spelling --- cocos/2d/CCNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index ffd2440a96..736e7a59e7 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -384,7 +384,7 @@ void Node::updateRotationQuat() // 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(halfRady), coshalfRady = cosf(halfRady), sinhalfRady = sinf(halfRady), coshalfRadz = cosf(halfRadz), sinhalfRadz = sinf(halfRadz); + 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; From 0db70977f949b2c67045c45e8f5235739b08d48d Mon Sep 17 00:00:00 2001 From: yangxiao Date: Thu, 25 Dec 2014 10:39:48 +0800 Subject: [PATCH 07/10] wrong scale order --- cocos/2d/CCNode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index 736e7a59e7..f52a1b5a98 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -1791,15 +1791,15 @@ const Mat4& Node::getNodeToParentTransform() const } if (_scaleX != 1.f) { - _transform.m[0] *= _scaleX, _transform.m[4] *= _scaleX, _transform.m[8] *= _scaleX; + _transform.m[0] *= _scaleX, _transform.m[1] *= _scaleX, _transform.m[2] *= _scaleX; } if (_scaleY != 1.f) { - _transform.m[1] *= _scaleY, _transform.m[5] *= _scaleY, _transform.m[9] *= _scaleY; + _transform.m[4] *= _scaleY, _transform.m[5] *= _scaleY, _transform.m[6] *= _scaleY; } if (_scaleZ != 1.f) { - _transform.m[2] *= _scaleZ, _transform.m[6] *= _scaleZ, _transform.m[10] *= _scaleZ; + _transform.m[8] *= _scaleZ, _transform.m[9] *= _scaleZ, _transform.m[10] *= _scaleZ; } _transform.m[12] = x, _transform.m[13] = y, _transform.m[14] = z; From 04e273e245947c498685252a6d135cc910d53e50 Mon Sep 17 00:00:00 2001 From: yangxiao Date: Thu, 25 Dec 2014 14:54:20 +0800 Subject: [PATCH 08/10] bind setRotationQuat --- .../manual/cocos2d/lua_cocos2dx_manual.cpp | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/cocos/scripting/lua-bindings/manual/cocos2d/lua_cocos2dx_manual.cpp b/cocos/scripting/lua-bindings/manual/cocos2d/lua_cocos2dx_manual.cpp index b46c5cf137..47dab09de1 100644 --- a/cocos/scripting/lua-bindings/manual/cocos2d/lua_cocos2dx_manual.cpp +++ b/cocos/scripting/lua-bindings/manual/cocos2d/lua_cocos2dx_manual.cpp @@ -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); } From de7b70f63e53e2636de6d39bcdf7fbc36757eab3 Mon Sep 17 00:00:00 2001 From: yangxiao Date: Thu, 25 Dec 2014 14:55:43 +0800 Subject: [PATCH 09/10] skip Node::set/getRotationQuat --- tools/tolua/cocos2dx.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tolua/cocos2dx.ini b/tools/tolua/cocos2dx.ini index a612f8cc65..ea95ce748a 100644 --- a/tools/tolua/cocos2dx.ini +++ b/tools/tolua/cocos2dx.ini @@ -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], From 060c6ee0b7fd95c359065cf5870bfb07e97ca2dd Mon Sep 17 00:00:00 2001 From: yangxiao Date: Mon, 29 Dec 2014 14:36:25 +0800 Subject: [PATCH 10/10] add quaternion test --- .../Classes/Sprite3DTest/Sprite3DTest.cpp | 53 ++++++++++++++++++- .../Classes/Sprite3DTest/Sprite3DTest.h | 18 +++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.cpp b/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.cpp index 5181534696..8c5c65e0dc 100644 --- a/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.cpp +++ b/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.cpp @@ -67,7 +67,8 @@ static std::function 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); +} diff --git a/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.h b/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.h index 234066fa81..c562025fcf 100644 --- a/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.h +++ b/tests/cpp-tests/Classes/Sprite3DTest/Sprite3DTest.h @@ -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: