Height Field Collision Issue

Report any bugs here and we'll post fixes

Moderators: Sascha Willems, Thomas

Re: Height Field Collision Issue

Postby Julio Jerez » Tue Feb 01, 2022 1:46 pm

for my first check, I made the procedural to be a collision tree, by doing this.

//#define D_USE_PORDEDURAL_COLLISION

the glitch is still there, but the behavior is quite different, and that a problem.
I will check that first.

then I will check how is act when use the convex hull.
they all have to produce the same behavior, whether it is right or wrong, it must be consistent.
so I will investigate that tonight.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Julio Jerez » Tue Feb 01, 2022 1:56 pm

actually, the mesh does behave the same, so that's good.

edit:
the bug does happen with both convex and compound that only has that convex, but one is more pronounce than the other, and that's inconsistent.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Julio Jerez » Tue Feb 01, 2022 3:12 pm

oh, I think I found the bug.

do not do anything yet, the bug is a bad assumption that in made class ndShapeConvexPolygon

I assumed that when a face was inside the colling shape aabb, it did not need to build a convex cap for the support vertex. This worked in my test because, I was always checking with wheel which tend to be small.

the convex cap are generated when a face intersected the aabb of the colliding shape.

when you tested with a box, the aabb of the box intersected the faces, so that works but the convex shape is bigger so the mesh polygon at random sometime intersect and sometime does not. If it fail, them it could produce and edge normal the would be right for the face if it was not part of a convex surface.

the solution is to always build the convex cap.
I hate when assumptions make something marginally better and them they have a way to bite you in the but.

It is not a big deal, all the functionality is there, I just need to add the extra logic, I will fix tonight.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Julio Jerez » Tue Feb 01, 2022 6:02 pm

ok, if you sync, it should work now.
I run very smooth in the demo with all permutation of shapes the demo allows.

I set so that you can see in your own demo how the contacts move under the shape when the hit some edges.
But this does not seems to affect your script than moves tha car, the point is that now you can experiment with wheel contacts if you want, but not to work around a bug.

I really like your implementation of the lower LOD AI car, this can populate a complex city with few hundred cars all acting somewhat realistically with the environment and not taxing the system. Very clever.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Esharc » Wed Feb 02, 2022 10:16 am

I wish I had good news for you today Julio, I wish I could say that we can move on from this bug.

But I am still getting it on my side. I at first thought there my be something wrong with the syncing on my side. But I made sure and deleted everything and started over. I do not see it happing in the Sandbox with the procedural mesh or the ndShapeStatic_bvh. But both of them do the same in my tests. It does happen on the height field in the Sandbox, if I have a small height field that follows the AI vehicle.

I am trying to figure out now what can possible be different. But I have not found anything yet. I will keep investigating, and I want to see how it works if I add spheres to the shape as well for the wheels.

I hope to have better new tomorrow
Esharc
 
Posts: 120
Joined: Tue Jan 10, 2017 5:23 am
Location: South Africa

Re: Height Field Collision Issue

Postby Julio Jerez » Wed Feb 02, 2022 11:01 am

So not in the sand box, bit happens in you app.

On the engine side it doe not matter if it is heighfield, tree, or procedural.

And it seem now by what you say tha the one difference is that the height are different.
Or are you saying that is happens even in a flat surface?

Meantime, I will add some random elevation to the demo, to see if that recreate the problem in the sand box.

Please see if you can change the test so that repro what you are getting now.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Julio Jerez » Wed Feb 02, 2022 11:31 am

Esharc wrote:It does happen on the height field in the Sandbox, if I have a small height field that follows the AI vehicle.

What does this mean, changing direction variables elevations of the height data?
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Esharc » Wed Feb 02, 2022 1:36 pm

Yeah not in the Sandbox, but in our app.

I update the height field position as the AI vehicle moves. This is how we are currently doing it in our app. To change to the procedural grid is going to be a big change in our system, and I would like to keep it as it is. But if it will be better with the procedural then I will see about changing it. Using the tree will not work since the terrain is too big to have the whole terrain in one collision mesh.

Here is the code that I added to use the height field and update it as the vehicle moves along.

Code: Select all
#define D_HEIGHTFIELD_GRID_SIZE      2.0f
#define D_HEIGHTFIELD_WIDTH         16
#define D_HEIGHTFIELD_HEIGHT      16
#define D_HEIGHTFIELD_TILE_SIZE      2

   class CAiController : public ndModel
   {
   public:
      CAiController(ndDemoEntityManager* pScene, ndBodyDynamic* pBody, ndBodyKinematic* pHeightField)
         : m_pScene(pScene)
         , m_pAiBody(pBody)
         , m_pHeightField(pHeightField)
         , m_dDesiredSpeed(4.1667f)      // 4.1667f m/s = 15 km/h (9.3 mph) 33.3333 m/s = 120km/h (74.6mph)
         , m_dCurrentSpeed(0.0f)
         , m_dSpeedProportional(3000.0f)
         , m_dIntegral(0.0f)
         , m_dIntegralGain(3000.0f)
         , m_dDerivativeGain(600.0f)
         , m_dPreviousError(0.0f)
         , m_dCombinedMaximumForce()
      {
         m_dCombinedMaximumForce = pBody->GetMassMatrix().m_w * ndFloat32(6.0);      // Mass * Maximum acceleration of 6m/s/s
      }

   protected:
      virtual void Update(ndWorld* const, ndFloat32 timestep) override
      {
         if (m_pAiBody->GetPosition().m_y < 1.5f)
         {
            ndMatrix mMatrix(m_pAiBody->GetRotation(), ndVector(ndFloat32(0.0), ndFloat32(0.0), ndFloat32(0.0), ndFloat32(1.0)));
            ndVector vForward = mMatrix.TransformVector(ndVector(ndFloat32(0.0), ndFloat32(0.0), ndFloat32(1.0), ndFloat32(0.0)));
            ndVector vVelocity = m_pAiBody->GetVelocity();
            m_dCurrentSpeed = (vForward.DotProduct(vVelocity)).GetScalar();
            ndFloat32 dSpeedDifference = m_dDesiredSpeed - m_dCurrentSpeed;
            ndFloat32 dForce = _UpdatePIDForDriveForces(dSpeedDifference, timestep);
            dForce = dClamp(dForce, -m_dCombinedMaximumForce, m_dCombinedMaximumForce);
            ndVector vForce(ndFloat32(0.0), ndFloat32(0.0), dForce, ndFloat32(0.0));
            ndVector vOffset(ndFloat32(0.0), ndFloat32(0.0), ndFloat32(0.0), ndFloat32(1.0));
            ndVector vOffsetLS = mMatrix.TransformVector(vOffset);      // Offset in local space
            ndVector vForceLS = mMatrix.TransformVector(vForce);      // Force in local space
            m_pAiBody->SetForce(m_pAiBody->GetForce() + vForceLS);
            m_pAiBody->SetTorque(m_pAiBody->GetTorque() + (vOffsetLS.CrossProduct(vForceLS)));
            _ApplyLateralForces(timestep);
         }

         if (m_pHeightField)
         {
            // Move the height field with the body
            static int iFrameCount = 0;

            if (iFrameCount == 100)      // Update the heightfield every 50 frames
            {
               ndVector heightPos = m_pAiBody->GetPosition();
               heightPos.m_x -= 16.0f;
               heightPos.m_y = 0.0f;
               heightPos.m_z -= 16.0f;
               ndMatrix mHeightField = m_pHeightField->GetMatrix();
               mHeightField.m_posit = heightPos;
               m_pHeightField->SetMatrixUpdateScene(mHeightField);

               iFrameCount = 0;
            }

            ++iFrameCount;
         }

         // Get the camera to follow the vehicle
         ndVector origin(m_pAiBody->GetPosition());
         ndQuaternion rot(dYawMatrix(180.0f * ndDegreeToRad));
         origin.m_x += 10.0f;
         m_pScene->SetCameraMatrix(rot, origin);
      }

   private:
      ndFloat32 _UpdatePIDForDriveForces(ndFloat32 dError, ndFloat32 dTimestep)
      {
         ndFloat32 dProportional = m_dSpeedProportional * dError;
         m_dIntegral = m_dIntegral + m_dIntegralGain * dError * dTimestep;

         // Make sure our integral remains inside reasonable bounds relative to the maximum force we are supposed to use
         m_dIntegral = dClamp(m_dIntegral, -m_dCombinedMaximumForce, m_dCombinedMaximumForce);

         // Reset integral so that we don't overshoot stopping, and don't move slightly when our speed should be zero.
         if (abs(m_dDesiredSpeed) < 0.01 && abs(m_dCurrentSpeed) < 0.01)
            m_dIntegral = 0;

         ndFloat32 dDerivative = m_dDerivativeGain * (dError - m_dPreviousError) / dTimestep;
         ndFloat32 dOutput = m_dIntegral + dDerivative + dProportional;
         m_dPreviousError = dError;
         return dOutput;
      }
      void _ApplyLateralForces(ndFloat32 dTimestep)
      {
         ndMatrix mMatrix(m_pAiBody->GetRotation(), ndVector(ndFloat32(0.0), ndFloat32(0.0), ndFloat32(0.0), ndFloat32(1.0)));
         ndVector vForward = mMatrix.TransformVector(ndVector(ndFloat32(0.0), ndFloat32(0.0), ndFloat32(1.0), ndFloat32(0.0)));
         vForward.m_w = ndFloat32(0.0);
         ndVector vUp = mMatrix.TransformVector(ndVector(ndFloat32(0.0), ndFloat32(1.0), ndFloat32(0.0), ndFloat32(0.0)));
         vUp.m_w = ndFloat32(0.0);
         // Get some info about our current velocity
         ndVector vVelocity = m_pAiBody->GetVelocity();
         ndFloat32 dVelocity = vVelocity.DotProduct(vVelocity).GetScalar();
         // Work out lateral force to stop sliding (all in world space)
         ndVector vVelocitySideways = vVelocity - vForward.Scale(vVelocity.DotProduct(vForward).GetScalar()) - vUp.Scale(vVelocity.DotProduct(vUp).GetScalar());
         ndVector vVelocityUp = vVelocity - vForward.Scale(vVelocity.DotProduct(vForward).GetScalar()) - vVelocitySideways;
         ndVector vSidewaysMomentum = vVelocitySideways.Scale(m_pAiBody->GetMassMatrix().m_w);
         ndVector vVerticalMomentum = vVelocityUp.Scale(m_pAiBody->GetMassMatrix().m_w);
         m_pAiBody->ApplyImpulsePair(ndVector::m_negOne * vSidewaysMomentum * 0.8f, ndVector(0.0f), dTimestep);      // 0.8 = momentum cancelling factor
         m_pAiBody->ApplyImpulsePair(ndVector::m_negOne * vVerticalMomentum * 0.0f, ndVector(0.0f), dTimestep);

         // Work out steering forces
         ndFloat32 dSteering = 0.0;               // Keep the vehicle travelling straight
         ndFloat32 dMaxTorque = 50000;
         ndFloat32 dDesiredAngularSpeedFactor = 1.0;
         ndFloat32 dDesiredAngularSpeed = dDesiredAngularSpeedFactor * dVelocity * dSteering / (ndPi);   // Steering is a value from -pi to pi

         if (m_dCurrentSpeed < 0)   // Flip desired angular speed for reversing
            dDesiredAngularSpeed *= -1;

         ndFloat32 dAngularSpeed = vUp.DotProduct(m_pAiBody->GetOmega()).GetScalar();            // Component of the angular velocity about the up vector
         ndFloat32 dAngularSpeedDifference = dDesiredAngularSpeed - dAngularSpeed;
         dAngularSpeedDifference = dClamp(dAngularSpeedDifference, ndFloat32(-0.3), ndFloat32(0.3));
         dAngularSpeedDifference = dAngularSpeedDifference / ndFloat32(0.3);               // Normalise to between -1 and 1;
         ndFloat32 dTorque = dAngularSpeedDifference * dMaxTorque;
         ndVector vYAxisMoment = ndVector(ndFloat32(0.0), dTorque, ndFloat32(0.0), ndFloat32(0.0));                        // Vehicle space torque
         ndVector vWorldMoment = mMatrix.TransformVector(vYAxisMoment);               // Get the torque to world space
         m_pAiBody->SetTorque(m_pAiBody->GetTorque() + vWorldMoment);
      }

      ndDemoEntityManager* m_pScene;
      ndBodyDynamic* m_pAiBody;
      ndBodyKinematic* m_pHeightField;
      ndFloat32 m_dDesiredSpeed;
      ndFloat32 m_dCurrentSpeed;
      ndFloat32 m_dSpeedProportional;
      ndFloat32 m_dIntegral;
      ndFloat32 m_dIntegralGain;
      ndFloat32 m_dDerivativeGain;
      ndFloat32 m_dPreviousError;
      ndFloat32 m_dCombinedMaximumForce;
   };

   static ndBodyDynamic* AddRigidBody(ndDemoEntityManager* const scene, const ndMatrix& matrix, const ndShapeInstance& shape, ndDemoInstanceEntity* const rootEntity, ndFloat32 mass, ndBodyKinematic* pHeightField)
   {
      ndBodyDynamic* const pBody = new ndBodyDynamic();
      ndDemoEntity* const pEntity = new ndDemoEntity(matrix, rootEntity);
      pBody->SetNotifyCallback(new ndDemoEntityNotify(scene, pEntity));
      pBody->SetMatrix(matrix);
      pBody->SetCollisionShape(shape);
      pBody->SetMassMatrix(mass, shape);
      CAiController* pController = new CAiController(scene, pBody, pHeightField);


      ndWorld* const world = scene->GetWorld();
      world->AddModel(pController);
      world->AddBody(pBody);
      return pBody;
   }

   ndShapeInstance CreateCompondCollision()
   {
      ndFloat32 convexHullPoints[336] = { 2.64974f,  0.903322f,  -0.766362f,  2.64974f,  0.903322f,  -0.0842047f,  0.677557f,  0.903322f,  0.662591f,  -0.596817f,  0.903322f,  0.662591f,  -2.77764f,  0.903321f,  0.0424131f,
         -2.77764f,  0.903321f,  -0.766362f,  -1.56248f,  0.903322f,  -0.766362f,  -0.784835f,  0.903322f,  -0.766362f,  1.46171f,  0.903322f,  -0.766362f,  2.22016f,  0.903322f,  -0.766362f,
         -2.77764f,  -0.918637f,  -0.766362f,  -2.77764f,  -0.918637f,  0.0424131f,  -0.596817f,  -0.918637f,  0.662591f,  0.677557f,  -0.918636f,  0.662591f,  2.64974f,  -0.918636f,  -0.0842047f,
         -1.56248f,  -0.918637f,  -0.766362f,  -0.784834f,  -0.918637f,  -0.766362f,  1.46171f,  -0.918636f,  -0.766362f,  2.22016f,  -0.918636f,  -0.766362f,  2.64974f,  -0.918636f,  -0.766362f,
         2.22016f,  -0.654416f,  -0.766362f,  2.22016f,  -0.918636f,  -0.766362f,  2.64974f,  -0.918636f,  -0.766362f,  2.22016f,  0.661676f,  -0.766362f,  2.22016f,  0.903322f,  -0.766362f,
         2.64974f,  0.903322f,  -0.766362f,  -2.77764f,  0.903321f,  -0.766362f,  -2.77764f,  0.903321f,  0.0424131f,  -2.77764f,  -0.918637f,  0.0424131f,  -2.77764f,  -0.918637f,  -0.766362f,
         -2.77764f,  0.903321f,  0.0424131f,  -0.596817f,  0.903322f,  0.662591f,  -0.596817f,  -0.918637f,  0.662591f,  -2.77764f,  -0.918637f,  0.0424131f,  2.64974f,  0.903322f,  -0.0842047f,
         2.64974f,  0.903322f,  -0.766362f,  2.64974f,  -0.918636f,  -0.766362f,  2.64974f,  -0.918636f,  -0.0842047f,  0.677557f,  0.903322f,  0.662591f,  2.64974f,  0.903322f,  -0.0842047f,
         2.64974f,  -0.918636f,  -0.0842047f,  0.677557f,  -0.918636f,  0.662591f,  -2.77764f,  -0.918637f,  -0.766362f,  -1.56248f,  -0.918637f,  -0.766362f,  -1.56248f,  -0.654416f,  -0.766362f,
         -2.77764f,  0.903321f,  -0.766362f,  -1.56248f,  0.661676f,  -0.766362f,  -1.56248f,  0.903322f,  -0.766362f,  -0.784834f,  -0.654416f,  -0.766362f,  -0.784835f,  0.661676f,  -0.766362f,
         -0.784834f,  -0.918637f,  -0.766362f,  1.46171f,  -0.918636f,  -0.766362f,    1.46171f,  -0.654416f,  -0.766362f,  1.46171f,  0.661676f,  -0.766362f,  -0.784835f,  0.903322f,  -0.766362f,
         1.46171f,  0.903322f,  -0.766362f,  -0.784834f,  -0.654416f,  -0.766362f,  -1.56248f,  -0.654416f,  -0.766362f,  -1.17366f,  -0.654417f,  -1.15761f,  -1.56248f,  -0.654416f,  -0.766362f,
         -1.56248f,  -0.918637f,  -0.766362f,  -1.17366f,  -0.918637f,  -1.15761f,  -1.17366f,  -0.654417f,  -1.15761f,  -1.56248f,  -0.918637f,  -0.766362f,  -0.784834f,  -0.918637f,  -0.766362f,
         -1.17366f,  -0.918637f,  -1.15761f,  -0.784834f,  -0.918637f,  -0.766362f,  -0.784834f,  -0.654416f,  -0.766362f,  -1.17366f,  -0.654417f,  -1.15761f,  -1.17366f,  -0.918637f,  -1.15761f,
         -1.56248f,  0.661676f,  -0.766362f,  -0.784835f,  0.661676f,  -0.766362f,  -1.17366f,  0.661676f,  -1.15761f,  -0.784835f,  0.661676f,  -0.766362f,  -0.784835f,  0.903322f,  -0.766362f,
         -1.17366f,  0.903322f,  -1.15761f,  -1.17366f,  0.661676f,  -1.15761f,  -0.784835f,  0.903322f,  -0.766362f,  -1.56248f,  0.903322f,  -0.766362f,  -1.17366f,  0.903322f,  -1.15761f,
         -1.56248f,  0.903322f,  -0.766362f,  -1.56248f,  0.661676f,  -0.766362f,  -1.17366f,  0.661676f,  -1.15761f,  -1.17366f,  0.903322f,  -1.15761f,  2.22016f,  -0.654416f,  -0.766362f,
         1.46171f,  -0.654416f,  -0.766362f,  1.84093f,  -0.654416f,  -1.15761f,  1.46171f,  -0.654416f,  -0.766362f,  1.46171f,  -0.918636f,  -0.766362f,  1.84093f,  -0.918636f,  -1.15761f,
         1.84093f,  -0.654416f,  -1.15761f,  1.46171f,  -0.918636f,  -0.766362f,  2.22016f,  -0.918636f,  -0.766362f,  1.84093f,  -0.918636f,  -1.15761f,  2.22016f,  -0.918636f,  -0.766362f,
         2.22016f,  -0.654416f,  -0.766362f,  1.84093f,  -0.654416f,  -1.15761f,  1.84093f,  -0.918636f,  -1.15761f,  1.46171f,  0.661676f,  -0.766362f,  2.22016f,  0.661676f,  -0.766362f,
         1.84093f,  0.661676f,  -1.15761f,  2.22016f,  0.661676f,  -0.766362f,  2.22016f,  0.903322f,  -0.766362f,  1.84093f,  0.903322f,  -1.15761f,  1.84093f,  0.661676f,  -1.15761f,
         2.22016f,  0.903322f,  -0.766362f,  1.46171f,  0.903322f,  -0.766362f,  1.84093f,  0.903322f,  -1.15761f,  1.46171f,  0.903322f,  -0.766362f,  1.46171f,  0.661676f,  -0.766362f,
         1.84093f,  0.661676f,  -1.15761f,  1.84093f,  0.903322f,  -1.15761f };

      ndMatrix mParentInv = dGetIdentityMatrix();
      mParentInv.m_posit = ndVector(ndFloat32(0.0), ndFloat32(-1.0), ndFloat32(0.0), ndFloat32(1.0));
      ndMatrix mChildWorld = dGetIdentityMatrix();
      mChildWorld.m_front = ndVector(ndFloat32(0.0), ndFloat32(0.0), ndFloat32(1.0), ndFloat32(0.0));
      mChildWorld.m_up = ndVector(ndFloat32(1.0), ndFloat32(0.0), ndFloat32(0.0), ndFloat32(0.0));
      mChildWorld.m_right = ndVector(ndFloat32(0.0), ndFloat32(1.0), ndFloat32(0.0), ndFloat32(0.0));
      mChildWorld.m_posit = ndVector(ndFloat32(0.0), ndFloat32(1.158), ndFloat32(-0.508), ndFloat32(1.0));
      ndMatrix mChildLocal = mChildWorld * mParentInv;

#if 1
      ndShapeInstance shapeInstance(new ndShapeCompound());
      shapeInstance.GetShape()->GetAsShapeCompound()->BeginAddRemove();
      ndShapeInstance childShapeInstance(new ndShapeConvexHull(336 / 3, sizeof(ndFloat32) * 3, 0.0, &convexHullPoints[0]));
      childShapeInstance.SetLocalMatrix(mChildLocal);
      shapeInstance.GetShape()->GetAsShapeCompound()->AddCollision(&childShapeInstance);
      shapeInstance.GetShape()->GetAsShapeCompound()->EndAddRemove();
#else
      ndShapeInstance shapeInstance(new ndShapeConvexHull(336 / 3, sizeof(ndFloat32) * 3, 0.0, &convexHullPoints[0]));
      shapeInstance.SetLocalMatrix(mChildLocal);
#endif
      return shapeInstance;
   }

   ndShapeInstance CreateBoxCollision()
   {
      return ndShapeInstance(new ndShapeBox(1.0, 0.5, 2.0));
   }

   static void AddAiVehicle(ndDemoEntityManager* const scene, ndBodyKinematic* pHeightField)
   {
      //ndShapeInstance shapeInstance = CreateBoxCollision();
      ndShapeInstance shapeInstance = CreateCompondCollision();

      ndDemoMeshIntance* const aiGeometry = new ndDemoMeshIntance("AiVehicle", scene->GetShaderCache(), &shapeInstance, "earthmap.tga", "earthmap.tga", "earthmap.tga");
      ndDemoInstanceEntity* const aiEntity = new ndDemoInstanceEntity(aiGeometry);
      scene->AddEntity(aiEntity);
      ndMatrix mBodyMatrix = dGetIdentityMatrix();
      mBodyMatrix.m_posit = ndVector(0.0f, 5.0f, 0.0f, 1.0f);
      //mBodyMatrix.m_posit = ndVector(0.0f, 1.2f, 0.0f, 1.0f);
      auto pAiBody = AddRigidBody(scene, mBodyMatrix, shapeInstance, aiEntity, 1000.0, pHeightField);

      ndVector origin(pAiBody->GetPosition());
      ndQuaternion rot(dYawMatrix(180.0f * ndDegreeToRad));
      origin.m_x += 10.0f;
      scene->SetCameraMatrix(rot, origin);
   }

   ndBodyKinematic* BuildHeightField(ndDemoEntityManager* const scene, const ndMatrix& location)
   {
      // create the height field collision and rigid body
      ndShapeInstance heighfieldInstance(new ndShapeHeightfield(D_HEIGHTFIELD_WIDTH, D_HEIGHTFIELD_HEIGHT,
         ndShapeHeightfield::m_invertedDiagonals,
         1.0f / 100.0f, D_HEIGHTFIELD_GRID_SIZE, D_HEIGHTFIELD_GRID_SIZE));

      ndShapeHeightfield* const shape = heighfieldInstance.GetShape()->GetAsShapeHeightfield();
      ndArray<ndInt16>& hightMap = shape->GetElevationMap();
      dAssert(hightMap.GetCount() == D_HEIGHTFIELD_WIDTH * D_HEIGHTFIELD_HEIGHT);
      for (int i = 0; i < D_HEIGHTFIELD_WIDTH * D_HEIGHTFIELD_HEIGHT; ++i)
      {
         ndFloat32 high = 0.0; //  heightfield[i].m_y * 100.0f;
         dAssert(high < ndFloat32(1 << 15));
         dAssert(high > -ndFloat32(1 << 15));
         hightMap[i] = ndInt16(high);
      }
      shape->UpdateElevationMapAabb();

      ndPhysicsWorld* const world = scene->GetWorld();
      ndBodyDynamic* const body = new ndBodyDynamic();
      //body->SetNotifyCallback(new ndDemoEntityNotify(scene, entity));
      body->SetMatrix(location);
      body->SetCollisionShape(heighfieldInstance);

      world->AddBody(body);
      return body;
   }
}

//void ndBasicAiDemo(ndDemoEntityManager* const scene)
void ndBasicCompoundShapeDemo(ndDemoEntityManager* const scene)
{
   ndMatrix heighfieldLocation(dGetIdentityMatrix());
   heighfieldLocation.m_posit.m_x = -16.0f;
   heighfieldLocation.m_posit.m_z = -16.0f;
   auto pHeightField = BuildHeightField(scene, heighfieldLocation);
   //BuildProceduralMap(scene, 200, 2.0f, 0.0f);
   AddAiVehicle(scene, pHeightField);
   //AddAiVehicle(scene, nullptr);
}


Sometimes the bug happens quickly, but sometime it takes some time before it happens. I hope it happens when you look at it.
Esharc
 
Posts: 120
Joined: Tue Jan 10, 2017 5:23 am
Location: South Africa

Re: Height Field Collision Issue

Postby Julio Jerez » Wed Feb 02, 2022 3:43 pm

I see what you are doing with the heightfield. not sure if that is a good system.
as long as the change is the height field does not cause changes on the height that the vehicle is at, it should be fine.
also It could get very complex, when there are more than one vehicle. unless you add one rigid body to the world for each vehicle and each vehicle has it's own terrains, that's woeful
that is exactly what the procedural is for.
but anyway, is that method works for your app, them that's fine.

I pasted that new code, and I do not see any glitches.
I even did this, so that the elevation are uneven
Code: Select all
   for (int i = 0; i < D_HEIGHTFIELD_WIDTH * D_HEIGHTFIELD_HEIGHT; ++i)
   {
      //ndFloat32 high = 0.0; //  heightfield[i].m_y * 100.0f;
      ndFloat32 high = dGaussianRandom(1.0f);


the vehicle moves rather nice, I even made the random mush larger ndFloat32 high = dGaussianRandom(4.0f);

which will make significant concaves and convex sections caps and still acted quite smooth.

If I am supposed to see the bug with the new script? somehow this is not doing it, I am lost now.
did this repro make the bug happen in the sandbox in your side?

I checked it in with the new repro.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Julio Jerez » Wed Feb 02, 2022 3:59 pm

I did not see that before, but I see that you are using the ndModel for your vehicle.

this offers a work around solution to the bug. Basically, it goes like this.

in the update function you can get the contact joint for the vehicle and the terrain.
them, for each contact point, since you want the contact to be the contact at the terrain but the normal of the face and not the edge.

you can read the contact and make a function that get the grid for the position and them make override the contact normal.

I did that trick for vehicles in 3.14, but now 4.00 I add the general solution, that somehow is failing for you, but that should work as a fallback.

there are many demos that iterate over contacts, in the sand box if you want to try that. you can check the sound.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Julio Jerez » Wed Feb 02, 2022 4:26 pm

Ok. Having the model make for a few solutions.

Basically what you are making is a ray cast car.

If this the case them it can be solve in a legitimate way that play nice with the engine.

This are the steps.

1-set a shape Id for both vehicle an collision shape.
2- in the contact notify, reject all contacts, this will make a valid joint but not contacts.
3- in the model update, you set 4 hard points for raycast or convex cast.
Them you trace a short convex cast with a sphere shape, this will give you the contact point on the terrain.

And you add those as contacts to the contact joint.

If you think this could be a viable solution, tell me, I can set it up for you.

This will be equivalent to the uption of adding the shere wheel and I would say will be simpler.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Esharc » Thu Feb 03, 2022 12:10 am

We do not use ndModel in our system, the only reason why I used ndModel in the Sandbox demo is so that I will have access to the update loop. I will investigate adding it to the vehicles and get back to you.

We have separate height fields for each vehicle, and then ignore collisions between height fields. I would like to get the procedural terrain working in our app, cause like you say it is not ideal to have the height fields for each vehicle. For now I just want to focus on this problem first.
Esharc
 
Posts: 120
Joined: Tue Jan 10, 2017 5:23 am
Location: South Africa

Re: Height Field Collision Issue

Postby Julio Jerez » Thu Feb 03, 2022 12:28 am

I recommend you try to get a model, so that you can get the update after all the collision action has happens. the has always been a problem because when a joint is working calculation contacts, is no good to interfere with process.

I will see if I can do in in the contact call back, by having the joint calculating the contacts them delete them, but the problem is ta as you can see, the philosophy of the engine is to get things in local variable and the copy the result to the final object.
you may not see that as important but make a bit different for multi threaded.

anyway I see if I can see the ray cast not using ndModel.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Height Field Collision Issue

Postby Esharc » Thu Feb 03, 2022 12:48 am

Yes I can definitely see the worth in doing it the way that you do, and the model will be a good idea. There are some good improvements in Newton 4 that I would like to get into our system to make it more stable.

I have made a video of the bump that I get in the Sandbox demo on the height field. I have made so that the height field is flat. The bug happens from about 30 seconds in the video.

https://youtu.be/V0DuUBX5VPI
Esharc
 
Posts: 120
Joined: Tue Jan 10, 2017 5:23 am
Location: South Africa

Re: Height Field Collision Issue

Postby Julio Jerez » Thu Feb 03, 2022 1:00 am

Oh, I see I did not run it long enough.
Yes saw on bump at about 30 second, there maybe more.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

PreviousNext

Return to Bugs and Fixes

Who is online

Users browsing this forum: No registered users and 13 guests