#define _AXIS_OBJECT_H_
class AxisObject
{
enum BoxParts
{
BOX_NONE = 0x00,
BOX_TOP = 0x01,
BOX_BOT = 0x02,
BOX_FRONT = 0x04,
BOX_BACK = 0x08,
BOX_LEFT = 0x10,
BOX_RIGHT = 0x20,
BOX_ALL = 0xFF
};
private:
void addMaterial(const Ogre::String& mat, Ogre::ColourValue &clr, Ogre::SceneBlendType sbt);
void addBox(Ogre::ManualObject* obj, Ogre::Vector3 dim, Ogre::Vector3 pos, Ogre::ColourValue color, short boxMask);
public:
Ogre::ManualObject* createAxis(Ogre::SceneManager* scene, const Ogre::String &name, Ogre::Real scale);
};
#endif
#include "Ogre.h"
#include "OgreMaterial.h"
#include "AxisObject.h"
using namespace Ogre;
void AxisObject::addBox(Ogre::ManualObject* obj, Ogre::Vector3 dim, Ogre::Vector3 pos, Ogre::ColourValue color, short boxMask)
{
if(!obj)
return;
obj->begin("Axis", Ogre::RenderOperation::OT_TRIANGLE_LIST);
dim/= 2;
Ogre::Real l = dim.x;
Ogre::Real h = dim.y;
Ogre::Real w = dim.z;
obj->position(Ogre::Vector3(-1, h, w) + pos);
obj->colour(color);
obj->position(Ogre::Vector3(-l, -h, w) + pos);
obj->colour(color);
obj->position(Ogre::Vector3(1, -h, w) + pos);
obj->colour(color);
obj->position(Ogre::Vector3(1, h, w) + pos);
obj->position(Ogre::Vector3(-1, h, -w) + pos);
obj->colour(color);
obj->position(Ogre::Vector3(-1, -h, -w) + pos);
obj->colour(color);
obj->position(Ogre::Vector3(1, -h, -w) + pos);
obj->colour(color);
obj->position(Ogre::Vector3(1, h, -w) + pos);
//front back
if(boxMask & BOX_FRONT)
obj->quad(0, 1, 2, 3);
if(boxMask & BOX_BACK)
obj->quad(7, 6, 5, 4);
//top bottom
if(boxMask & BOX_TOP)
obj->quad(0, 3, 7, 4);
if(boxMask & BOX_BOT)
obj->quad(2, 1, 5, 6);
//end caps
if(boxMask & BOX_RIGHT)
obj->quad(1, 0, 4, 5);
if(boxMask & BOX_LEFT)
obj->quad(3, 2, 6, 7);
obj->end();
}
void AxisObject::addMaterial(const Ogre::String& mat, Ogre::ColourValue &clr, Ogre::SceneBlendType sbt)
{
static int init = false;
if(init)
return;
else
init = true;
Ogre::MaterialPtr matptr = Ogre::MaterialManager::getSingleton().create(mat, "General");
matptr->setReceiveShadows(false);
matptr->getTechnique(0)->setLightingEnabled(true);
matptr->getTechnique(0)->getPass(0)->setDiffuse(clr);
matptr->getTechnique(0)->getPass(0)->setAmbient(clr);
matptr->getTechnique(0)->getPass(0)->setSelfIllumination(clr);
matptr->getTechnique(0)->getPass(0)->setSceneBlending(sbt);
matptr->getTechnique(0)->getPass(0)->setLightingEnabled(false);
matptr->getTechnique(0)->getPass(0)->setVertexColourTracking(Ogre::TVC_DIFFUSE);
}
Ogre::ManualObject* AxisObject::createAxis(Ogre::SceneManager* scene, const Ogre::String &name, Ogre::Real scale)
{
addMaterial("Axis", Ogre::ColourValue(1, 1, 1, .75), Ogre::SBT_TRANSPARENT_ALPHA);
Ogre::ManualObject* axis = scene->createManualObject(name);
Ogre::Real len = scale;
Ogre::Real scl = len * .1;
Ogre::Real loc = len / 2 + scl / 2;
Ogre::Real fade = .5;
Ogre::Real solid = .8;
addBox(axis, Vector3(len, scl, scl), Vector3(loc,0,0), ColourValue(0, 0, solid, solid), (BOX_ALL & ~BOX_RIGHT));
addBox(axis, Vector3(len, scl, scl), Vector3(-loc,0,0), ColourValue(0, 0, fade, fade), (BOX_ALL & ~BOX_LEFT));
addBox(axis, Vector3(scl, len, scl), Vector3(0,loc,0), ColourValue(0, solid, 0, solid), (BOX_ALL & ~BOX_BOT));
addBox(axis, Vector3(scl, len, scl), Vector3(0,-loc,0), ColourValue(0, fade, 0, fade), (BOX_ALL & ~BOX_TOP));
addBox(axis, Vector3(scl, scl, len), Vector3(0,0,loc), ColourValue(solid, 0, 0, solid), (BOX_ALL & ~BOX_BACK));
addBox(axis, Vector3(scl, scl, len), Vector3(0,0,-loc), ColourValue(fade, 0, 0, fade), (BOX_ALL & ~BOX_FRONT));
axis->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - 1);
return axis;
}
调用
#include "ExampleApplication.h"
#include "AxisObject.h"
#define NUM_JAIQUAS 6
AnimationState* mAnimState[NUM_JAIQUAS];
Real mAnimationSpeed[NUM_JAIQUAS];
Vector3 mSneakStartOffset;
Vector3 mSneakEndOffset;
Quaternion mOrientations[NUM_JAIQUAS];
Vector3 mBasePositions[NUM_JAIQUAS];
SceneNode* mSceneNode[NUM_JAIQUAS];
Degree mAnimationRotation(-60);
Real mAnimChop = 7.96666f;
Real mAnimChopBlend = 0.3f;
// Event handler to animate
class SkeletalAnimationFrameListener : public ExampleFrameListener
{
protected:
public:
SkeletalAnimationFrameListener(RenderWindow* win, Camera* cam, const std::string &debugText)
: ExampleFrameListener(win, cam)
{
mDebugText = debugText;
}
bool frameRenderingQueued(const FrameEvent& evt)
{
if( ExampleFrameListener::frameRenderingQueued(evt) == false )
return false;
for (int i = 0; i < NUM_JAIQUAS; ++i)
{
Real inc = evt.timeSinceLastFrame * mAnimationSpeed[i];
if ((mAnimState[i]->getTimePosition() + inc) >= mAnimChop)
{
// Loop
// Need to reposition the scene node origin since animation includes translation
// Calculate as an offset to the end position, rotated by the
// amount the animation turns the character
Quaternion rot(mAnimationRotation, Vector3::UNIT_Y);
Vector3 startoffset = mSceneNode[i]->getOrientation() * -mSneakStartOffset;
Vector3 endoffset = mSneakEndOffset;
Vector3 offset = rot * startoffset;
Vector3 currEnd = mSceneNode[i]->getOrientation() * endoffset + mSceneNode[i]->getPosition();
mSceneNode[i]->setPosition(currEnd + offset);
mSceneNode[i]->rotate(rot);
mAnimState[i]->setTimePosition((mAnimState[i]->getTimePosition() + inc) - mAnimChop);
}
else
{
mAnimState[i]->addTime(inc);
}
}
return true;
}
};
class SkeletalApplication : public ExampleApplication
{
public:
SkeletalApplication() {}
protected:
std::string mDebugText;
// Just override the mandatory create scene method
void createScene(void)
{
mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
mSceneMgr->setShadowTextureSize(512);
mSceneMgr->setShadowColour(ColourValue(0.6, 0.6, 0.6));
// Setup animation default
Animation::setDefaultInterpolationMode(Animation::IM_LINEAR);
Animation::setDefaultRotationInterpolationMode(Animation::RIM_LINEAR);
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
// The jaiqua sneak animation doesn't loop properly, so lets hack it so it does
// We want to copy the initial keyframes of all bones, but alter the Spineroot
// to give it an offset of where the animation ends
SkeletonPtr skel = SkeletonManager::getSingleton().load("jaiqua.skeleton",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
Animation* anim = skel->getAnimation("Sneak");
Animation::NodeTrackIterator trackIter = anim->getNodeTrackIterator();
while (trackIter.hasMoreElements())
{
NodeAnimationTrack* track = trackIter.getNext();
TransformKeyFrame oldKf(0, 0);
track->getInterpolatedKeyFrame(mAnimChop, &oldKf);
// Drop all keyframes after the chop
while (track->getKeyFrame(track->getNumKeyFrames()-1)->getTime() >= mAnimChop - mAnimChopBlend)
track->removeKeyFrame(track->getNumKeyFrames()-1);
TransformKeyFrame* newKf = track->createNodeKeyFrame(mAnimChop);
TransformKeyFrame* startKf = track->getNodeKeyFrame(0);
Bone* bone = skel->getBone(track->getHandle());
if (bone->getName() == "Spineroot")
{
mSneakStartOffset = startKf->getTranslate() + bone->getInitialPosition();
mSneakEndOffset = oldKf.getTranslate() + bone->getInitialPosition();
mSneakStartOffset.y = mSneakEndOffset.y;
// Adjust spine root relative to new location
newKf->setRotation(oldKf.getRotation());
newKf->setTranslate(oldKf.getTranslate());
newKf->setScale(oldKf.getScale());
}
else
{
newKf->setRotation(startKf->getRotation());
newKf->setTranslate(startKf->getTranslate());
newKf->setScale(startKf->getScale());
}
}
Entity *ent;
Real rotInc = Math::TWO_PI / (float)NUM_JAIQUAS;
Real rot = 0.0f;
for (int i = 0; i < NUM_JAIQUAS; ++i)
{
Quaternion q;
q.FromAngleAxis(Radian(rot), Vector3::UNIT_Y);
mOrientations[i] = q;
mBasePositions[i] = q * Vector3(0,0,-20);
ent = mSceneMgr->createEntity("jaiqua" + StringConverter::toString(i), "jaiqua.mesh");
// Add entity to the scene node
mSceneNode[i] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
mSceneNode[i]->attachObject(ent);
mSceneNode[i]->rotate(q);
mSceneNode[i]->translate(mBasePositions[i]);
Ogre::String oname = "jaiqua-Axis" + StringConverter::toString(i);
Ogre::Vector3 pos(0, 0, 0);
Ogre::Quaternion rotq(Ogre::Quaternion::IDENTITY);
AxisObject axisObj;
Ogre::ManualObject* o = axisObj.createAxis(mSceneMgr, oname, 2);
Bone* bone = ent->getSkeleton()->getBone(i);
Matrix4 boneMat4;
bone->getWorldTransforms(&boneMat4);
Matrix3 boneMat3;
boneMat4.extract3x3Matrix(boneMat3);
Vector3 offsetPos = pos * boneMat3; //得到 旋转以后的原点
Quaternion quat = bone->_getDerivedOrientation().Inverse() * rotq;
ent->attachObjectToBone(bone->getName(), o, quat, offsetPos);
mAnimState[i] = ent->getAnimationState("Sneak");
mAnimState[i]->setEnabled(true);
mAnimState[i]->setLoop(false); // manual loop since translation involved
mAnimationSpeed[i] = Math::RangeRandom(0.5, 1.5);
rot += rotInc;
}
// Give it a little ambience with lights
Light* l;
l = mSceneMgr->createLight("BlueLight");
l->setType(Light::LT_SPOTLIGHT);
l->setPosition(-200,150,-100);
Vector3 dir(-l->getPosition());
dir.normalise();
l->setDirection(dir);
l->setDiffuseColour(0.5, 0.5, 1.0);
l = mSceneMgr->createLight("GreenLight");
l->setType(Light::LT_SPOTLIGHT);
l->setPosition(0,150,-100);
dir = -l->getPosition();
dir.normalise();
l->setDirection(dir);
l->setDiffuseColour(0.5, 1.0, 0.5);
// Position the camera
mCamera->setPosition(100,20,0);
mCamera->lookAt(0,10,0);
// Report whether hardware skinning is enabled or not
Technique* t = ent->getSubEntity(0)->getMaterial()->getBestTechnique();
Pass* p = t->getPass(0);
if (p->hasVertexProgram() && p->getVertexProgram()->isSkeletalAnimationIncluded())
mDebugText = "Hardware skinning is enabled";
else
mDebugText = "Software skinning is enabled";
Plane plane;
plane.normal = Vector3::UNIT_Y;
plane.d = 100;
MeshManager::getSingleton().createPlane("Myplane",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
1500,1500,20,20,true,1,60,60,Vector3::UNIT_Z);
Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
pPlaneEnt->setMaterialName("Examples/Rockwall");
pPlaneEnt->setCastShadows(false);
mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,99,0))->attachObject(pPlaneEnt);
Ogitors::AxisGizmo::createPlaneMesh(mSceneMgr, "FirstPlane");
Ogitors::AxisGizmo::createMesh(mSceneMgr, "FirstAxisMesh");
}
// Create new frame listener
void createFrameListener(void)
{
mFrameListener= new SkeletalAnimationFrameListener(mWindow, mCamera, mDebugText);
mRoot->addFrameListener(mFrameListener);
}
};