diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp
index e85aa9b83..082100b27 100644
--- a/apps/openmw/mwmechanics/actors.cpp
+++ b/apps/openmw/mwmechanics/actors.cpp
@@ -172,16 +172,19 @@ namespace MWMechanics
 
         MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
         if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead())
-            mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle)));
+            mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim, CharState_Idle)));
         else
-            mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Death1)));
+            mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim, CharState_Death1)));
     }
 
     void Actors::removeActor (const MWWorld::Ptr& ptr)
     {
         PtrControllerMap::iterator iter = mActors.find(ptr);
         if(iter != mActors.end())
+        {
+            delete iter->second;
             mActors.erase(iter);
+        }
     }
 
     void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
@@ -189,10 +192,10 @@ namespace MWMechanics
         PtrControllerMap::iterator iter = mActors.find(old);
         if(iter != mActors.end())
         {
-            CharacterController ctrl = iter->second;
+            CharacterController *ctrl = iter->second;
             mActors.erase(iter);
 
-            ctrl.updatePtr(ptr);
+            ctrl->updatePtr(ptr);
             mActors.insert(std::make_pair(ptr, ctrl));
         }
     }
@@ -203,7 +206,10 @@ namespace MWMechanics
         while(iter != mActors.end())
         {
             if(iter->first.getCell()==cellStore)
+            {
+                delete iter->second;
                 mActors.erase(iter++);
+            }
             else
                 ++iter;
         }
@@ -222,8 +228,8 @@ namespace MWMechanics
             {
                 if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead())
                 {
-                    if(iter->second.getState() >= CharState_Death1)
-                        iter->second.setState(CharState_Idle);
+                    if(iter->second->getState() >= CharState_Death1)
+                        iter->second->setState(CharState_Idle);
 
                     updateActor(iter->first, totalDuration);
                     if(iter->first.getTypeName() == typeid(ESM::NPC).name())
@@ -250,10 +256,10 @@ namespace MWMechanics
                     continue;
                 }
 
-                if(iter->second.getState() >= CharState_Death1)
+                if(iter->second->getState() >= CharState_Death1)
                     continue;
 
-                iter->second.setState(CharState_Death1);
+                iter->second->setState(CharState_Death1);
 
                 ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)];
 
@@ -270,7 +276,7 @@ namespace MWMechanics
             for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
             {
                 Movement movement;
-                iter->second.update(duration, movement);
+                iter->second->update(duration, movement);
                 mMovement.push_back(std::make_pair(iter->first, movement));
             }
             MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);
@@ -297,27 +303,27 @@ namespace MWMechanics
     {
         PtrControllerMap::iterator iter = mActors.find(ptr);
         if(iter != mActors.end())
-            iter->second.forceStateUpdate();
+            iter->second->forceStateUpdate();
     }
 
     void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
     {
         PtrControllerMap::iterator iter = mActors.find(ptr);
         if(iter != mActors.end())
-            iter->second.playGroup(groupName, mode, number);
+            iter->second->playGroup(groupName, mode, number);
     }
     void Actors::skipAnimation(const MWWorld::Ptr& ptr)
     {
         PtrControllerMap::iterator iter = mActors.find(ptr);
         if(iter != mActors.end())
-            iter->second.skipAnim();
+            iter->second->skipAnim();
     }
 
     bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
     {
         PtrControllerMap::iterator iter = mActors.find(ptr);
         if(iter != mActors.end())
-            return iter->second.isAnimPlaying(groupName);
+            return iter->second->isAnimPlaying(groupName);
         return false;
     }
 }
diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp
index 386840e3a..1369d783c 100644
--- a/apps/openmw/mwmechanics/actors.hpp
+++ b/apps/openmw/mwmechanics/actors.hpp
@@ -25,7 +25,7 @@ namespace MWMechanics
 {
     class Actors
     {
-        typedef std::map<MWWorld::Ptr,CharacterController> PtrControllerMap;
+        typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
         PtrControllerMap mActors;
 
         MWWorld::PtrMovementList mMovement;
diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp
index 853ffc375..f958b8286 100644
--- a/apps/openmw/mwrender/animation.cpp
+++ b/apps/openmw/mwrender/animation.cpp
@@ -45,6 +45,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL
 
 Animation::Animation(const MWWorld::Ptr &ptr)
     : mPtr(ptr)
+    , mCamera(NULL)
     , mInsert(NULL)
     , mSkelBase(NULL)
     , mAccumRoot(NULL)
@@ -72,8 +73,9 @@ Animation::~Animation()
 
 void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly)
 {
-    OgreAssert(!mInsert, "Object already has a root!");
-    mInsert = node->createChildSceneNode();
+    OgreAssert(mAnimSources.size() == 0, "Setting object root while animation sources are set!");
+    if(!mInsert)
+        mInsert = node->createChildSceneNode();
 
     std::string mdlname = Misc::StringUtils::lowerCase(model);
     std::string::size_type p = mdlname.rfind('\\');
@@ -89,6 +91,9 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
         Misc::StringUtils::toLower(mdlname);
     }
 
+    mSkelBase = NULL;
+    destroyObjectList(mInsert->getCreator(), mObjectRoot);
+
     mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
                                NifOgre::Loader::createObjectBase(mInsert, mdlname));
     if(mObjectRoot.mSkelBase)
@@ -110,7 +115,23 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
         Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
         while(boneiter.hasMoreElements())
             boneiter.getNext()->setManuallyControlled(true);
+
+        // Reattach any objects that have been attached to this one
+        ObjectAttachMap::iterator iter = mAttachedObjects.begin();
+        while(iter != mAttachedObjects.end())
+        {
+            if(!skelinst->hasBone(iter->second))
+                mAttachedObjects.erase(iter++);
+            else
+            {
+                mSkelBase->attachObjectToBone(iter->second, iter->first);
+                iter++;
+            }
+        }
     }
+    else
+        mAttachedObjects.clear();
+
     for(size_t i = 0;i < mObjectRoot.mControllers.size();i++)
     {
         if(mObjectRoot.mControllers[i].getSource().isNull())
@@ -736,4 +757,24 @@ bool Animation::isPriorityActive(int priority) const
     return false;
 }
 
+Ogre::TagPoint *Animation::attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj)
+{
+    Ogre::TagPoint *tag = NULL;
+    Ogre::SkeletonInstance *skel = (mSkelBase ? mSkelBase->getSkeleton() : NULL);
+    if(skel && skel->hasBone(bonename))
+    {
+        tag = mSkelBase->attachObjectToBone(bonename, obj);
+        mAttachedObjects[obj] = bonename;
+    }
+    return tag;
+}
+
+void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
+{
+    ObjectAttachMap::iterator iter = mAttachedObjects.find(obj);
+    if(iter != mAttachedObjects.end())
+        mAttachedObjects.erase(iter);
+    mSkelBase->detachObjectFromBone(obj);
+}
+
 }
diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp
index 31be0fb2a..f87fade55 100644
--- a/apps/openmw/mwrender/animation.hpp
+++ b/apps/openmw/mwrender/animation.hpp
@@ -11,6 +11,7 @@
 
 namespace MWRender
 {
+class Camera;
 
 class Animation
 {
@@ -79,7 +80,10 @@ protected:
     };
     typedef std::map<std::string,AnimState> AnimStateMap;
 
+    typedef std::map<Ogre::MovableObject*,std::string> ObjectAttachMap;
+
     MWWorld::Ptr mPtr;
+    Camera *mCamera;
 
     Ogre::SceneNode *mInsert;
     Ogre::Entity *mSkelBase;
@@ -94,6 +98,8 @@ protected:
 
     Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
 
+    ObjectAttachMap mAttachedObjects;
+
     float mAnimVelocity;
     float mAnimSpeedMult;
 
@@ -131,7 +137,18 @@ protected:
 
     bool handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key);
 
+    /* Sets the root model of the object. If 'baseonly' is true, then any meshes or particle
+     * systems in the model are ignored (useful for NPCs, where only the skeleton is needed for
+     * the root).
+     *
+     * Note that you must make sure all animation sources are cleared before reseting the object
+     * root. All nodes previously retrieved with getNode will also become invalidated.
+     */
     void setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly);
+
+    /* Adds the keyframe controllers in the specified model as a new animation source. Note that
+     * the filename portion of the provided model name will be prepended with 'x', and the .nif
+     * extension will be replaced with .kf. */
     void addAnimSource(const std::string &model);
 
     static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
@@ -199,7 +216,16 @@ public:
 
     virtual void showWeapons(bool showWeapon);
 
+    void setCamera(Camera *cam)
+    { mCamera = cam; }
+
     Ogre::Node *getNode(const std::string &name);
+
+    // Attaches the given object to a bone on this object's base skeleton. If the bone doesn't
+    // exist, the object isn't attached and NULL is returned. The returned TagPoint is only
+    // valid until the next setObjectRoot call.
+    Ogre::TagPoint *attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj);
+    void detachObjectFromBone(Ogre::MovableObject *obj);
 };
 
 }
diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp
index e71e694f9..d226c577c 100644
--- a/apps/openmw/mwrender/camera.cpp
+++ b/apps/openmw/mwrender/camera.cpp
@@ -3,6 +3,7 @@
 #include <OgreSceneNode.h>
 #include <OgreCamera.h>
 #include <OgreSceneManager.h>
+#include <OgreTagPoint.h>
 
 #include "../mwbase/environment.hpp"
 #include "../mwbase/windowmanager.hpp"
@@ -57,10 +58,10 @@ namespace MWRender
 
         Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X);
         if (!mVanity.enabled && !mPreviewMode) {
-            mCameraNode->setOrientation(xr);
+            mCamera->getParentNode()->setOrientation(xr);
         } else {
             Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z);
-            mCameraNode->setOrientation(zr * xr);
+            mCamera->getParentNode()->setOrientation(zr * xr);
         }
     }
 
@@ -112,14 +113,12 @@ namespace MWRender
     void Camera::toggleViewMode()
     {
         mFirstPersonView = !mFirstPersonView;
-        mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
-                                                  NpcAnimation::VM_Normal);
+        processViewChange();
+
         if (mFirstPersonView) {
             mCamera->setPosition(0.f, 0.f, 0.f);
-            setLowHeight(false);
         } else {
             mCamera->setPosition(0.f, 0.f, mCameraDistance);
-            setLowHeight(true);
         }
     }
     
@@ -139,21 +138,16 @@ namespace MWRender
             return true;
         mVanity.enabled = enable;
 
-        mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
-                                                  NpcAnimation::VM_Normal);
+        processViewChange();
 
         float offset = mPreviewCam.offset;
         Ogre::Vector3 rot(0.f, 0.f, 0.f);
         if (mVanity.enabled) {
             rot.x = Ogre::Degree(-30.f).valueRadians();
             mMainCam.offset = mCamera->getPosition().z;
-
-            setLowHeight(true);
         } else {
             rot.x = getPitch();
             offset = mMainCam.offset;
-
-            setLowHeight(!mFirstPersonView);
         }
         rot.z = getYaw();
 
@@ -169,20 +163,15 @@ namespace MWRender
             return;
 
         mPreviewMode = enable;
-        mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
-                                                  NpcAnimation::VM_Normal);
+        processViewChange();
 
         float offset = mCamera->getPosition().z;
         if (mPreviewMode) {
             mMainCam.offset = offset;
             offset = mPreviewCam.offset;
-
-            setLowHeight(true);
         } else {
             mPreviewCam.offset = offset;
             offset = mMainCam.offset;
-
-            setLowHeight(!mFirstPersonView);
         }
 
         mCamera->setPosition(0.f, 0.f, offset);
@@ -283,26 +272,48 @@ namespace MWRender
         // If we're switching to a new NpcAnimation, ensure the old one is
         // using a normal view mode
         if(mAnimation && mAnimation != anim)
+        {
             mAnimation->setViewMode(NpcAnimation::VM_Normal);
+            mAnimation->setCamera(NULL);
+            mAnimation->detachObjectFromBone(mCamera);
+        }
         mAnimation = anim;
-        mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
-                                                  NpcAnimation::VM_Normal);
+        mAnimation->setCamera(this);
+
+        processViewChange();
     }
 
-    void Camera::setHeight(float height)
+    void Camera::processViewChange()
     {
-        mHeight = height;
-        mCameraNode->setPosition(0.f, 0.f, mHeight);
+        mAnimation->detachObjectFromBone(mCamera);
+        mCamera->detachFromParent();
+
+        if(isFirstPerson())
+        {
+            mAnimation->setViewMode(NpcAnimation::VM_FirstPerson);
+            Ogre::TagPoint *tag = mAnimation->attachObjectToBone("Head", mCamera);
+            tag->setInheritOrientation(false);
+        }
+        else
+        {
+            mAnimation->setViewMode(NpcAnimation::VM_Normal);
+            mCameraNode->attachObject(mCamera);
+        }
     }
 
     float Camera::getHeight()
     {
-        return mHeight * mTrackingPtr.getRefData().getBaseNode()->getScale().z;
+        if(mCamera->isParentTagPoint())
+        {
+            Ogre::TagPoint *tag = static_cast<Ogre::TagPoint*>(mCamera->getParentNode());
+            return tag->_getFullLocalTransform().getTrans().z;
+        }
+        return mCamera->getParentNode()->getPosition().z;
     }
 
     bool Camera::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera)
     {
-        mCamera->getParentSceneNode ()->needUpdate(true);
+        mCamera->getParentSceneNode()->needUpdate(true);
         camera = mCamera->getRealPosition();
         player = mTrackingPtr.getRefData().getBaseNode()->getPosition();
 
@@ -325,15 +336,6 @@ namespace MWRender
         mFreeLook = enable;
     }
 
-    void Camera::setLowHeight(bool low)
-    {
-        if (low) {
-            mCameraNode->setPosition(0.f, 0.f, mHeight * 0.85);
-        } else {
-            mCameraNode->setPosition(0.f, 0.f, mHeight);
-        }
-    }
-
     bool Camera::isVanityOrPreviewModeEnabled()
     {
         return mPreviewMode || mVanity.enabled;
diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp
index ad5e35f93..3418efcc9 100644
--- a/apps/openmw/mwrender/camera.hpp
+++ b/apps/openmw/mwrender/camera.hpp
@@ -46,8 +46,6 @@ namespace MWRender
         /// Updates sound manager listener data
         void updateListener();
 
-        void setLowHeight(bool low = true);
-
     public:
         Camera(Ogre::Camera *camera);
         ~Camera();
@@ -80,6 +78,8 @@ namespace MWRender
         bool isFirstPerson() const
         { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
 
+        void processViewChange();
+
         void update(float duration);
 
         /// Set camera distance for current mode. Don't work on 1st person view.
@@ -93,7 +93,6 @@ namespace MWRender
 
         void setAnimation(NpcAnimation *anim);
 
-        void setHeight(float height);
         float getHeight();
 
         /// Stores player and camera world positions in passed arguments
diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp
index e9ecedc55..c6e6e158e 100644
--- a/apps/openmw/mwrender/characterpreview.cpp
+++ b/apps/openmw/mwrender/characterpreview.cpp
@@ -44,9 +44,14 @@ namespace MWRender
     {
         mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
 
-        /// \todo Read the fallback values from INIImporter (Inventory:Directional*)
+        // This is a dummy light to turn off shadows without having to use a separate set of shaders
         Ogre::Light* l = mSceneMgr->createLight();
         l->setType (Ogre::Light::LT_DIRECTIONAL);
+        l->setDiffuseColour (Ogre::ColourValue(0,0,0));
+
+        /// \todo Read the fallback values from INIImporter (Inventory:Directional*)
+        l = mSceneMgr->createLight();
+        l->setType (Ogre::Light::LT_DIRECTIONAL);
         l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3));
         l->setDiffuseColour (Ogre::ColourValue(1,1,1));
 
diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp
index b5f2ea031..f2df5ccd5 100644
--- a/apps/openmw/mwrender/npcanimation.cpp
+++ b/apps/openmw/mwrender/npcanimation.cpp
@@ -14,6 +14,7 @@
 #include "../mwbase/mechanicsmanager.hpp"
 
 #include "renderconst.hpp"
+#include "camera.hpp"
 
 
 namespace MWRender
@@ -98,17 +99,22 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
     Misc::StringUtils::toLower(mBodyPrefix);
 
     bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
-    std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
+    std::string smodel = (viewMode != VM_FirstPerson) ?
+                         (!isBeast ? "meshes\\base_anim.nif"     : "meshes\\base_animkna.nif") :
+                         (!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
     setObjectRoot(node, smodel, true);
 
-    addAnimSource(smodel);
-    if(mBodyPrefix.find("argonian") != std::string::npos)
-        addAnimSource("meshes\\argonian_swimkna.nif");
-    else if(!mNpc->isMale() && !isBeast)
-        addAnimSource("meshes\\base_anim_female.nif");
-    if(mNpc->mModel.length() > 0)
-        addAnimSource("meshes\\"+mNpc->mModel);
-    if(mViewMode == VM_FirstPerson)
+    if(mViewMode != VM_FirstPerson)
+    {
+        addAnimSource(smodel);
+        if(mBodyPrefix.find("argonian") != std::string::npos)
+            addAnimSource("meshes\\argonian_swimkna.nif");
+        else if(!mNpc->isMale() && !isBeast)
+            addAnimSource("meshes\\base_anim_female.nif");
+        if(mNpc->mModel.length() > 0)
+            addAnimSource("meshes\\"+mNpc->mModel);
+    }
+    else
     {
         /* A bit counter-intuitive, but unlike third-person anims, it seems
          * beast races get both base_anim.1st.nif and base_animkna.1st.nif.
@@ -128,20 +134,28 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
     assert(viewMode != VM_HeadOnly);
     mViewMode = viewMode;
 
+    clearAnimSources();
+
     const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
     const ESM::Race *race = store.get<ESM::Race>().find(mNpc->mRace);
-    bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
-    std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
 
-    clearAnimSources();
-    addAnimSource(smodel);
-    if(mBodyPrefix.find("argonian") != std::string::npos)
-        addAnimSource("meshes\\argonian_swimkna.nif");
-    else if(!mNpc->isMale() && !isBeast)
-        addAnimSource("meshes\\base_anim_female.nif");
-    if(mNpc->mModel.length() > 0)
-        addAnimSource("meshes\\"+mNpc->mModel);
-    if(mViewMode == VM_FirstPerson)
+    bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
+    std::string smodel = (viewMode != VM_FirstPerson) ?
+                         (!isBeast ? "meshes\\base_anim.nif"     : "meshes\\base_animkna.nif") :
+                         (!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
+    setObjectRoot(mInsert->getParentSceneNode(), smodel, true);
+
+    if(mViewMode != VM_FirstPerson)
+    {
+        addAnimSource(smodel);
+        if(mBodyPrefix.find("argonian") != std::string::npos)
+            addAnimSource("meshes\\argonian_swimkna.nif");
+        else if(!mNpc->isMale() && !isBeast)
+            addAnimSource("meshes\\base_anim_female.nif");
+        if(mNpc->mModel.length() > 0)
+            addAnimSource("meshes\\"+mNpc->mModel);
+    }
+    else
     {
         /* A bit counter-intuitive, but unlike third-person anims, it seems
          * beast races get both base_anim.1st.nif and base_animkna.1st.nif.
@@ -197,19 +211,11 @@ void NpcAnimation::updateParts(bool forceupdate)
     if(!forceupdate)
         return;
 
-    /* FIXME: Remove this once we figure out how to show what in first-person */
-    if(mViewMode == VM_FirstPerson)
-    {
-        for(size_t i = 0;i < slotlistsize;i++)
-            this->*slotlist[i].mPart = inv.getSlot(slotlist[i].mSlot);
-        return;
-    }
-
     for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++)
     {
-        MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].mSlot);
+        MWWorld::ContainerStoreIterator store = inv.getSlot(slotlist[i].mSlot);
 
-        this->*slotlist[i].mPart = iter;
+        this->*slotlist[i].mPart = store;
         removePartGroup(slotlist[i].mSlot);
 
         if(this->*slotlist[i].mPart == inv.end())
@@ -219,7 +225,6 @@ void NpcAnimation::updateParts(bool forceupdate)
             removeIndividualPart(ESM::PRT_Hair);
 
         int prio = 1;
-        MWWorld::ContainerStoreIterator &store = this->*slotlist[i].mPart;
         if(store->getTypeName() == typeid(ESM::Clothing).name())
         {
             prio = ((slotlist[i].mBasePriority+1)<<1) + 0;
@@ -279,32 +284,34 @@ void NpcAnimation::updateParts(bool forceupdate)
     std::pair<std::string, int> thisCombination = std::make_pair(race, flags);
     if (sRaceMapping.find(thisCombination) == sRaceMapping.end())
     {
-        static std::map<int, int> bodypartMap;
-        if(bodypartMap.size() == 0)
+        typedef std::multimap<ESM::BodyPart::MeshPart,ESM::PartReferenceType> BodyPartMapType;
+        static BodyPartMapType sBodyPartMap;
+        if(sBodyPartMap.size() == 0)
         {
-            bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck;
-            bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest;
-            bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin;
-            bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand;
-            bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand;
-            bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist;
-            bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist;
-            bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm;
-            bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm;
-            bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm;
-            bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm;
-            bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot;
-            bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot;
-            bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle;
-            bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle;
-            bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee;
-            bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee;
-            bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg;
-            bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg;
-            bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail;
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Neck, ESM::PRT_Neck));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Groin, ESM::PRT_Groin));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_RHand));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_LHand));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_RFoot));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_LFoot));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_RKnee));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_LKnee));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg));
+            sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail));
         }
 
-        sRaceMapping[thisCombination].resize(ESM::PRT_Count, NULL);
+        std::vector<const ESM::BodyPart*> &parts = sRaceMapping[thisCombination];
+        parts.resize(ESM::PRT_Count, NULL);
 
         const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
         const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
@@ -325,29 +332,55 @@ void NpcAnimation::updateParts(bool forceupdate)
                     && bodypart.mId[bodypart.mId.size()-3] == '1'
                     && bodypart.mId[bodypart.mId.size()-2] == 's'
                     && bodypart.mId[bodypart.mId.size()-1] == 't';
-            if (firstPerson != (mViewMode == VM_FirstPerson))
+            if(firstPerson != (mViewMode == VM_FirstPerson))
+            {
+                if(mViewMode == VM_FirstPerson && (bodypart.mData.mPart == ESM::BodyPart::MP_Hand ||
+                                                   bodypart.mData.mPart == ESM::BodyPart::MP_Wrist ||
+                                                   bodypart.mData.mPart == ESM::BodyPart::MP_Forearm ||
+                                                   bodypart.mData.mPart == ESM::BodyPart::MP_Upperarm))
+                {
+                    /* Allow 3rd person skins as a fallback for the arms if 1st person is missing. */
+                    BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
+                    while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
+                    {
+                        if(!parts[bIt->second])
+                            parts[bIt->second] = &*it;
+                        bIt++;
+                    }
+                }
                 continue;
-            for (std::map<int, int>::iterator bIt = bodypartMap.begin(); bIt != bodypartMap.end(); ++bIt )
-                if (bIt->second == bodypart.mData.mPart)
-                    sRaceMapping[thisCombination][bIt->first] = &*it;
+            }
+            BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
+            while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
+            {
+                parts[bIt->second] = &*it;
+                bIt++;
+            }
         }
     }
 
-    for (int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
+    const std::vector<const ESM::BodyPart*> &parts = sRaceMapping[thisCombination];
+    for(int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
     {
-        const ESM::BodyPart* bodypart = sRaceMapping[thisCombination][part];
-        if (mPartPriorities[part] < 1 && bodypart)
-            addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
+        if(mPartPriorities[part] < 1)
+        {
+            const ESM::BodyPart* bodypart = parts[part];
+            if(bodypart)
+                addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
+        }
     }
 }
 
 NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
 {
     NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
-    setRenderProperties(objects, mVisibilityFlags, RQG_Main, RQG_Alpha);
+    setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha);
 
     for(size_t i = 0;i < objects.mEntities.size();i++)
-        objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
+    {
+        Ogre::Entity *ent = objects.mEntities[i];
+        ent->getUserObjectBindings().setUserAny(Ogre::Any(group));
+    }
     for(size_t i = 0;i < objects.mParticles.size();i++)
         objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
 
@@ -382,6 +415,13 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
     Ogre::Vector3 ret = Animation::runAnimation(timepassed);
 
     Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
+    if(mViewMode == VM_FirstPerson && mCamera)
+    {
+        float pitch = mCamera->getPitch();
+        Ogre::Node *node = baseinst->getBone("Bip01 Neck");
+        node->pitch(Ogre::Radian(pitch*0.75f), Ogre::Node::TS_WORLD);
+    }
+
     for(size_t i = 0;i < sPartListSize;i++)
     {
         Ogre::Entity *ent = mObjectParts[i].mSkelBase;
@@ -458,9 +498,31 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
     {
         const ESM::BodyPart *bodypart = 0;
         if(!mNpc->isMale() && !part->mFemale.empty())
+        {
             bodypart = partStore.search(part->mFemale+ext);
+            if(!bodypart && mViewMode == VM_FirstPerson)
+            {
+                bodypart = partStore.search(part->mFemale);
+                if(bodypart && !(bodypart->mData.mPart == ESM::BodyPart::MP_Hand ||
+                                 bodypart->mData.mPart == ESM::BodyPart::MP_Wrist ||
+                                 bodypart->mData.mPart == ESM::BodyPart::MP_Forearm ||
+                                 bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm))
+                    bodypart = NULL;
+            }
+        }
         if(!bodypart && !part->mMale.empty())
+        {
             bodypart = partStore.search(part->mMale+ext);
+            if(!bodypart && mViewMode == VM_FirstPerson)
+            {
+                bodypart = partStore.search(part->mMale);
+                if(bodypart && !(bodypart->mData.mPart == ESM::BodyPart::MP_Hand ||
+                                 bodypart->mData.mPart == ESM::BodyPart::MP_Wrist ||
+                                 bodypart->mData.mPart == ESM::BodyPart::MP_Forearm ||
+                                 bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm))
+                    bodypart = NULL;
+            }
+        }
 
         if(bodypart)
             addOrReplaceIndividualPart(part->mPart, group, priority, "meshes\\"+bodypart->mModel);
@@ -472,8 +534,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
 void NpcAnimation::showWeapons(bool showWeapon)
 {
     mShowWeapons = showWeapon;
-    if(showWeapon &&
-       mViewMode != VM_FirstPerson/* FIXME: Remove this once first-person bodies work */)
+    if(showWeapon)
     {
         MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
         mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp
index 1d2cdf1ea..44599ebee 100644
--- a/apps/openmw/mwrender/renderconst.hpp
+++ b/apps/openmw/mwrender/renderconst.hpp
@@ -59,6 +59,9 @@ enum VisibilityFlags
     // overlays, we only want these on the main render target
     RV_Overlay = 1024,
 
+    // First person meshes do not cast shadows
+    RV_FirstPerson = 2048,
+
     RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water
 };