mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 12:56:38 +00:00 
			
		
		
		
	Movement solver tweaks
1) As much as I dislike it, upping the collision margin from 0.1 to 0.2 fixes bugs, particularly involving walking into upwards-slanted walls. 2) There were still some problems involving acute crevices/seams; they were using the adjusted instead of unadjusted normal, and also they need to bypass the don't-slide-upwards check to prevent (see #6379) 3) The move-away-from-what-we-just-hit code needs to run always, not just on non-initial iterations. No idea why I did it this way before. 4) Force bullet to give actor boxes a tiny collision margin of 0.001 instead of the default 0.04. I can't tell whether this is actually working or not, but it should reduce unexplained weirdness. 5) A piece of code that was meant to prevent bugs by short-circuiting the movement solver if its direction changed more than 180 degrees actually caused problems instead of preventing them, so I deleted it.
This commit is contained in:
		
							parent
							
								
									b6d2c57de2
								
							
						
					
					
						commit
						49d2daee6a
					
				
					 3 changed files with 17 additions and 12 deletions
				
			
		|  | @ -59,6 +59,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic | |||
|     mRotationallyInvariant = (mMeshTranslation.x() == 0.0 && mMeshTranslation.y() == 0.0) && std::fabs(mOriginalHalfExtents.x() - mOriginalHalfExtents.y()) < 2.2; | ||||
| 
 | ||||
|     mConvexShape = static_cast<btConvexShape*>(mShape.get()); | ||||
|     mConvexShape->setMargin(0.001); // make sure bullet isn't using the huge default convex shape margin of 0.04
 | ||||
| 
 | ||||
|     mCollisionObject = std::make_unique<btCollisionObject>(); | ||||
|     mCollisionObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ namespace MWPhysics | |||
|     // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
 | ||||
|     static constexpr int sMaxIterations = 8; | ||||
|     // Allows for more precise movement solving without getting stuck or snagging too easily.
 | ||||
|     static constexpr float sCollisionMargin = 0.1f; | ||||
|     static constexpr float sCollisionMargin = 0.2f; | ||||
|     // Allow for a small amount of penetration to prevent numerical precision issues from causing the "unstuck"ing code to run unnecessarily
 | ||||
|     // Currently set to 0 because having the "unstuck"ing code run whenever possible prevents some glitchy snagging issues
 | ||||
|     static constexpr float sAllowedPenetration = 0.0f; | ||||
|  |  | |||
|  | @ -252,6 +252,8 @@ namespace MWPhysics | |||
|                 remainingTime *= (1.0f-tracer.mFraction); | ||||
| 
 | ||||
|                 auto planeNormal = tracer.mPlaneNormal; | ||||
|                 // need to know the unadjusted normal to handle certain types of seams properly
 | ||||
|                 const auto origPlaneNormal = planeNormal; | ||||
| 
 | ||||
|                 // If we touched the ground this frame, and whatever we ran into is a wall of some sort,
 | ||||
|                 // pretend that its collision normal is pointing horizontally
 | ||||
|  | @ -275,10 +277,11 @@ namespace MWPhysics | |||
|                 bool usedSeamLogic = false; | ||||
| 
 | ||||
|                 // check for the current and previous collision planes forming an acute angle; slide along the seam if they do
 | ||||
|                 // for this, we want to use the original plane normal, or else certain types of geometry will snag
 | ||||
|                 if(numTimesSlid > 0) | ||||
|                 { | ||||
|                     auto dotA = lastSlideNormal * planeNormal; | ||||
|                     auto dotB = lastSlideNormalFallback * planeNormal; | ||||
|                     auto dotA = lastSlideNormal * origPlaneNormal; | ||||
|                     auto dotB = lastSlideNormalFallback * origPlaneNormal; | ||||
|                     if(numTimesSlid <= 1) // ignore fallback normal if this is only the first or second slide
 | ||||
|                         dotB = 1.0; | ||||
|                     if(dotA <= 0.0 || dotB <= 0.0) | ||||
|  | @ -291,14 +294,14 @@ namespace MWPhysics | |||
|                             lastSlideNormal = lastSlideNormalFallback; | ||||
|                         } | ||||
| 
 | ||||
|                         auto constraintVector = bestNormal ^ planeNormal; // cross product
 | ||||
|                         auto constraintVector = bestNormal ^ origPlaneNormal; // cross product
 | ||||
|                         if(constraintVector.length2() > 0) // only if it's not zero length
 | ||||
|                         { | ||||
|                             constraintVector.normalize(); | ||||
|                             newVelocity = project(velocity, constraintVector); | ||||
| 
 | ||||
|                             // version of surface rejection for acute crevices/seams
 | ||||
|                             auto averageNormal = bestNormal + planeNormal; | ||||
|                             auto averageNormal = bestNormal + origPlaneNormal; | ||||
|                             averageNormal.normalize(); | ||||
|                             tracer.doTrace(actor.mCollisionObject, newPosition, newPosition + averageNormal*(sCollisionMargin*2.0), collisionWorld); | ||||
|                             newPosition = (newPosition + tracer.mEndPos)/2.0; | ||||
|  | @ -309,27 +312,28 @@ namespace MWPhysics | |||
|                 } | ||||
|                 // otherwise just keep the normal vector rejection
 | ||||
| 
 | ||||
|                 // if this isn't the first iteration, or if the first iteration is also the last iteration,
 | ||||
|                 // move away from the collision plane slightly, if possible
 | ||||
|                 // this reduces getting stuck in some concave geometry, like the gaps above the railings in some ald'ruhn buildings
 | ||||
|                 // this is different from the normal collision margin, because the normal collision margin is along the movement path,
 | ||||
|                 // but this is along the collision normal
 | ||||
|                 if(!usedSeamLogic && (iterations > 0 || remainingTime < 0.01f)) | ||||
|                 if(!usedSeamLogic) | ||||
|                 { | ||||
|                     tracer.doTrace(actor.mCollisionObject, newPosition, newPosition + planeNormal*(sCollisionMargin*2.0), collisionWorld); | ||||
|                     newPosition = (newPosition + tracer.mEndPos)/2.0; | ||||
|                 } | ||||
| 
 | ||||
|                 // Do not allow sliding up steep slopes if there is gravity.
 | ||||
|                 if (newPosition.z() >= swimlevel && !actor.mFlying && !isWalkableSlope(planeNormal)) | ||||
|                 // The purpose of this is to prevent air control from letting you slide up tall, unwalkable slopes.
 | ||||
|                 // For that purpose, it is not necessary to do it when trying to slide along acute seams/crevices (i.e. usedSeamLogic)
 | ||||
|                 // and doing so would actually break air control in some situations where vanilla allows air control.
 | ||||
|                 // Vanilla actually allows you to slide up slopes as long as you're in the "walking" animation, which can be true even
 | ||||
|                 // in the air, so allowing this for seams isn't a compatibility break.
 | ||||
|                 if (newPosition.z() >= swimlevel && !actor.mFlying && !isWalkableSlope(planeNormal) && !usedSeamLogic) | ||||
|                     newVelocity.z() = std::min(newVelocity.z(), velocity.z()); | ||||
| 
 | ||||
|                 if (newVelocity * origVelocity <= 0.0f) | ||||
|                     break; | ||||
| 
 | ||||
|                 numTimesSlid += 1; | ||||
|                 lastSlideNormalFallback = lastSlideNormal; | ||||
|                 lastSlideNormal = planeNormal; | ||||
|                 lastSlideNormal = origPlaneNormal; | ||||
|                 velocity = newVelocity; | ||||
|             } | ||||
|         } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue