From Javier Taibo, "ere is the new code with Billboard "rotate around axis" functionality.

A new AutoRotateMode was added. I named it ROTATE_TO_AXIS to be
consistent with the other AutoRotateModes, even though it changes from
how is called in Billboard (AXIAL_ROT).

  Setters and getters for rotation axis and normal were also added to the
AutoTransform class interface.

  The implementation is mainly a copy-paste from Billboard code.
"
This commit is contained in:
Robert Osfield
2010-11-05 17:24:50 +00:00
parent 5a0b2760b4
commit 752a5e2a3c
2 changed files with 153 additions and 4 deletions

View File

@@ -72,13 +72,25 @@ class OSG_EXPORT AutoTransform : public Transform
{
NO_ROTATION,
ROTATE_TO_SCREEN,
ROTATE_TO_CAMERA
ROTATE_TO_CAMERA,
ROTATE_TO_AXIS
};
void setAutoRotateMode(AutoRotateMode mode) { _autoRotateMode = mode; _firstTimeToInitEyePoint = true; }
void setAutoRotateMode(AutoRotateMode mode);
AutoRotateMode getAutoRotateMode() const { return _autoRotateMode; }
/** Set the rotation axis for the AutoTransform's child nodes.
* Only utilized when _autoRotateMode==ROTATE_TO_AXIS. */
void setAxis(const Vec3& axis);
/** Get the rotation axis. */
inline const Vec3& getAxis() const { return _axis; }
/** This normal defines child Nodes' front face direction when unrotated. */
void setNormal(const Vec3& normal);
/** Get the front face direction normal. */
inline const Vec3& getNormal() const { return _normal; }
void setAutoScaleToScreen(bool autoScaleToScreen) { _autoScaleToScreen = autoScaleToScreen; _matrixDirty=true; }
bool getAutoScaleToScreen() const { return _autoScaleToScreen; }
@@ -124,6 +136,24 @@ class OSG_EXPORT AutoTransform : public Transform
mutable bool _matrixDirty;
mutable osg::Matrixd _cachedMatrix;
enum AxisAligned
{
AXIAL_ROT_X_AXIS=ROTATE_TO_AXIS+1,
AXIAL_ROT_Y_AXIS,
AXIAL_ROT_Z_AXIS,
CACHE_DIRTY
};
Vec3 _axis;
Vec3 _normal;
// used internally as cache of which what _axis is aligned to help
// decide which method of rotation to use.
int _cachedMode;
Vec3 _side;
void updateCache();
};
}

View File

@@ -26,7 +26,11 @@ AutoTransform::AutoTransform():
_minimumScale(0.0),
_maximumScale(DBL_MAX),
_autoScaleTransitionWidthRatio(0.25),
_matrixDirty(true)
_matrixDirty(true),
_axis(0.0f,0.0f,1.0f),
_normal(0.0f,-1.0f,0.0f),
_cachedMode(NO_ROTATION),
_side(1.0f,0.0,0.0f)
{
// setNumChildrenRequiringUpdateTraversal(1);
}
@@ -44,11 +48,52 @@ AutoTransform::AutoTransform(const AutoTransform& pat,const CopyOp& copyop):
_minimumScale(pat._minimumScale),
_maximumScale(pat._maximumScale),
_autoScaleTransitionWidthRatio(pat._autoScaleTransitionWidthRatio),
_matrixDirty(true)
_matrixDirty(true),
_axis(pat._axis),
_normal(pat._normal),
_cachedMode(pat._cachedMode),
_side(pat._side)
{
// setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);
}
void AutoTransform::setAutoRotateMode(AutoRotateMode mode)
{
_autoRotateMode = mode;
_firstTimeToInitEyePoint = true;
_cachedMode = CACHE_DIRTY;
updateCache();
}
void AutoTransform::setAxis(const Vec3& axis)
{
_axis = axis;
_axis.normalize();
updateCache();
}
void AutoTransform::setNormal(const Vec3& normal)
{
_normal = normal;
_normal.normalize();
updateCache();
}
void AutoTransform::updateCache()
{
if (_autoRotateMode==ROTATE_TO_AXIS)
{
if (_axis==Vec3(1.0f,0.0,0.0f) && _normal==Vec3(0.0f,-1.0,0.0f)) _cachedMode = AXIAL_ROT_X_AXIS;
else if (_axis==Vec3(0.0f,1.0,0.0f) && _normal==Vec3(1.0f, 0.0,0.0f)) _cachedMode = AXIAL_ROT_Y_AXIS;
else if (_axis==Vec3(0.0f,0.0,1.0f) && _normal==Vec3(0.0f,-1.0,0.0f)) _cachedMode = AXIAL_ROT_Z_AXIS;
else _cachedMode = ROTATE_TO_AXIS;
}
else _cachedMode = _autoRotateMode;
_side = _axis^_normal;
_side.normalize();
}
void AutoTransform::setScale(const Vec3d& scale)
{
_scale = scale;
@@ -240,6 +285,80 @@ void AutoTransform::accept(NodeVisitor& nv)
q.set(osg::Matrix::inverse(lookto));
setRotation(q);
}
else if (_autoRotateMode==ROTATE_TO_AXIS)
{
Matrix matrix;
Vec3 ev(eyePoint - _position);
switch(_cachedMode)
{
case(AXIAL_ROT_Z_AXIS):
{
ev.z() = 0.0f;
float ev_length = ev.length();
if (ev_length>0.0f)
{
//float rotation_zrotation_z = atan2f(ev.x(),ev.y());
//mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
float inv = 1.0f/ev_length;
float s = ev.x()*inv;
float c = -ev.y()*inv;
matrix(0,0) = c;
matrix(1,0) = -s;
matrix(0,1) = s;
matrix(1,1) = c;
}
break;
}
case(AXIAL_ROT_Y_AXIS):
{
ev.y() = 0.0f;
float ev_length = ev.length();
if (ev_length>0.0f)
{
//float rotation_zrotation_z = atan2f(ev.x(),ev.y());
//mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
float inv = 1.0f/ev_length;
float s = -ev.z()*inv;
float c = ev.x()*inv;
matrix(0,0) = c;
matrix(2,0) = s;
matrix(0,2) = -s;
matrix(2,2) = c;
}
break;
}
case(AXIAL_ROT_X_AXIS):
{
ev.x() = 0.0f;
float ev_length = ev.length();
if (ev_length>0.0f)
{
//float rotation_zrotation_z = atan2f(ev.x(),ev.y());
//mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
float inv = 1.0f/ev_length;
float s = -ev.z()*inv;
float c = -ev.y()*inv;
matrix(1,1) = c;
matrix(2,1) = -s;
matrix(1,2) = s;
matrix(2,2) = c;
}
break;
}
case(ROTATE_TO_AXIS): // need to implement
{
float ev_side = ev*_side;
float ev_normal = ev*_normal;
float rotation = atan2f(ev_side,ev_normal);
matrix.makeRotate(rotation,_axis);
break;
}
}
Quat q;
q.set(matrix);
setRotation(q);
}
_previousEyePoint = eyePoint;
_previousLocalUp = localUp;