findPick() does not work sometimes

I created a model to test triangle picking.



findPick works well most of the time.



but sometimes some specific triangles doesn’t collide with rays on some direction



It’s very weird. Please look at the images below.



The first image shows some part of a triangle can be picked but other part of a triangle can not.









However, if ray’s direction is changed, all part of the triangle is picked (Second image)










To test it, I modified TestTrianglePick.java test code



After running the test,



type number keys (‘0’, ‘1’, ‘2’ …) then



Picking ray is showed. If picking fails, error message is printed through syserr.



I post the test code and modeling file



http://mulova.tistory.com/attachment/jk0.zip



Appreciate in advance.  :lol:



import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.FloatBuffer;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.app.AbstractGame;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.AbsoluteMouse;
import com.jme.input.FirstPersonHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.intersection.PickData;
import com.jme.intersection.TrianglePickResults;
import com.jme.math.Ray;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Line;
import com.jme.scene.Point;
import com.jme.scene.SceneElement;
import com.jme.scene.Spatial;
import com.jme.scene.batch.TriangleBatch;
import com.jme.scene.shape.AxisRods;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.util.TextureManager;
import com.jme.util.export.binary.BinaryImporter;
import com.jme.util.geom.BufferUtils;
import com.rontab.bim.util.RenderUtil;

/**
 * Started Date: Jul 22, 2004 <br>
 * <br>
 *
 * Demonstrates picking with the mouse.
 *
 * @author Jack Lindamood
 */
public class TestTrianglePick extends SimpleGame {
    private static final Logger logger = Logger
            .getLogger(TestTrianglePick.class.getName());

   private static final String   FILE_PATH   = "C:/test.jme";
   
   private Line line = new Line();

   // This will be my mouse
   AbsoluteMouse am;

   private Point pointSelection;

   Spatial maggie;

   private Line[] selection;

   public static void main(String[] args) {
      Logger.getLogger("").setLevel(Level.WARNING);
      TestTrianglePick app = new TestTrianglePick();
      app.setDialogBehaviour(AbstractGame.ALWAYS_SHOW_PROPS_DIALOG);
      app.start();
   }

   protected void simpleInitGame() {
      cam.setLocation(new Vector3f(-20, 10, -50));
      cam.lookAt(new Vector3f(-150, 0, -60), Vector3f.UNIT_Y);
      ((FirstPersonHandler)input).getMouseLookHandler().requireButtonPress(true);
      cam.update();
      rootNode.setCullMode(SceneElement.CULL_NEVER);
      setupBase();
      // Create a new mouse. Restrict its movements to the display screen.
      am = new AbsoluteMouse("The Mouse", display.getWidth(), display
            .getHeight());

      // Get a picture for my mouse.
      TextureState ts = display.getRenderer().createTextureState();
        URL cursorLoc = TestTrianglePick.class.getClassLoader().getResource(
                "jmetest/data/cursor/cursor1.png" );
        Texture t = TextureManager.loadTexture(cursorLoc, Texture.MM_LINEAR,
            Texture.FM_LINEAR);
      ts.setTexture(t);
      am.setRenderState(ts);

      // Make the mouse's background blend with what's already there
      AlphaState as = display.getRenderer().createAlphaState();
      as.setBlendEnabled(true);
      as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
      as.setTestEnabled(true);
      as.setTestFunction(AlphaState.TF_GREATER);
      am.setRenderState(as);

      // Move the mouse to the middle of the screen to start with
      am.setLocalTranslation(new Vector3f(display.getWidth() / 2, display
            .getHeight() / 2, 0));
      // Assign the mouse to an input handler
      am.registerWithInputHandler(input);

      // Create the box in the middle. Give it a bounds
      try {
         URL model = new File(FILE_PATH).toURI().toURL();
         BinaryImporter importer = new BinaryImporter();
         maggie = (Spatial) importer.load(model);
         
      } catch (IOException e) { // Just in case anything happens
            logger.logp(Level.SEVERE, this.getClass().toString(),
                    "simpleInitGame()", "Exception", e);
         System.exit(0);
      }

      maggie.setModelBound(new BoundingBox());
      maggie.updateModelBound();
      // Attach Children
      rootNode.attachChild(maggie);
      rootNode.attachChild(am);

      maggie.lockBounds();
      maggie.lockTransforms();
      results.setCheckDistance(true);

      pointSelection = new Point("selected triangle", new Vector3f[1], null,
            new ColorRGBA[1], null);
      pointSelection.setSolidColor(new ColorRGBA(1, 0, 0, 1));
      pointSelection.setPointSize(10);
      pointSelection.setAntialiased(true);
      ZBufferState zbs = display.getRenderer().createZBufferState();
      zbs.setFunction(ZBufferState.CF_ALWAYS);
      pointSelection.setRenderState(zbs);
      pointSelection.setLightCombineMode(LightState.OFF);

      rootNode.attachChild(pointSelection);
      
      testRay(new Vector3f(-19.677053f, 0.0f, -2.6199493f), new Vector3f(-0.7508563f, 0.0f, -0.66046566f));
      
      KeyBindingManager kbm = KeyBindingManager.getKeyBindingManager();
      kbm.add("1", KeyInput.KEY_1);
      kbm.add("2", KeyInput.KEY_2);
      kbm.add("3", KeyInput.KEY_3);
      kbm.add("4", KeyInput.KEY_4);
      kbm.add("5", KeyInput.KEY_5);
      kbm.add("6", KeyInput.KEY_6);
      kbm.add("7", KeyInput.KEY_7);
      kbm.add("8", KeyInput.KEY_8);
      kbm.add("9", KeyInput.KEY_9);
      kbm.add("0", KeyInput.KEY_0);
   }

   private void createSelectionTriangles(int number) {
      clearPreviousSelections();
      selection = new Line[number];
      for (int i = 0; i < selection.length; i++) {
         selection[i] = new Line("selected triangle" + i, new Vector3f[4],
               null, new ColorRGBA[4], null);
         selection[i].setSolidColor(new ColorRGBA(0, 1, 0, 1));
         selection[i].setLineWidth(5);
         selection[i].setAntialiased(true);
         selection[i].setMode(Line.CONNECTED);

         ZBufferState zbs = display.getRenderer().createZBufferState();
         zbs.setFunction(ZBufferState.CF_ALWAYS);
         selection[i].setRenderState(zbs);
         selection[i].setLightCombineMode(LightState.OFF);

         rootNode.attachChild(selection[i]);
      }

      rootNode.updateGeometricState(0, true);
      rootNode.updateRenderState();
   }

   private void clearPreviousSelections() {
      if (selection != null) {
            for ( Line line : selection ) {
                rootNode.detachChild( line );
            }
      }
   }

   TrianglePickResults results = new TrianglePickResults() {

      public void processPick() {

         // initialize selection triangles, this can go across multiple
         // target
         // meshes.
         int total = 0;
         for (int i = 0; i < getNumber(); i++) {
            total += getPickData(i).getTargetTris().size();
         }
         if (getNumber() > 0 && total == 0) {
            System.err.println("<<<< Can't get triangle >>>>");
         }
         createSelectionTriangles(total);
         if (getNumber() > 0) {
            int previous = 0;
            for (int num = 0; num < getNumber(); num++) {
               PickData pData = getPickData(num);
               List<Integer> tris = pData.getTargetTris();
               TriangleBatch mesh = (TriangleBatch) pData.getTargetMesh();

               for (int i = 0; i < tris.size(); i++) {
                  int triIndex = tris.get( i );
                  Vector3f[] vec = new Vector3f[3];
                  mesh.getTriangle(triIndex, vec);
                  FloatBuffer buff = selection[i + previous]
                        .getVertexBuffer(0);

                        for ( Vector3f v : vec ) {
                            v.multLocal( mesh.getParentGeom()
                                    .getWorldScale() );
                            mesh.getParentGeom().getWorldRotation().mult(
                                    v, v );
                            v.addLocal( mesh.getParentGeom()
                                    .getWorldTranslation() );
                        }

                  BufferUtils.setInBuffer(vec[0], buff, 0);
                  BufferUtils.setInBuffer(vec[1], buff, 1);
                  BufferUtils.setInBuffer(vec[2], buff, 2);
                  BufferUtils.setInBuffer(vec[0], buff, 3);

                  if (num == 0 && i == 0) {
                     selection[i + previous]
                           .setSolidColor(new ColorRGBA(1, 0, 0, 1));
                     Vector3f loc = new Vector3f();
                     pData.getRay().intersectWhere(vec[0], vec[1],
                           vec[2], loc);
                     BufferUtils.setInBuffer(loc, pointSelection
                           .getVertexBuffer(0), 0);
                  }
               }

               previous = tris.size();
            }
         }
      }
   };

   // This is called every frame. Do changing of values here.
   protected void simpleUpdate() {

      // Is button 0 down? Button 0 is left click
      if (MouseInput.get().isButtonDown(0)) {
         Vector2f screenPos = new Vector2f();
         // Get the position that the mouse is pointing to
         screenPos.set(am.getHotSpotPosition().x, am.getHotSpotPosition().y);
         // Get the world location of that X,Y value
         Vector3f worldCoords = display.getWorldCoordinates(screenPos, 1.0f);
         // Create a ray starting from the camera, and going in the direction
         // of the mouse's location
         final Ray mouseRay = new Ray(cam.getLocation(), worldCoords
               .subtractLocal(cam.getLocation()));
         mouseRay.getDirection().normalizeLocal();
         results.clear();

         maggie.calculatePick(mouseRay, results);
         showRay(mouseRay);
         
      }
      KeyBindingManager kbm = KeyBindingManager.getKeyBindingManager();
      if (kbm.isValidCommand("1", false)) {
         testRay(new Vector3f(-19.677053f, 0.2f, -2.6199493f), new Vector3f(-0.7508563f, 0.0f, -0.66046566f));
      } else if (kbm.isValidCommand("2", false)) {
         testRay(new Vector3f(-14.950614f, 0.2f, -33.370464f), new Vector3f(-0.9732216f, 0.0f, -0.22986898f));
      } else if (kbm.isValidCommand("3", false)) {
         testRay(new Vector3f(-10.722265f, 0.2f, -26.857378f), new Vector3f(-0.94959575f, 0.0f, -0.31347752f));
      } else if (kbm.isValidCommand("4", false)) {
         testRay(new Vector3f(-7.654091f, 0.2f, -37.46059f), new Vector3f(-0.9744296f, 0.0f, -0.22469339f));
      } else if (kbm.isValidCommand("5", false)) {
         testRay(new Vector3f(5.784861f, 0.2f, -18.619741f), new Vector3f(-0.92963105f, 0.0f, -0.3684917f));
      } else if (kbm.isValidCommand("6", false)) {
         testRay(new Vector3f(1.8931199f, 0.2f, -1.2393173f), new Vector3f(-0.8212465f, 0.0f, -0.5705737f));
      } else if (kbm.isValidCommand("7", false)) {
         testRay(new Vector3f(-0.8870149f, 0.2f, -3.2509987f), new Vector3f(-0.8220476f, 0.0f, -0.5694188f));
      } else if (kbm.isValidCommand("8", false)) {
         testRay(new Vector3f(-16.766214f, 0.2f, 0.29477668f), new Vector3f(-0.75086683f, 0.0f, -0.6604537f));
      } else if (kbm.isValidCommand("9", false)) {
         testRay(new Vector3f(-17.708593f, 0.2f, 0.51814497f), new Vector3f(-0.7047615f, 0.0f, -0.7094444f));
      } else if (kbm.isValidCommand("0", false)) {
         testRay(new Vector3f(-1.3747561f, 0.2f, -3.5791903f), new Vector3f(-0.84651035f, 0.0f, -0.53237224f));
      }
      
   }

   private void testRay(Vector3f origin, Vector3f dir) {
      Ray mouseRay = new Ray();
      mouseRay.getOrigin().set(origin);
      mouseRay.getDirection().set(dir);
      mouseRay.getDirection().normalizeLocal();
      results.clear();
      maggie.calculatePick(mouseRay, results);
      showRay(mouseRay);
   }
   
   
   protected void setupBase() {
      Quad floor = new Quad("floor", 5000f, 5000f);
      floor.setLocalTranslation(0, -0.1f, 0);
      RenderUtil.makeTransparent(floor);
      floor.getLocalRotation().lookAt(Vector3f.UNIT_Y, Vector3f.UNIT_X);
      floor.setSolidColor(ColorRGBA.white);
      MaterialState ms = RenderUtil.getMaterialState(floor);
      ms.setColorMaterial(MaterialState.CM_AMBIENT_AND_DIFFUSE);
      
      AxisRods rods = new AxisRods("axis", true, 1000, 0.05f);
      rootNode.attachChild(rods);
      rootNode.attachChild(floor);
      rootNode.updateRenderState();
      rootNode.updateGeometricState(0, true);
   }
   
   public void showRay(Ray ray) {
      Vector3f start = new Vector3f(ray.origin);
      Vector3f end = new Vector3f(ray.direction);
      end.multLocal(1000f);
      end.addLocal(start);

      line.clearBuffers();
      line.reconstruct(BufferUtils.createFloatBuffer(new Vector3f[] { start, end }), null,
            BufferUtils.createFloatBuffer(new ColorRGBA[2]), null);
      line.setSolidColor(ColorRGBA.white);
      line.setLineWidth(3);
      line.removeFromParent();
      rootNode.attachChild(line);
      rootNode.updateRenderState();
      rootNode.updateGeometricState(0f, true);
   }
}


try updating CollisionTreeManager if u modify the object.

Thanks for your reply.



I already tried it but it doesn't work.



When the phenomenon comes up,



The PickResult has 2 pick data but they don't have any triangles and the distance is infinity.

Does anyone have an idea for this?



It’s very critical problem for me.



Help will be appreciated  :’(

Can only suggest drawing a line to show the ray, that way you can sanity check your mouse cooridnates etc to the scengraph

I'm sorry I'm lack of english. I don't understand your reply.



Please try the test code with the given resource file.



In normal situation, triangle and point picked are shown with red color.



but some triangles are not picked and it depends on the direction of rays.