I'm new to 3d engines in general, and I'm getting this NullPointerException when I try to collide a Geometry and a BoundingVolume object.
Here's how I declare my objects (sorry, it's rather messy at the moment)
public void simpleInitApp() {
Quad q= new Quad(100, 100);
Dome mesh = new Dome(Vector3f.ZERO, 2, 32, 1f,false);
geom = new Geometry("Cylinder", mesh); //declared elsewhere
g3 = new Geometry("lel", q);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat2.setColor("Color", ColorRGBA.Red);
geom.setMaterial(mat);
g3.setMaterial(mat2);
rootNode.attachChild(geom);
rootNode.attachChild(g3);
and here's my update loop
public void simpleUpdate(float tpf) {
// System.out.println("hi");
BoundingVolume b = g3.getWorldBound(); //should give boundingvolume of the quad
System.out.println(b.getVolume()); //just to test if this works
CollisionResults r2 = new CollisionResults(); //declare and initialize the collisionresults
geom.collideWith(b, r2); //collide
System.out.println(r2.size()); //this returns a value, usually between 0-2
for(CollisionResult x:r2){
System.out.println("x = "+ x.getContactPoint().getX());
/*and oddly enough, i get a NullPointerException here even though the collision appeared successful - this never prints anything either so it's not going out of bounds or anything*/
}
}
tl;dr-get a NullPointerException when I try to print off the coordinates of each CollisionResult from the intersection of a BoundingVolume and a Geometry
Neither the JMonkey Forums nor the JMonkey docs seem to be of any assistance. Would any of you be able to help? Thanks in advance.
Your models not attached to JBullet physics.
try sg like this:
BulletAppState buleltAppState;
public void simpleInitApp() {
Quad q= new Quad(100, 100);
Dome mesh = new Dome(Vector3f.ZERO, 2, 32, 1f,false);
geom = new Geometry("Cylinder", mesh); //declared elsewhere
g3 = new Geometry("lel", q);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat2.setColor("Color", ColorRGBA.Red);
geom.setMaterial(mat);
g3.setMaterial(mat2);
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.getPhysicsSpace().attachChild(geom);
bulletAppState.getPhysicsSpace().attachChild(g3);
rootNode.attachChild(geom);
rootNode.attachChild(g3);
}
after that you can check collision!
I've done a little research and I believe the problem is that there isn't a single collision point between 2 2D/3D objects, there is a 2D/3D collision region. Therefore null is returned as no single point is available. This is backed up by a comment by a developer. I believe the JMonkey collision detection doesn't actually calculate the intersection region because its quite mathematically complex (although it does give the triangle involved in the collision)
If both your shapes are convex you may be interested in this post on calculating 3d polygon intersections: Finding the intersection of two 3D polygons.
Related
I would like to understand one thing , below I saw that a collision between two rectangles works .
create method:
//nave
spaceShip = new Image(new TextureRegion(new Texture(Gdx.files.internal("rocket.png")),98,154));
spaceShip.setOrigin(spaceShip.getWidth()/2, spaceShip.getHeight()/2);
spaceShip.setBounds(spaceShip.getX(),spaceShip.getY(),spaceShip.getWidth(),spaceShip.getHeight());
spaceShip.setZIndex(3);
//meteora
meteora = new Image(new TextureRegion(new Texture(Gdx.files.internal("planet.png")),128,128));
meteora.setOrigin(meteora.getWidth()/2,meteora.getHeight()/2);
meteora.setPosition(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2);
meteora.setBounds(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
meteora.setZIndex(3);
Render method:
rect1 = new Rectangle(spaceShip.getX(),spaceShip.getY(),spaceShip.getWidth(),spaceShip.getHeight());
rect2 = new Rectangle(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
if(Intersector.overlaps(rect1,rect2)){
System.out.println("collision");
}
Now , my question is :
as I can see collisions with dynamic objects .
Let me explain, there will be different now created in a random time .
So how can I tell if a collision occurs with one of these objects and understand what it is .
Rectangle has no method .setName , I wanted to use this to figure out which object my ship touched .
Can anyone recommend a solution ?
Thank You
EDIT
add Image object
meteora = new Image(new TextureRegion(new Texture(Gdx.files.internal("planet.png")), 128, 128));
meteora.setOrigin(meteora.getWidth() / 2, meteora.getHeight() / 2);
meteora.setPosition(Gdx.graphics.getWidth() / 2, 100);
meteora.setZIndex(3);
Rectangle rect = new Rectangle(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
rectangles.add(rect);
I am not entirely sure what the question is, but in answer to what I think you are getting at:
Typically you would want to add all the new randomly created rectangles to a collection of rectangles, then you can iterate through this collection to check for collisions:
List<Rectangle> rectangles = new ArrayList<Rectangle>(); // a field in your class
// inside the method to create random rectangles
Rectangle tmp = new Rectangle(1,2,3,4);
rectangles.add(tmp);
// inside the method to check for collisions
for(Rectangle rect : rectangles) {
if(Intersector.overlaps(rect, shipRect) {
System.out.println("collision");
}
}
Note that your rect1 for your ship's bounds should be saved as a field (shipRect in this example) as well so that you can refer back to it at any time
So Im new to JME3 and I have a few problems understanding the BetterCharacterControl.
When I try to apply a BetterCharacterControl to a box it always "expands" from the upper part of the box instead of the center. (A picture explains that better:)
I cant find any functions to change the location it gets applied at, I already tried to create a subclass in which I changed the RigidBody to the BoxCollisionShape directly but that seems to somehow screw up the isOnGround Method. Also if I want to use slopes later it would be nice to have the capsule shape.
Box box2 = new Box(10, 15, 10);
player = new Geometry("Player", box2);
player.setLocalTranslation(new Vector3f(0, 20, 0));
Material mat = new Material(assetManager,
"Common/MatDefs/Light/Lighting.j3md");
mat.setBoolean("UseMaterialColors", true);
mat.setColor("Ambient", ColorRGBA.Blue);
mat.setColor("Diffuse", ColorRGBA.Blue);
player.setMaterial(mat);
playerC = new BetterCharacterControl(12, 30, 0);
playerC.setJumpForce(new Vector3f(0, 700, 0));
player.addControl(playerC);
rootNode.attachChild(player);
bulletAppState.getPhysicsSpace().add(playerC);
On a different note, it seems like I i have to apply a huge vector for the jump force for it to do anything (I didnt change any gravity values)
Im glad for any help
i had this same problem. The way I resolved it is not usual. I coded a class and did inherit from BetterCharacterControl overwriting getShape() method as follows:
protected CollisionShape getShape() {
//TODO: cleanup size mess..
CapsuleCollisionShape capsuleCollisionShape = new CapsuleCollisionShape(getFinalRadius(), (getFinalHeight() - (2 * getFinalRadius())));
CompoundCollisionShape compoundCollisionShape = new CompoundCollisionShape();
//Vector3f addLocation = new Vector3f(0, (getFinalHeight() / 2.0f), 0); REMOVED LINE
Vector3f addLocation = new Vector3f(0, 0, 0); //NEW LINE
compoundCollisionShape.addChildShape(capsuleCollisionShape, addLocation);
return compoundCollisionShape;
}
This works because the original code is a composite created in such a way so that the child node is offset by the value: (getFinalHeight () / 2.0f). The new line adds not realize this shift, leaving the object in the center position of the box set. However, this way of solving the problem, it can create problems when actually a composite mesh is used in the final object.
i have made a transform and rendered a Polygon object with it(mesh is of type Polygon):
at.setToTranslation(gameObject.position.x, gameObject.position.y);
at.rotate(Math.toRadians(rotation));
at.scale(scale, scale);
g2d.setTransform(at);
g2d.fillPolygon(mesh);
now i want to return the exact mesh i rendered so that i can do collision checks on it. only problem is that if i return mesh it returns the un-transformed mesh. so i tried setting the transform to the Polygon object (mesh) like so:
mesh = (Polygon)at.createTransformedShape(mesh);
but unfortunately at.createTransformedShape() returns a Shape that can only be casted to Path2D.Double. so if anyone knows how to convert Path2D.Double to Polygon or knows another way to set the transformations to the mesh please please help.
If AffineTransform#createTransformedShape doesn't provide the desired result for Polygons (as it seems to be the case), you can split the Polygon into Points, transform each Point and combine into a new Polygon. Try:
//Polygon mesh
//AffineTransform at
int[] x = mesh.xpoints;
int[] y = mesh.ypoints;
int[] rx = new int[x.length];
int[] ry = new int[y.length];
for(int i=0; i<mesh.npoints; i++){
Point2d p = new Point2d.Double(x[i], y[i]);
at.transform(p,p);
rx[i]=p.x;
ry[i]=p.y;
}
mesh = new Polygon(rx, ry, mesh.npoints)
I'm testing something with jMonkeyEngine and I'm attempting to have the camera follow a box spatial. I followed official instructions here:
http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:making_the_camera_follow_a_character
When applying, what I learnt there I produced the following code:
#Override
public void simpleInitApp() {
flyCam.setEnabled(false);
//world objects
Box b = new Box(Vector3f.ZERO, 1, 1, 1);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
geom.setMaterial(mat);
rootNode.attachChild(geom);
//Ship node
shipNode = new Node();
rootNode.attachChild(shipNode);
//Ship
Box shipBase = new Box(new Vector3f(0, -1f, 10f), 5, 0.2f, 5);
Geometry shipGeom = new Geometry("Ship Base", shipBase);
Material shipMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
shipMat.setColor("Color", ColorRGBA.Green);
shipGeom.setMaterial(shipMat);
shipNode.attachChild(shipGeom);
//Camera node
cameraNode = new CameraNode("Camera Node", cam);
cameraNode.setControlDir(ControlDirection.CameraToSpatial);
shipNode.attachChild(cameraNode);
initPhysics();
initKeys();
}
When the following code is called:
#Override
public void simpleUpdate(float tpf) {
//Update ship heading
shipHeading = shipHeading.mult(shipRotationMoment);
shipNode.setLocalRotation(shipHeading);
shipPos = shipPos.add(shipVelocity);
shipNode.setLocalTranslation(shipPos);
}
The box moves as is predicted but the camera stays where it is. The graph should be something like this:
rootNode
b (Box)
shipNode
shipBase
cameraNode
Therefore the camera should be already bound to shipNode. What am I missing?
Reading through the tutorial you provided, it seems you might have a typo. You have:
cameraNode.setControlDir(ControlDirection.CameraToSpatial);
However, the tutorial has:
//This mode means that camera copies the movements of the target:
camNode.setControlDir(ControlDirection.SpatialToCamera);
Lower down in the tutorial it defines the difference between these 2 ControlDirections. The one the tutorial provides has the camera follow the movement of the object, whereas what you have the object follows the movement of the camera.
Hope this helps.
I've been searching for a way to send a list of coord(x,y,z) to jzy3d. But without success.
The only way I found is to use a "builder" with a list of "coord3d" and a "tesselator", but it actually doesn't work.
I don't realy get the meaning of the Tesselator in fact ?
Here is the code I tried :
public Chart getChart(){
List<Coord3d> coordinates = new ArrayList<Coord3d>();
for(int i=0; i<200; i++)
coordinates.add( new Coord3d(5, 10, 15) );
Tesselator tesselator = new Tesselator() {
#Override
public AbstractComposite build(float[] x, float[] y, float[] z) {
return null;
}
};
tesselator.build(coordinates);
org.jzy3d.plot3d.primitives.Shape surface = (Shape)Builder.build(coordinates, tesselator);
/*/ Define a function to plot
Mapper mapper = new Mapper(){
public double f(double x, double y) {
return 10*Math.sin(x/10)*Math.cos(y/20)*x;
}
};*/
// Define range and precision for the function to plot
// Range range = new Range(-150,150);
// int steps = 50;
// Create the object to represent the function over the given range.
// org.jzy3d.plot3d.primitives.Shape surface = (Shape)Builder.buildOrthonormal(new OrthonormalGrid(range, steps, range, steps), mapper);
//surface.setColorMapper(new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(), surface.getBounds().getZmax(), new Color(1,1,1,.5f)));
// surface.setWireframeDisplayed(true);
// surface.setWireframeColor(Color.BLACK);
//surface.setFace(new ColorbarFace(surface));
//surface.setFaceDisplayed(true);
//surface.setFace2dDisplayed(true); // opens a colorbar on the right part of the display
// Create a chart
Chart chart = new Chart("swing");
chart.getScene().getGraph().add(surface);
return chart;
}
Could someone please tell me how to feed my graph with many XYZ coordonates so that I may get a 3d surface plot like this one :
(source: free.fr)
A tesselator allows creating polygons out of a list of points. Jzy3d provides two base tesselators: one that supports points standing on a regular grid (called OrthonormalTesselator), one that supports unstructured points as input (DelaunayTesselator). The second one is not always "working good": not a problem concerning its implementation but mainly the fact that it's difficult to decide how points should work together to form a polygon in 3d. You may find some discussions about it on Jzy3d wiki and discussion groups.
To manually build polygons, here's what you should do:
// Build a polygon list
double [][]distDataProp = new double[][] {{.25,.45, .20},{.56, .89, .45}, {.6, .3,.7}};
List<Polygon> polygons = new ArrayList<Polygon>();
for(int i = 0; i < distDataProp.length -1; i++){
for(int j = 0; j < distDataProp[i].length -1; j++){
Polygon polygon = new Polygon();
polygon.add(new Point( new Coord3d(i, j, distDataProp[i][j]) ));
polygon.add(new Point( new Coord3d(i, j+1, distDataProp[i][j+1]) ));
polygon.add(new Point( new Coord3d(i+1, j+1, distDataProp[i+1][j+1]) ));
polygon.add(new Point( new Coord3d(i+1, j, distDataProp[i+1][j]) ));
polygons.add(polygon);
}
}
// Creates the 3d object
Shape surface = new Shape(polygons);
surface.setColorMapper(new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(), surface.getBounds().getZmax(), new org.jzy3d.colors.Color(1,1,1,1f)));
surface.setWireframeDisplayed(true);
surface.setWireframeColor(org.jzy3d.colors.Color.BLACK);
chart = new Chart();
chart.getScene().getGraph().add(surface);