diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp
index 450889eb2..95bc429e3 100644
--- a/apps/openmw/mwclass/creature.cpp
+++ b/apps/openmw/mwclass/creature.cpp
@@ -774,7 +774,7 @@ namespace MWClass
         return ref->mBase->mAiData.mFight;
     }
 
-    void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale) const
+    void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool /* rendering */) const
     {
         MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
         scale *= ref->mBase->mScale;
diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp
index c4ea09255..55127eefc 100644
--- a/apps/openmw/mwclass/creature.hpp
+++ b/apps/openmw/mwclass/creature.hpp
@@ -133,7 +133,8 @@ namespace MWClass
 
             virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const;
 
-            virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const;
+            virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const;
+            /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh
     };
 }
 
diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp
index 9fa2cc603..5679dc3e9 100644
--- a/apps/openmw/mwclass/npc.cpp
+++ b/apps/openmw/mwclass/npc.cpp
@@ -1012,8 +1012,12 @@ namespace MWClass
                 + shield;
     }
 
-    void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale) const
+    void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale, bool rendering) const
     {
+        if (!rendering)
+            return; // collision meshes are not scaled based on race height
+                    // having the same collision extents for all races makes the environments easier to test
+
         MWWorld::LiveCellRef<ESM::NPC> *ref =
             ptr.get<ESM::NPC>();
 
diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp
index d919131db..c2d2ca8fa 100644
--- a/apps/openmw/mwclass/npc.hpp
+++ b/apps/openmw/mwclass/npc.hpp
@@ -109,7 +109,8 @@ namespace MWClass
             /// \param actor Actor that is resposible for the ID being applied to \a ptr.
             /// \return Any effect?
 
-            virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale) const;
+            virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool rendering) const;
+            /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh
 
             virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const;
             ///< Inform actor \a ptr that a skill use has succeeded.
diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp
index 94d93e7d7..a681c7945 100644
--- a/apps/openmw/mwphysics/actor.cpp
+++ b/apps/openmw/mwphysics/actor.cpp
@@ -110,12 +110,14 @@ void Actor::updateScale()
     float scale = mPtr.getCellRef().getScale();
     osg::Vec3f scaleVec(scale,scale,scale);
 
-    if (!mPtr.getClass().isNpc())
-        mPtr.getClass().adjustScale(mPtr, scaleVec);
-
+    mPtr.getClass().adjustScale(mPtr, scaleVec, false);
     mScale = scaleVec;
     mShape->setLocalScaling(toBullet(mScale));
 
+    scaleVec = osg::Vec3f(scale,scale,scale);
+    mPtr.getClass().adjustScale(mPtr, scaleVec, true);
+    mRenderingScale = scaleVec;
+
     updatePosition();
 }
 
@@ -124,6 +126,11 @@ osg::Vec3f Actor::getHalfExtents() const
     return osg::componentMultiply(mHalfExtents, mScale);
 }
 
+osg::Vec3f Actor::getRenderingHalfExtents() const
+{
+    return osg::componentMultiply(mHalfExtents, mRenderingScale);
+}
+
 void Actor::setInertialForce(const osg::Vec3f &force)
 {
     mForce = force;
diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp
index 7a12f549d..a4afa48a1 100644
--- a/apps/openmw/mwphysics/actor.hpp
+++ b/apps/openmw/mwphysics/actor.hpp
@@ -66,10 +66,17 @@ namespace MWPhysics
         void updatePosition();
 
         /**
-         * Returns the (scaled) half extents
+         * Returns the half extents of the collision body (scaled according to collision scale)
          */
         osg::Vec3f getHalfExtents() const;
 
+        /**
+         * Returns the half extents of the collision body (scaled according to rendering scale)
+         * @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape,
+         * most likely to make environment collision testing easier. However in some cases (swimming level) we want the actual scale.
+         */
+        osg::Vec3f getRenderingHalfExtents() const;
+
         /**
          * Sets the current amount of inertial force (incl. gravity) affecting this physic actor
          */
@@ -118,6 +125,7 @@ namespace MWPhysics
         osg::Quat mRotation;
 
         osg::Vec3f mScale;
+        osg::Vec3f mRenderingScale;
         osg::Vec3f mPosition;
 
         osg::Vec3f mForce;
diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp
index e666161da..80a63bf1b 100644
--- a/apps/openmw/mwphysics/physicssystem.cpp
+++ b/apps/openmw/mwphysics/physicssystem.cpp
@@ -261,7 +261,7 @@ namespace MWPhysics
 
             static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
                     .find("fSwimHeightScale")->getFloat();
-            float swimlevel = waterlevel + halfExtents.z() - (halfExtents.z() * 2 * fSwimHeightScale);
+            float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale);
 
             ActorTracer tracer;
             osg::Vec3f inertia = physicActor->getInertialForce();
@@ -878,6 +878,15 @@ namespace MWPhysics
             return osg::Vec3f();
     }
 
+    osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor)
+    {
+        Actor* physactor = getActor(actor);
+        if (physactor)
+            return physactor->getRenderingHalfExtents();
+        else
+            return osg::Vec3f();
+    }
+
     class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback
     {
     public:
diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp
index db8da2886..6f38653c8 100644
--- a/apps/openmw/mwphysics/physicssystem.hpp
+++ b/apps/openmw/mwphysics/physicssystem.hpp
@@ -110,6 +110,9 @@ namespace MWPhysics
             /// Get physical half extents (scaled) of the given actor.
             osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor);
 
+            /// @see MWPhysics::Actor::getRenderingHalfExtents
+            osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor);
+
             /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
             /// be overwritten. Valid until the next call to applyQueuedMovement.
             void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity);
diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp
index 93afeda25..eb950ea79 100644
--- a/apps/openmw/mwrender/characterpreview.cpp
+++ b/apps/openmw/mwrender/characterpreview.cpp
@@ -287,7 +287,7 @@ namespace MWRender
     void InventoryPreview::onSetup()
     {
         osg::Vec3f scale (1.f, 1.f, 1.f);
-        mCharacter.getClass().adjustScale(mCharacter, scale);
+        mCharacter.getClass().adjustScale(mCharacter, scale, true);
 
         mNode->setScale(scale);
 
diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp
index 4c73c603b..30fd42527 100644
--- a/apps/openmw/mwworld/class.cpp
+++ b/apps/openmw/mwworld/class.cpp
@@ -287,7 +287,7 @@ namespace MWWorld
         return "";
     }
 
-    void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const
+    void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const
     {
     }
 
diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp
index 1157db670..b2d3453af 100644
--- a/apps/openmw/mwworld/class.hpp
+++ b/apps/openmw/mwworld/class.hpp
@@ -258,7 +258,8 @@ namespace MWWorld
             virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
             ///< @return the number of enchantment points available for possible enchanting
 
-            virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const;
+            virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const;
+            /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh
 
             virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
             ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices
diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp
index 459b3b6ca..33e2ba17c 100644
--- a/apps/openmw/mwworld/scene.cpp
+++ b/apps/openmw/mwworld/scene.cpp
@@ -72,7 +72,7 @@ namespace
         {
             float scale = ptr.getCellRef().getScale();
             osg::Vec3f scaleVec (scale, scale, scale);
-            ptr.getClass().adjustScale(ptr, scaleVec);
+            ptr.getClass().adjustScale(ptr, scaleVec, true);
             rendering.scaleObject(ptr, scaleVec);
         }
     }
diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp
index be86987e8..17118e169 100644
--- a/apps/openmw/mwworld/worldimp.cpp
+++ b/apps/openmw/mwworld/worldimp.cpp
@@ -1969,7 +1969,7 @@ namespace MWWorld
     {
         osg::Vec3f pos (object.getRefData().getPosition().asVec3());
 
-        pos.z() += heightRatio*2*mPhysics->getHalfExtents(object).z();
+        pos.z() += heightRatio*2*mPhysics->getRenderingHalfExtents(object).z();
 
         return isUnderwater(object.getCell(), pos);
     }