wjc272008 / jmonkeyengine

Automatically exported from code.google.com/p/jmonkeyengine
0 stars 0 forks source link

Collision Ray passes through 2-dimensional box #455

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
When performing a ray collision with a box where 1 extent (in this case the Y) 
is 0, the collision passes through the box in certain cases. This seems similar 
to an earlier bug where the terrain showed the same behaviour.

The following code sets up a simple application and searches for the places in 
the scene where the collision misses for 1 pixel and hits for all surrounding 
pixels.

This bug was detected in a full scene and reproduced in the code below. An 
image has been attached to this report that shows where it happened in the full 
application. The red dot is where the mouse is positioned and the blue square 
shows that it's hitting the wrong 'square'

--- CODE ---
package test;

import org.lwjgl.input.Mouse;
import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResults;
import com.jme3.light.PointLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;

public class DebugCollision extends SimpleApplication {

    public static void main(String... args) {
        DebugCollision app = new DebugCollision();

        app.setShowSettings(false);
        app.start();
    }

    private Vector3f worldCoordinates = new Vector3f();

    private Ray mouseRay = new Ray();

    private Vector2f screenPos = new Vector2f();

    private static final Vector3f INITIAL_CAMERA_LOCATION = new Vector3f(-386.85208f, 100.24096f, 272.6368f);
    private static final Vector3f INITIAL_CAMERA_LOOK_AT = new Vector3f(-393.79184f, 23.13253f, 187.81754f);
    private static final Vector3f INITIAL_CAMERA_WORLD_UP = new Vector3f(0.0f, 1.0f, -0.1f);

    private static final float INITIAL_BOX_EXTENT_X = 11.566265f;
    private static final float INITIAL_BOX_EXTENT_Y = 0.0f;
    private static final float INITIAL_BOX_EXTENT_Z = INITIAL_BOX_EXTENT_X;
    private static final Vector3f INITIAL_BOX_TRANSLATION = new Vector3f(-420.24097f, 8.183132f, 181.20483f);

    /**
     * 
     */
    public DebugCollision() {
        // TODO Auto-generated constructor stub
    }

    public int getCollisionAmount(Vector2f screenPos) {

        // Get the world location of that X,Y value - far
        worldCoordinates.set(getCamera().getWorldCoordinates(screenPos, 1));

        Vector3f origin = getCamera().getLocation();
        mouseRay.setOrigin(origin);
        mouseRay.setDirection(worldCoordinates.subtractLocal(origin).normalizeLocal());

        CollisionResults results = new CollisionResults();
        rootNode.collideWith(mouseRay, results);

        return results.size();
    }

    /*
     * (non-Javadoc)
     * @see com.jme3.app.SimpleApplication#simpleInitApp()
     */
    @Override
    public void simpleInitApp() {
        Box quad = new Box(INITIAL_BOX_EXTENT_X, INITIAL_BOX_EXTENT_Y, INITIAL_BOX_EXTENT_Z);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        Geometry geo = new Geometry("test geo");
        geo.setMaterial(mat);
        geo.setMesh(quad);
        geo.setLocalTranslation(INITIAL_BOX_TRANSLATION);

        PointLight pl = new PointLight();
        pl.setColor(ColorRGBA.White);
        rootNode.addLight(pl);

        rootNode.attachChild(geo);

        getCamera().setLocation(INITIAL_CAMERA_LOCATION);
        getCamera().lookAt(INITIAL_CAMERA_LOOK_AT, INITIAL_CAMERA_WORLD_UP);

        inputManager.removeListener(flyCam);
        inputManager.setCursorVisible(true);
    }

    @Override
    public void simpleUpdate(float tpf) {
        // Scan
        for (int x = settings.getWidth() - 1; x > 0; x--) {
            for (int y = 1; y < settings.getWidth() - 1; y++) {
                screenPos.set(x - 1, y - 1);
                int amount = getCollisionAmount(screenPos);
                screenPos.set(x, y - 1);
                amount += getCollisionAmount(screenPos);
                screenPos.set(x + 1, y - 1);
                amount += getCollisionAmount(screenPos);

                screenPos.set(x - 1, y);
                amount += getCollisionAmount(screenPos);
                screenPos.set(x, y);
                int centerCollisionAmount = getCollisionAmount(screenPos);
                amount += centerCollisionAmount;
                screenPos.set(x + 1, y);
                amount += getCollisionAmount(screenPos);

                screenPos.set(x - 1, y + 1);
                amount += getCollisionAmount(screenPos);
                screenPos.set(x, y + 1);
                amount += getCollisionAmount(screenPos);
                screenPos.set(x + 1, y + 1);
                amount += getCollisionAmount(screenPos);

                if (centerCollisionAmount == 0 && amount == 16) {
                    System.err.println("Fault at " + x + ", " + y + " - Should be a collision");
                    Mouse.setCursorPosition(x, y);

                }
            }
        }
    }
}
----

Original issue reported on code.google.com by j.warmer...@gmail.com on 18 Jan 2012 at 2:45

Attachments:

GoogleCodeExporter commented 9 years ago
This bug is present in jME3.0beta / 18-jan-2012

Original comment by j.warmer...@gmail.com on 18 Jan 2012 at 2:46

GoogleCodeExporter commented 9 years ago

Original comment by normen667 on 2 Feb 2012 at 4:56

GoogleCodeExporter commented 9 years ago

Original comment by normen667 on 2 Feb 2012 at 4:57

GoogleCodeExporter commented 9 years ago

Original comment by ShadowIs...@gmail.com on 26 Mar 2012 at 4:19

GoogleCodeExporter commented 9 years ago
The issue occurs due to the BoundingBox class not supporting 0 extent in any of 
the axes.

Original comment by ShadowIs...@gmail.com on 2 Dec 2012 at 6:37

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
I think I have found the Bug, but I am not sure. Sorry if I had posted in the 
wrong issue.

The Octree can only calculate the correct volume for cubes with the same length 
on each side. For long boxes (e.g. a 2D-Box) the child bounds are simply wrong.
Class "Octnode", Line 76:

private BoundingBox getChildBound(int side){
        float extent = bbox.getXExtent() * 0.5f;
        Vector3f center = new Vector3f(bbox.getCenter().x + extent * extentMult[side].x,
                                       bbox.getCenter().y + extent * extentMult[side].y,
                                       bbox.getCenter().z + extent * extentMult[side].z);
        return new BoundingBox(center, extent, extent, extent);
    }

but this function should be like this:

private BoundingBox getChildBound(int side) {
        float ex = bbox.getXExtent() * .5f;
        float ey = bbox.getYExtent() * .5f;
        float ez = bbox.getZExtent() * .5f;

        Vector3f center = new Vector3f(
                bbox.getCenter().x + ex * extentMult[side].x,
                bbox.getCenter().y + ey * extentMult[side].y,
                bbox.getCenter().z + ez * extentMult[side].z);
        return new BoundingBox(center, ex, ey, ez);
    }

If this is the wrong 

Original comment by florianb...@googlemail.com on 10 Mar 2014 at 10:08