I know I shouldn’t be using negative params when calling setLocalScale right?
But if I do, the Box I’m trying to collide a Ray with won’t intersect in some places depending on the Ray angle.
Unless I’m missing something, I would suggest maybe to either make a comment saying scale params should never be negative or better yet enforce this in jme inside the setLocalScale
method or something? this might be useful to catch bugs if caller(/user) is using parameter variables that mistakenly go negative without user’s knowledge, some collisions won’t happen due to that…
Here’s the testcase with “XXX:” marked on the line with the negative scale params already set, just move the mouse over the Box to generate randomColor normals and see how in some places on the Box no normal will be added (due to no collisions detected); to fix this remove the two “-” signs from params on setLocalScale
pre type="java"
package org.jme3.tests;
import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
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.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.debug.Arrow;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Line;
import com.jme3.system.AppSettings;
public class TranslationWickedtry extends SimpleApplication {
private Node collidables;
// private Node nodeLine;
private Node subRoot;
private final static String mapToggleSubNodeTransform = “mapToggleSubNodeTransform”;
private static final float lineWidth = 5f;
private BitmapText helloText;
public static void main(String[] args) {
TranslationWickedtry app = new TranslationWickedtry();
AppSettings aps = new AppSettings(true);
// aps.load(aps.getTitle());
aps.setVSync(true);
app.setShowSettings(false);
app.setSettings(aps);
app.start();
}
@Override
public void simpleInitApp() {
flyCam.setDragToRotate(true);
flyCam.setMoveSpeed(20f);
cam.setLocation(new Vector3f(61.42587f, -145.20616f, 13.512871f));
cam.setRotation(new Quaternion(0.5186105f, 0.4658943f, -0.41162565f,
0.5869838f));
cam.setDirection(new Vector3f(0.1199981f, -0.99238f, 0.027971268f));
subRoot = new Node();
rootNode.attachChild(subRoot);
subRoot.setLocalScale(-4f, 11f, -6f);// XXX: make all positive to fix
subRoot.setLocalRotation(new Quaternion().fromAngles(
FastMath.DEG_TO_RAD 38, FastMath.DEG_TO_RAD 12,
FastMath.DEG_TO_RAD 154));
subRoot.setLocalTranslation(3f, 8f, 12f);
// nodeLine = new Node();
// rootNode.attachChild(nodeLine);
/** create four colored boxes and a floor to shoot at: /
collidables = new Node(“collidables”);
subRoot.attachChild(collidables);
Box meshBox = new Box(new Vector3f(-2, 0, 1), 1, 1, 1);
Geometry geoBox = new Geometry(“Boxy”, meshBox);
Material matBox = new Material(assetManager,
“Common/MatDefs/Misc/WireColor.j3md”);
matBox.setColor(“Color”, ColorRGBA.Orange);
geoBox.setMaterial(matBox);
collidables.attachChild(geoBox);
transformSubNode();
Node coord = new Node();
attachCoordinateAxes(Vector3f.ZERO, coord);
rootNode.attachChild(coord);
inputManager.addMapping(mapToggleSubNodeTransform, new KeyTrigger(
KeyInput.KEY_SPACE));
inputManager.addListener(actionListener, mapToggleSubNodeTransform);
// ========
helloText = new BitmapText(guiFont, false);
helloText.setSize(guiFont.getCharSet().getRenderedSize());
helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
helloText.setText(“press SPACE to toggle subNode’s transform”);
guiNode.attachChild(helloText);
}
private void transformSubNode() {
collidables.setLocalTranslation(11, 17, -29);
collidables.scale(2.3f, 4.2f, 7.1f);
collidables.rotate(FastMath.DEG_TO_RAD 35f,
FastMath.DEG_TO_RAD 35f, FastMath.DEG_TO_RAD * 35f);
}
private final ActionListener actionListener = new ActionListener() {
@SuppressWarnings(“synthetic-access”)
@Override
public void onAction(String name, boolean isPressed, float tpf) {
do {
if ((mapToggleSubNodeTransform == name) && (isPressed)) {
// FIXME: implement Transform.equals() or .isIdentity()?
// if
// (subNode.getLocalTransform().equals(Transform.IDENTITY))
// {
// subNode.getLocalRotation().equals(o)
if (collidables.getLocalTransform().getTranslation().getX() == 0) {
helloText.setText(“subNode is transformed”);
transformSubNode();
} else {
helloText.setText(“subNode is NOT transformed”);
collidables.setLocalTransform(Transform.IDENTITY);
}
break;
}
} while (false);
}
};
@Override
public void simpleUpdate(float tpf) {
Vector3f origin = cam.getWorldCoordinates(
inputManager.getCursorPosition(), 0.0f);
Vector3f direction = cam
.getWorldCoordinates(inputManager.getCursorPosition(), 0.3f)
.subtractLocal(origin).normalizeLocal();
Ray ray = new Ray(origin, direction);
CollisionResults results = new CollisionResults();
collidables.collideWith(ray, results);
if (results.size() > 0) {
CollisionResult closest = results.getClosestCollision();
// world coord of the contact
Vector3f normalStartPoint = closest.getContactPoint().clone();
// the direction of the normal, normalized already:
Vector3f normalDirection = closest.getContactNormal();
if (!normalDirection.isUnitVector()) {
// was not normalized?! impossible
throw null;
}
// normalVec is a point on the
normal to the surface
Vector3f normalEndPoint = normalStartPoint.add(normalDirection
.mult(10f));
// the vector perpendicular on both
contact
and normal
vectors// Vector3f upVec = contact.cross(normalVec).normalizeLocal();
// nodeLine.setLocalTransform(subRoot.getLocalTransform().clone());
// normalStartPoint = nodeLine.worldToLocal(normalStartPoint, null);
// normalEndPoint = nodeLine.worldToLocal(normalEndPoint, null);
Line line = new Line(normalStartPoint, normalEndPoint);
Geometry geoLine = new Geometry(“line1”, line);
Material mark_mat = new Material(assetManager,
“Common/MatDefs/Misc/SolidColor.j3md”);
mark_mat.setColor(“Color”, ColorRGBA.randomColor());
geoLine.setMaterial(mark_mat);
// nodeLine.attachChild(geoLine);
rootNode.attachChild(geoLine);// rootNode is not transformed
// Q.assumedTrue(nodeLine.getLocalTransform().equals(Transform.IDENTITY));
}
}
private void attachCoordinateAxes(Vector3f pos, Node toNode) {
Arrow arrow = new Arrow(Vector3f.UNIT_X);
// make arrow thicker,
arrow.setLineWidth(lineWidth);
putShape(arrow, ColorRGBA.Red, toNode).setLocalTranslation(pos);
arrow = new Arrow(Vector3f.UNIT_Y);
arrow.setLineWidth(lineWidth); // make arrow thicker
putShape(arrow, ColorRGBA.Green, toNode).setLocalTranslation(pos);
arrow = new Arrow(Vector3f.UNIT_Z);
arrow.setLineWidth(lineWidth); // make arrow thicker
putShape(arrow, ColorRGBA.Blue, toNode).setLocalTranslation(pos);
}
private Geometry putShape(Mesh shape, ColorRGBA color, Node onNode) {
Geometry g = new Geometry(“coordinate axis”, shape);
Material mat = new Material(assetManager,
“Common/MatDefs/Misc/Unshaded.j3md”);
mat.getAdditionalRenderState().setWireframe(true);
mat.setColor(“Color”, color);
g.setMaterial(mat);
onNode.attachChild(g);
// g.setCullHint(CullHint.Inherit);
return g;
}
}
/pre