A complete 3D game development suite written purely in Java.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
jmonkeyengine/jme3-terrain/src/test/java/com/jme3/terrain/collision/TerrainCollisionTest.java

88 lines
3.7 KiB

Fix and Improve TerrainPicking (#1049) * Fix TerrainPicking by not adding "ghost" collisions to the CollisionResults (which weren't removed). Improve TerrainPicking by allowing to do more ray tracing (previously, it stopped on the first hit, now it will stop on the first hit within range). * Upgraded TerrainTestCollision to support multiple collisions and print the collision results detailed. MultiCollision can easily be turned on/off in simpleInitApp(). During testing, I noticed a bug where in very rare cases the first collision isn't what is expected but the back side of the clicked mountain. It has to be validated if this is due to the following changes or was already present. * Added Basic Unit Tests for Collision * TerrainPicker: Change API to return int to conform with collideWith * TerrainQuad: Conform with Picker now returning the number of collisions and allow to set multipleCollisions true or false. * TerrainPicking: Fixed a bug where the perpendicular collision always returned true, no matter the result of checkTriangles. Also add support for multiple collisions (which is toggleable to the old behavior, because the picker can early out then). * Try to fix Travis Build * Fixed a Regression which occurred due to Multi Collision Handling: The method used to provide duplicate results, which is why I commented it out. This lead to corner-cases not colliding at all anymore, thus I added a unit-test and removed the commented code and instead made addCollision de-duplicate entries.
6 years ago
package com.jme3.terrain.collision;
import com.jme3.collision.CollisionResults;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class TerrainCollisionTest extends BaseAWTTest {
TerrainQuad quad;
@Before
public void initQuad() {
Texture heightMapImage = getAssetManager().loadTexture("Textures/Terrain/splat/mountains512.png");
AbstractHeightMap map = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f);
map.load();
quad = new TerrainQuad("terrain", 65, 513, map.getHeightMap());
}
/**
* Due to a previous bug, when no collision should happen, the CollisionResults struct was still populated, leading
* to an incoherency of data and ghost collisions when passing a non-empty CR.
*/
@Test
public void testNoCollision() {
Ray r = new Ray(new Vector3f(0f, 40f, 0f), Vector3f.UNIT_Y.negate());
r.setLimit(0.1f);
CollisionResults cr = new CollisionResults();
long l = System.nanoTime();
int cw = quad.collideWith(r, cr);
System.out.println((System.nanoTime() - l) + " ns");
Assert.assertEquals(0, cw);
Assert.assertEquals(0, cr.size());
Assert.assertEquals(null, cr.getClosestCollision());
Assert.assertEquals(null, cr.getFarthestCollision());
}
@Test
public void testPerpendicularCollision() {
Ray r = new Ray(new Vector3f(0f, 40f, 0f), Vector3f.UNIT_Y.negate());
CollisionResults cr = new CollisionResults();
int cw = quad.collideWith(r, cr);
Assert.assertEquals(1, cw);
Assert.assertEquals(1, cr.size());
Assert.assertEquals(new Vector3f(0f, 28f, 0f), cr.getClosestCollision().getContactPoint());
Assert.assertEquals(new Vector3f(-0.5144958f, 0.6859944f, 0.5144958f), cr.getClosestCollision().getContactNormal());
Assert.assertEquals(12, cr.getClosestCollision().getDistance(), 0.01d);
Assert.assertEquals(0, cr.getClosestCollision().getTriangleIndex());
}
@Test
public void testMultiCollision() {
// Ray parameters obtained by using TerrainTestCollision (manual inspection of a feasible ray and commenting out setLocalScale(2)
Ray r = new Ray(new Vector3f(-38.689114f, 35.622643f, -40.222355f), new Vector3f(0.68958646f, 0.0980845f, 0.7175304f));
CollisionResults cr = new CollisionResults();
long l = System.nanoTime();
int cw = quad.collideWith(r, cr);
System.out.println((System.nanoTime() - l) + " ns");
Assert.assertEquals(6, cw);
Assert.assertEquals(6, cr.size());
}
@Test
public void testPreventRegression() {
// This test is as the multi collision changes lead to a regression where sometimes a collision was ignored
// Ray parameters obtained by using TerrainTestCollision (manual inspection of a feasible ray and commenting out setLocalScale(2))
Ray r = new Ray(new Vector3f(101.61858f, 78.35965f, 17.645157f), new Vector3f(-0.4188528f, -0.56462675f, 0.71116734f));
CollisionResults cr = new CollisionResults();
quad.collideWith(r, cr);
Assert.assertEquals(3, cr.size());
Assert.assertEquals(68.1499f, cr.getClosestCollision().getDistance(), 0.01f);
Assert.assertEquals(new Vector3f(73.07381f, 39.88039f, 66.11114f), cr.getClosestCollision().getContactPoint());
Assert.assertEquals(new Vector3f(0.9103665f, 0.33104235f, -0.24828176f), cr.getClosestCollision().getContactNormal());
}
}