Calling moveTowardsWithCollision gets my player character stuck. I can't increase the radius of the sphere but I have increased the recursion up to 4. It didn't help. Is the answer to simply increase recursion or should I do something else?
private void moveTowardsWithCollision(Object3D toMove, Object3D towards, float amount) {
SimpleVector center = toMove.getTransformedCenter();
SimpleVector center2 = towards.getTransformedCenter();
SimpleVector direction = new SimpleVector((center2.x-center.x)*amount, (center2.y-center.y)*amount, (center2.z-center.z)*amount);
SimpleVector newDirection = collide(direction);
toMove.translate(newDirection);
}
private SimpleVector collide(SimpleVector directionToHead) {
collisionObject.setVisibility(true);
SimpleVector direction = hero.get(0).checkForCollisionEllipsoid(directionToHead, new SimpleVector(1f, 1f, 1f), 4);
collisionObject.setVisibility(false);
return direction;
}
Try to adjust http://www.jpct.net/doc/com/threed/jpct/Config.html#collideEllipsoidThreshold (http://www.jpct.net/doc/com/threed/jpct/Config.html#collideEllipsoidThreshold). You might have to lower or increase it...it depends on the scene and the scale of your geometry.
Neither Float.MIN_VALUE nor Float.MAX_VALUE (nor lots of values in between) helped. Still getting stuck.
No, we aren't talking about such kind of values. Keep in mind that this value is the length of the movement vector below which the recursion will stop. Setting it MIN_FLOAT or MAX_FLOAT makes no sense at all. If the default is for example 0.5, try something like 0.05 or 0.01 or 0.005...that kind of values. Combine this with changing the recursion depth to maybe 3 or 5 and see if that helps. Also make sure that you don't start inside of a collision already. Sometimes, this might happen due to inaccuracies in the calculations. Try to lift the object a little before doing the detection. You'll have to implement gravity anyway to make the hero follow the terrain. How is your collision code ATM (brief description, i don't need the actual oode).
Entire collision code is in my first code. The "gravity" is handled with a simple call to calcMinDistance.
Quote from: AGP on September 26, 2012, 01:35:22 AM
Entire collision code is in my first code. The "gravity" is handled with a simple call to calcMinDistance.
That might cause the problem. If you use a ray-polygon detection followed by an ellipsoid one, the result of the ray-polygon check might move your camera into a situation where the ellipsoid is already stuck in something when starting to move and ellipsoid collision detection isn't very good in resolving existing collisions. It's all about avoiding them in the first place. Try to replace your calcMinDistance-gravity by some that uses ellipsoids like the fps example does it.
Would simply alternating between calling calcMinDistance and testing for the collision each frame solve it?
I'm not sure what exactly you mean by that... ???
On one frame I would call calcMinDistance. On the next test for collisionEllipsoid. And so on.
I tested it and walked right through the walls, because I'm only testing half the time for collisions!
CalcMinDistance is by far the most intuitive way of following a terrain. Why not just improve checkForCollisionEllipsoid to consider calcMinDistance?
There is nothing to improve. The problem isn't related to both methods being used in the same iteration, it's related to the way they work. ray/polygon collision detection (calcMinDistance is nothing more than that) works for one point on the surface. If you take the distance to that point and adjust the hero accordingly, the ellipsoid that covers the hero extends far beyond that point in all directions and, depending on the terrains geometry, it might intersect with some geometry that is a few units away from the point but still in the ellipsoid's radius. There's not much you can do about it except using the same ellipsoid for gravity calculations.
What about a method that clears the results of the previous test?
That's not the point. The point is that your gravity calculation moves you into situations that can't be solved by the ellipsoid collision detection. There's nothing to clear or fix...they are just two collision detection approaches that don't mix very well.
OK, talk to me like I was a child. Every iteration I cast a ray downwards to determine the height of the current polygons on the terrain. You claim that this produces an ellipsoid that is somehow later re-used by checkForCollisionEllipsoid. Am I right so far? And, if so, why not just clear this ellipsoid so that I can make another collision test on the walls?
Quote from: AGP on September 28, 2012, 09:11:22 PM
You claim that this produces an ellipsoid that is somehow later re-used by checkForCollisionEllipsoid. Am I right so far? And, if so, why not just clear this ellipsoid so that I can make another collision test on the walls?
No, that's not what i mean. It doesn't create anything. The methods are totally independant. But to adjust an entity's height based on the ray-polygon collision and then try to do an ellipsoid collision detection might fail like in this artful drawing:
(http://jpct.de/pix/stuck.png)
As you can see, the ray won't hit the obstacle, but the ellisoid intersects with it. And that will make it stuck there. I won't always be as obvious as in this case though, but it illustrates the basic problem with this approach. But if you would use the ellipsoid in the first place, this won't happen because the entity will never end up like in the second drawing but it will hover on top of the obstacle.
OK, I understand your suggestion that by moving the hero by the result of calcMinDistance I accordingly affect the collision ellipsoid. But for one thing, where I'm getting stuck the terrain is plain and, for another, I can't see that as being a problem if the wall is 90 degrees to the floor (and for the most part my walls are). This problem really lies in result (or use of) checkForCollisionEllipsoid.
PS: Where I get stuck, the character is already on the ground (he doesn't fall as the one in your illustration).
It might still be caused by some inaccuracies between the two methods. Try to make the radius of the ellipsoid in y-direction a little lower than the actual distance from the ground so that the ellipsoid doesn't touch it. If that doesn't help, continue to play around with the parameters. There's no reason why it should get stuck on a plain, but it might if (for example) the threshold is very small. I would avoid combining the two methods anyway.
For whatever it's worth I added the following code to collide. If it collidedThisFrame, I don't move with calcMinDistance(). As I expected, it did not solve my problem, but at least now we know what the trouble is.
if (directionToHead.x != direction.x || directionToHead.z != direction.z)
collidedThisFrame = true;
else collidedThisFrame = false;
I tried collideOffset, gradually increasing it all the way to 1000. It didn't help.
Just stop using calcMinDistance at all. Try to use ellipsoid detection only.
How would this particular problem be helped by that? Especially since I don't use it after checkForEllipsoidCollision returns a SimpleVector other than the one it's passed.
It cleans up things to make it easier to track down the actual issue. I've no real idea what you are doing right now. The ellipsoid you are using is very small. I've no idea if that actually matches your geometry or not. Then there's some if-clause which decides if calcMinDistance will be used or not where you actually shouldn't use it anyway in this case (as explained in my drawing)...it all seems pretty convoluted to me and that makes it hard to find the real problem here. So i suggest to:
- Use an ellipsoid that has the size of the hero.
- Make sure that it covers the hero more or less.
- Leave out any gravity related code. You don't need it in this test case anyway (judging from the video).
- Make that work, then add additional stuff. Don't add additional stuff to something that is already broken. Take one or two steps back instead.
Your final collision method should have a few lines only. Do an ellipsoid collision detection for the hero, move the hero according to the results. That's all. No gravity, no ifs, nothing else. To make this work has to be first priority.
Then I propose either (the more likely knowing you) a method like checkForCollisionEllipsoid that automatically gets the size of the Object3D or (less likely knowing what you'll say about the pipeline) a drawEllipsoid(same arguments as checkForColEllipsoid). Otherwise it's too much guesswork, man.
I see your point, but that won't help much IMHO. It might be useful for the y-dimension of an object, but for normal collision detection, you want to extend the ellipsoid into x- and z-direction to some degree. You usually don't want to use a tight fitting ellipsoid. Apart from that, it's not a trivial problem and actually unsolvable in a lot of cases. In your case, you won't use an ellipsoid that covers both feet of your hero, because that would extend into the ground.
Use Mesh.getBoundingBox() for now, subtract the min from the max values, divide them by 2 and you have your basic values for the ellipsoid's radius. Add something to x and z just to be sure. Place it above the ground, so that it's close to it but doesn't intersect.
Covering the feet won't be a big priority (it doesn't have to look absolutely perfect, it just has to work). I'll try your values and report back, thanks.