Terrain <-> player collision

I've coded the steep method too… of course I'm sharing it with you.


 public boolean hillTooSteep(Vector3f origin, Vector3f goal) {
Vector3f intersection = new Vector3f();
Ray ray = new Ray(origin, goal)
PickResults results = new TrianglePickResults();
// Use the ray to find all the models on the player's island which are hit by the ray.
results.clear();
terrainNode.findPick(ray, results);

// Find the target model in the results.
boolean found = false;
boolean hit = false;
for(int i = 0; i < results.getNumber() && found == false; i++)
{
TriMesh model = (TriMesh)results.getPickData(i).getTargetMesh().getParentGeom();
if(model.getName().equalsIgnoreCase(terrainNode.getName()))
{
found = true;
// Find the intersection where the ray hits the target's boundingBox in world
// coordinate system.
Vector3f[] vertices = new Vector3f[3];
for(int j = 0; j < model.getTriangleCount() && hit == false; j++)
{
model.getTriangle(j, vertices);
hit = ray.intersectWhere(
vertices[0].addLocal(model.getWorldTranslation()),
vertices[1].addLocal(model.getWorldTranslation()),
vertices[2].addLocal(model.getWorldTranslation()), intersection);
}
}
}
// If the target cannot be found or the ray does not hit the target, return false.
if(found == false || hit == false)
{
return false;
}
return Distance.distance(characterNode.getLocalTranslation(), intersection) <= MAX_STEEP
}

as i promised, this is the updated version specifically working with model terrains.



   /**
    * Find the intersection of the ray passed in and the given island's nearest model from the origin
    * of the ray. The returned value is either in the island's local coordinate system or the world
    * coordinate system determined by the localCoordinateSystem boolean value passed in. If there is
    * no intersection found, return null.
    * @param ray The ray defines the direction of searching.
    * @param island The island that is searching from.
    * @param localCoordinateSystem The boolean value indicates if the returned value should be in the
    *         island's local coordinate system or the world coordinate system.
    * @return A Vector3f which defines the intersection point.
    */
   public static Vector3f findIntersection(Ray ray, Island island, boolean localCoordinateSystem) {
      Vector3f intersection = new Vector3f();
      PickResults results = new TrianglePickResults();
      results.setCheckDistance(true);
      // Find all the models on the island which are hit by the ray.
      island.getModelNode().findPick(ray, results);
      // Find the intersection where the ray hits the nearest model in world coordinate system.
      if(results.getNumber() > 0)
      {
         boolean hit = false;
         TriMesh model = (TriMesh)results.getPickData(0).getTargetMesh().getParentGeom();
         ArrayList triangles = results.getPickData(0).getTargetTris();
         Vector3f[] vertices = new Vector3f[3];
         // If there are triangles hit, get the nearest triangle and find the intersection.
         if(triangles.size() > 0)
         {
            model.getTriangle(((Integer)triangles.get(0)).intValue(), vertices);
            hit = ray.intersectWhere(
                  vertices[0].multLocal(model.getWorldScale()).addLocal(model.getWorldTranslation()),
                     vertices[1].multLocal(model.getWorldScale()).addLocal(model.getWorldTranslation()),
                        vertices[2].multLocal(model.getWorldScale()).addLocal(model.getWorldTranslation()), intersection);
         }
         // Return the intersection in different coordinate system based on the given boolean value.
         if(hit && localCoordinateSystem)
         {
            return intersection.subtractLocal(model.getWorldTranslation());
         }
         else if(hit && !localCoordinateSystem)
         {
            return intersection;
         }
      }
      // If there is no intersection found, return null.
      return null;
   }

i have to apologize~  :oops:



i made a bug in the collision detection method. im sry if it caused u any problems.



heres the corrected one.



   /**
    * Find the intersection of the ray passed in and the given island's nearest model from the origin
    * of the ray. The returned value is either in the island's local coordinate system or the world
    * coordinate system determined by the localCoordinateSystem boolean value passed in. If there is
    * no intersection found, return null.
    * @param ray The ray defines the direction of searching.
    * @param island The island that is searching from.
    * @param localCoordinateSystem The boolean value indicates if the returned value should be in the
    *         island's local coordinate system or the world coordinate system.
    * @return A Vector3f which defines the intersection point.
    */
   public static Vector3f findIntersection(Ray ray, Island island, boolean localCoordinateSystem) {
      Vector3f intersection = new Vector3f();
      TrianglePickResults results = new TrianglePickResults();
      results.setCheckDistance(true);
      // Find all the models on the island which are hit by the ray.
      island.getModelNode().findPick(ray, results);
      // Find the intersection where the ray hits the nearest model in world coordinate system.
      if(results.getNumber() > 0)
      {
         boolean hit = false;
         TriMesh model = (TriMesh)results.getPickData(0).getTargetMesh().getParentGeom();
         ArrayList triangles = results.getPickData(0).getTargetTris();
         Vector3f[] vertices = new Vector3f[3];
         // If there are triangles hit, get the nearest triangle and find the intersection.
         if(triangles.size() > 0)
         {
            model.getTriangle(((Integer)triangles.get(0)).intValue(), vertices);
            hit = ray.intersectWhere(
                  vertices[0].multLocal(model.getWorldScale()).addLocal(model.getWorldTranslation()),
                     vertices[1].multLocal(model.getWorldScale()).addLocal(model.getWorldTranslation()),
                        vertices[2].multLocal(model.getWorldScale()).addLocal(model.getWorldTranslation()), intersection);
         }
         // Return the intersection in different coordinate system based on the given boolean value.
         if(hit && localCoordinateSystem)
         {
            island.worldToLocal(intersection, intersection);
            return intersection;
         }
         else if(hit && !localCoordinateSystem)
         {
            return intersection;
         }
      }
      // If there is no intersection found, return null.
      return null;
   }

Try something like this…just a example…



public void walking(){
      this.loc.addLocal(this.player.getLocalRotation().getRotationColumn(2).multLocal(0.49f));
      this.player.setLocalTranslation(this.loc);
      
      if(doMorph){
         setKeyframe(MovAtribs.RUNNING[0], MovAtribs.RUNNING[1], MovAtribs.RUNNING[2], Controller.RT_WRAP);
         doMorph = false;
      }
      
      onGroundResult.clear();

      ray = new Ray(new Vector3f(
                  this.player.getLocalTranslation().x,
                  this.player.getLocalTranslation().y + 2.5f,
                  this.player.getLocalTranslation().z),
                  new Vector3f(
                        this.player.getLocalRotation().getRotationColumn(2).x,
                        -1.0f,
                        this.player.getLocalRotation().getRotationColumn(2).z));
      this.loc.normalize();
      if ((int)toWalkX != (int)loc.x || (int)toWalkZ != (int)loc.z){
         for(int i = 0; i < storedObjects.getObjects().size(); i++){
            storedObjects.getObjects(i).findPick(ray, onGroundResult);
            for(int j = 0; j < onGroundResult.getNumber(); j++) {
               TriMesh mesh = (TriMesh) onGroundResult.getPickData(j).getTargetMesh().getParentGeom();      

Thank you very much for all the methods, I'm going to examine them as soon as I get my source code readable again (I had to decompile it because I accidentally deleted the sources).

(sorry for the bump)

I've tested the methods (finally) and it seems that they don't get any pick results (It returns an empty array). This throws an arrayoutofbounds. Can anyone tell me how to fix this?

PS method's I'm using included below:


    public void setTerrain(Terrain terrain) {
        terrainNode = terrain;
        this.getLocalTranslation().y = getCollisionPoint(this.getLocalTranslation());
    }
    public float getCollisionPoint(Vector3f goal) {
Vector3f intersection = new Vector3f();
gravityRay = new Ray(goal, tempVector.set(goal.x, goal.y -1f, goal.z));
// Use the ray to find all the models on the player's island which are hit by the ray.
gravityResults.clear();
terrainNode.findPick(gravityRay, gravityResults);

// Find the target model in the results.
boolean found = false;
boolean hit = false;
//for(int i = 0; i < gravityResults.getNumber() && found == false; i++)
//{
TriMesh model = (TriMesh)gravityResults.getPickData(0).getTargetMesh().getParentGeom();
/*if(model.getName().equalsIgnoreCase(terrainNode.getName()))
{*/
found = true;
// Find the intersection where the ray hits the target's boundingBox in world
// coordinate system.
Vector3f[] vertices = new Vector3f[3];
for(int j = 0; j < model.getTriangleCount() && hit == false; j++)
{
model.getTriangle(j, vertices);
hit = gravityRay.intersectWhere(
vertices[0].addLocal(model.getWorldTranslation()),
vertices[1].addLocal(model.getWorldTranslation()),
vertices[2].addLocal(model.getWorldTranslation()), intersection);
}
//}
//}
// If the target cannot be found or the ray does not hit the target, return null.
if(found == false || hit == false)
return 0;
// Return the intersection.
return intersection.y;
}

i think i did that easier:

  public boolean isNearGround(float p_maxDst) {
    final Vector3f l_nodeTranslation = getLocalTranslation();
    final float l_height = getEngine().currentTerrain().getHeight(l_nodeTranslation);
    final BoundingBox l_box = (BoundingBox) getWorldBound();
    final float l_minHeight = l_height + (l_box != null ? l_box.yExtent : 3);
    return (!Float.isInfinite(l_minHeight) && !Float.isNaN(l_minHeight) && l_nodeTranslation.y - p_maxDst <= l_minHeight);
  }

  public void stickToGround() {
    final Vector3f l_nodeTranslation = getLocalTranslation();
    final float l_height = getEngine().currentTerrain().getHeight(l_nodeTranslation);
    final BoundingBox l_box = (BoundingBox) getWorldBound();
    final float l_minHeight = l_height + (l_box != null ? l_box.yExtent : 3);
    if (!Float.isInfinite(l_minHeight) && !Float.isNaN(l_minHeight)) {
      l_nodeTranslation.y = l_minHeight;
    }
  }



node stays on ground. then there is a "i am jumping"-condition when i do not call stickToGround.
and for the slopes:

  private void applySlopeModification(final AbstractControllableEntity p_ae) {
    m_afterMovement.set(p_ae.getLocalTranslation());
    final float l_oldHeight = p_ae.getEngine().currentTerrain().getHeight(m_beforeMovement);
    final float l_newHeight = p_ae.getEngine().currentTerrain().getHeight(m_afterMovement);
    m_beforeMovement.y = l_oldHeight;
    m_afterMovement.y = l_newHeight;
    m_flatted.set(m_diff);
    m_flatted.y = 0.0F;
    m_diff.set(m_afterMovement).subtractLocal(m_beforeMovement);
    final float l_angle = m_diff.angleBetween(m_flatted);
    final float l_length = m_diff.length();
    final float l_scaled = (float) GeoMath.scale(0.0, Math.PI / 2.0, 0.0, 1.0, Math.PI / 2.0 - (double) l_angle);
    if (l_oldHeight > l_newHeight) {
      m_walking.addToRelative(p_ae, l_scaled / m_walkDownSlopeSpeedUp);
    } else if (l_oldHeight < l_newHeight) {
      m_walking.addToRelative(p_ae, -l_scaled / m_walkUpSpeedSlowdown);
    }
  }



i check where i would go, get the angle, and slow down or speed up the movement
  1. Your code is almost unreadable with those m_'s, l_'s and p_'s in front of it
  2. You refer a lot to methods that you don't show ie. getEngine().currentTerrain();
  3. I guess, no, I'm sure that you are talking about heigthmap generated terrain. I use 3ds models.

your landscape is a 3ds model?

in this case, ignore my post