I’ve been fiddling with this for hours but I’m failing, please help…,
if I add any non Vector3f.ZERO local translation to the root node, although I am able to properly position the arrow, I cannot properly rotate it so that it shows perpendicular to the surface of collision(ie. a normal), as it does when translation of rootNode is 0,0,0
The rootNode can have any scale/rotation and it works ok, but if it has different translation => I don’t know how to rotate such that it remains the same as if it has 0,0,0 translation aka arrow is a normal on the surface
I’ve marked the line with rootNode translation with “XXX:” , set any value for x,y,z to see the problem, set to 0,0,0 to see it works well
this screenshot is when 0,0,0 thus it’s working, the arrow is a normal on the surface:
=====
the screenshot is when 0,0,-29 aka not working, failed to make arrow perpendicular on surface
http://i.imgur.com/c1MJa.png
====
pre type="java"
/*
- Copyright © 2009-2010 jMonkeyEngine
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
-
-
- Redistributions of source code must retain the above copyright
- Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-
- Redistributions in binary form must reproduce the above copyright
- Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-
- Neither the name of ‘jMonkeyEngine’ nor the names of its contributors
- Neither the name of ‘jMonkeyEngine’ nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/
package org.jme3.tests;
import java.util.prefs.BackingStoreException;
import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Transform;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.debug.Arrow;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;
public class TestMousePick extends SimpleApplication {
public static void main(String[] args) throws BackingStoreException {
TestMousePick app = new TestMousePick();
AppSettings aps = new AppSettings(true);
aps.load(aps.getTitle());
aps.setVSync(true);
app.setShowSettings(false);
app.setSettings(aps);
app.start();
}
Node shootables;
Geometry mark;
@Override
public void simpleInitApp() {
// flyCam.setEnabled(false);
flyCam.setDragToRotate(true);
flyCam.setMoveSpeed(20f);
initMark(); // a red sphere to mark the hit
/* create four colored boxes and a floor to shoot at: */
shootables = new Node(“Shootables”);
rootNode.attachChild(shootables);
shootables.attachChild(makeCube(“a Dragon”, -2f, 0f, 1f));
shootables.attachChild(makeCube(“a tin can”, 1f, -2f, 0f));
shootables.attachChild(makeCube(“the Sheriff”, 0f, 1f, -2f));
shootables.attachChild(makeCube(“the Deputy”, 1f, 0f, -4f));
shootables.attachChild(makeFloor());
shootables.attachChild(makeCharacter());
rootNode.scale(3.5f, 4.2f, 4.7f);
rootNode.rotate(FastMath.DEG_TO_RAD * 65f, FastMath.DEG_TO_RAD * 65f,
FastMath.DEG_TO_RAD * 65f);
rootNode.setLocalTranslation(0, 0, 0
// -29
);// XXX:
cam.setLocation(new Vector3f(1.4989337f, 4.4191055f, 73.00994f));
cam.setRotation(new Quaternion(-0.0011200219f, 0.9985451f,
-0.022919897f, -0.048795838f));
cam.setDirection(new Vector3f(-0.09739835f, -0.045882408f, -0.99418724f));
}
@Override
public void simpleUpdate(float tpf) {
Vector3f origin = cam.getWorldCoordinates(
inputManager.getCursorPosition(), 0.0f);
Vector3f direction = cam.getWorldCoordinates(
inputManager.getCursorPosition(), 0.3f);
direction.subtractLocal(origin).normalizeLocal();
// System.out.println( "origin: "
// + origin
// + " / dir: "
// + direction );
// Transform tr =
// rootNode.getWorldTransform();
// origin =
// tr.transformVector(
// origin,
// null );
// direction =
// tr.transformVector(
// direction,
// null );
// System.out.println( "origin : "
// + origin );
// System.out.println( "direction: "
// + direction );
Ray ray = new Ray(origin, direction);
CollisionResults results = new CollisionResults();
shootables.collideWith(ray, results);
if (results.size() > 0) {
CollisionResult closest = results.getClosestCollision();
Vector3f contact = closest.getContactPoint();
Vector3f normal = closest.getContactNormal();
System.out.println(normal.angleBetween(contact)
- FastMath.RAD_TO_DEG);
Transform tr = rootNode.getWorldTransform();
Vector3f upVec = contact.cross(normal);
upVec = tr.transformInverseVector(upVec, null);
contact = tr.transformInverseVector(contact, null);
normal = tr.transformInverseVector(normal, null);
mark.setLocalTranslation(contact);
Quaternion q =
// // tr.getRotation().clone().opposite();
new Quaternion();
// Vector3f.UNIT_Y;
// tr.transformInverseVector(
// Vector3f.UNIT_Y,
// null );
q.lookAt(normal, upVec);
// q.multLocal( tr.getRotation().inverse() );
mark.setLocalRotation(q);
// mark.lookAt(
// normal,
// upVec );
// q.subtractLocal( tr.getRotation().clone() );
// q.multLocal( tr.getRotation().inverse() );
// System.out.println( tr.getRotation(). );
rootNode.attachChild(mark);
} else {
rootNode.detachChild(mark);
}
}
/** A cube object for target practice /
protected Geometry makeCube(String name, float x, float y, float z) {
Box box = new Box(new Vector3f(x, y, z), 1, 1, 1);
Geometry cube = new Geometry(name, box);
Material mat1 = new Material(assetManager,
“Common/MatDefs/Misc/SolidColor.j3md”);
mat1.setColor(“Color”, ColorRGBA.randomColor());
cube.setMaterial(mat1);
return cube;
}
/* A floor to show that the “shot” can go through several objects. /
protected Geometry makeFloor() {
Box box = new Box(new Vector3f(0, -4, -5), 15, .2f, 15);
Geometry floor = new Geometry(“the Floor”, box);
Material mat1 = new Material(assetManager,
“Common/MatDefs/Misc/SolidColor.j3md”);
mat1.setColor(“Color”, ColorRGBA.Gray);
floor.setMaterial(mat1);
return floor;
}
/* A red ball that marks the last spot that was “hit” by the “shot”. */
protected void initMark() {
Arrow arrow = new Arrow(Vector3f.UNIT_Z.mult(2f));
arrow.setLineWidth(3);
// Sphere sphere = new Sphere(30, 30, 0.2f);
mark = new Geometry(“BOOM!”, arrow);
// mark = new Geometry(“BOOM!”, sphere);
Material mark_mat = new Material(assetManager,
“Common/MatDefs/Misc/SolidColor.j3md”);
mark_mat.setColor(“Color”, ColorRGBA.Red);
mark.setMaterial(mark_mat);
}
protected Spatial makeCharacter() {
// load a character from jme3test-test-data
Spatial golem = assetManager.loadModel(“Models/Oto/Oto.mesh.xml”);
golem.scale(0.5f);
golem.setLocalTranslation(-1.0f, -1.5f, -0.6f);
// We must add a light to make the model visible
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
golem.addLight(sun);
return golem;
}
}
/pre
- FastMath.RAD_TO_DEG);