I have problem using Vuforia with jPCT.
I have successfully passed the modelViewMatrix from Vuforia native code
QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(imageResult->getPose())
to Java.
And then I try to set the camera matrix of jPCT.
public void setCameraMatrix(float[] modelViewMatrixFromVuforia) {
float x = modelViewMatrixFromVuforia[12];
float y = modelViewMatrixFromVuforia[13];
float z = modelViewMatrixFromVuforia[14];
modelViewMatrixFromVuforia[12] = 0;
modelViewMatrixFromVuforia[13] = 0;
modelViewMatrixFromVuforia[14] = 0;
Matrix cameraMatrix = new Matrix();
cameraMatrix.setDump(modelViewMatrixFromVuforia);
cameraMatrix = cameraMatrix.invert();
camera.setBack(cameraMatrix);
camera.setPosition(x, y, z);
}
But the 3D Object is not being tracked properly. What have I missed?
I'm using this and it works perfectly:
private Matrix mMatrix = new Matrix();
...
mMatrix.setDump(modelViewMatrixFromVuforia); // float[16] sent from native code
mCamera.setBack(mMatrix);
But you have to rotate the matrix 180 degree around X axis before you send it to Java in order to match the coordinate system from Vuforia to jPCT.
Do the rotation in native codes as follows:
SampleUtils::rotatePoseMatrix(180.0f, 1.0f, 0, 0, &modelViewMatrix.data[0]);
Related
Recently i've been trying to equally distribute points over a 3d sphere surface, after some research this is my code in processing (java) :
import peasy.*;
PVector[] points_;
PVector[] generatePoints(int numberOfPoints){
PVector[] points = new PVector[numberOfPoints];
float gr = (float) (3-Math.sqrt(5));
float lambda = PI * gr;
for(int i=0; i<numberOfPoints; i++){
float t = (float)i/numberOfPoints;
float a1 = acos(1-2*t);
float a2 = lambda * i;
float x = sin(a1) * cos(a2);
float y = sin(a1) * sin(a2);
float z = cos(a1);
PVector p = new PVector(x,y,z).mult(30);
points[i] = p;
}
return points;
}
void setup(){
size(600,600,P3D);
PeasyCam cam = new PeasyCam(this,100);
cam.setMinimumDistance(50);
cam.setMaximumDistance(500);
points_ = generatePoints(1000);
}
void draw(){
background(0);
stroke(255);
strokeWeight(2);
for(int i=0; i<points_.length; i++){
point(points_[i].x,
points_[i].y,
points_[i].z);
}
}
The thing is that the points are generated following a similar algorithm to the golden spiral one, so i can not do something like draw triangles based on the actual point, the next one and the one below...
any ideas?
This is what I have.
This is what I want.
seems like the term you're looking for is triangulation. In 2D you would mostly use Delaunay-Triangulation, as it yields very pretty triangles. I have never seen it used in 3D, but according to wikipedia there seems to exist a version of it for more than two dimensions (also MATLAB offers a toolbox with 3D Delaunay).
UPDATE
Slick and JBox use radians that go in opposite directions, that's why I was having trouble.
I am making a game using JBox2D and Slick2D (per the title). So, because I couldn't find anything online about it, I wrote a bunch of code from scratch to convert between them. However, it seems as though the angles are different, even though both documentations say they use radians.
Here is my code:
//In the update function
angle = (float) (angle % 2*Math.PI);
mass = player.getMass();
position = player.getPosition();
if(input.isKeyDown(inputLeft)){
angle-=0.015f*turnBlocks.size()/mass; //turning, pt1
} else if(input.isKeyDown(inputRight)){
angle+=0.015f*turnBlocks.size()/mass;
}
player.setTransform(position, angle); //turning, pt2
if(input.isKeyDown(inputForward)){
float xv = (float)(0.25f * Math.sin(angle) *
thrustBlocks.size() / mass); //Converting angle to vector
float yv = (float)(0.25f * Math.cos(angle) *
thrustBlocks.size() / mass);
Vec2 curVel = player.getLinearVelocity();
xv = xv + curVel.x;
yv = yv + curVel.y;
player.setLinearVelocity(new Vec2(xv, yv));
}
and
//In the render function
g.setColor(Color.gray);
for(int mass = 0; mass < massBlocks.size(); mass++){
float boxx = (float)massBlocks.get(mass)[0];
float boxy = (float)massBlocks.get(mass)[1];
int[] slicklist = tr.toSlick(position.x+boxx, position.y+boxy);
boxx = (float)slicklist[0];
boxy = (float)slicklist[1];
float[] ps = {boxx-tr.xscale/2, boxy-tr.yscale/2,
boxx+tr.xscale/2, boxy-tr.yscale/2,
boxx+tr.xscale/2, boxy+tr.yscale/2,
boxx-tr.xscale/2, boxy+tr.yscale/2};
Polygon p = new Polygon(ps);
//turning, pt3
g.fill(p.transform(Transform.createRotateTransform(radAngle, slickx, slicky)));
}
When I run the above code (with the rest of it), I get the player block(s) moving in the direction it shows it is facing. However, the collision in Jbox2D is out of sync. Here is the pattern I have found:
1 unit = pi/4 in slick
Slick direction:
7___0___1
6___.___2
5___4___3
Jbox Direction:
5___0___3
2___.___6
7___4___1
Really, I have no idea what is going on. Can somebody help?
Okay. It turns out that even thought Slick's transform and JBox's angle are both radians, They go in opposite directions. So, I made the below code with the .getWorldPosition instead of transform.
float localJBoxX = thrustBlocks.get(count)[0];
float localJBoxY = thrustBlocks.get(count)[1];
float[] localEndCoords = {localJBoxX+0.5f, localJBoxY+0.5f,
localJBoxX-0.5f, localJBoxY+0.5f,
localJBoxX-0.5f, localJBoxY-0.5f,
localJBoxX+0.5f, localJBoxY-0.5f};
float[] slickCoords = new float[localEndCoords.length];
for(byte point = 0; point<localEndCoords.length/2; point++){
Vec2 localPoint = new Vec2(localEndCoords[point*2], localEndCoords[point*2+1]);
slickCoords[point*2] = (float)tr.toSlick(player.getWorldPoint(localPoint).x, player.getWorldPoint(localPoint).y)[0];
slickCoords[point*2+1] = (float)tr.toSlick(player.getWorldPoint(localPoint).x, player.getWorldPoint(localPoint).y)[1];
}
Polygon box = new Polygon(slickCoords);
g.fill(box.transform(new Transform())); //as to return a shape
I'm trying to convert a 3d point in OpenGL to a 2d point on screen to render a healthbar for a little game I'm writing. However, I'm having some trouble retrieving the x coordinate of where to draw the healthbar. Basically, the healthbar must appear to be above a player, but must always have the same width/height relative to the screen.
I tweaked a snippet of code I found from the accepted answer at Convert a 3D location to a 2D on-screen point. (XYZ => XY) and I now have this
public static int[] getScreenCoords(double x, double y, double z) {
FloatBuffer screenCoords = BufferUtils.createFloatBuffer(4);
IntBuffer viewport = BufferUtils.createIntBuffer(16);
FloatBuffer modelView = BufferUtils.createFloatBuffer(16);
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
// int[] screenCoords = new double[4];
// int[] viewport = new int[4];
// double[] modelView = new double[16];
// double[] projection = new double[16];
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
boolean result = GLU.gluProject((float) x, (float) y, (float) z, modelView, projection, viewport, screenCoords);
if (result) {
return new int[] { (int) screenCoords.get(3), (int) screenCoords.get(1) };
}
return null;
}
It seems to work fine with the y coordinate, however, x always returns 0 no matter what the angle is.
Many thanks in advance!
screenCoords.get(3) should be screenCoords.get(0) because the x position is stored at index 0. You also only actually need the capacity of screenCoords to be 3 floats, not 4.
Can someone tell me why my camera class isn't working correctly? I set the position vector to (0,0,-10) and the look at vector to (0,0,0) but when I draw something on (0,0,0) it isn't there. I'm very new to vector math and matrix stuff, so I'm betting it's LookThrough() where the problem is.
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix3f;
import org.lwjgl.util.vector.Vector3f;
public class Camera {
//3d vector to store the camera's position in
Vector3f position = null;
Vector3f lookAt = null;
//the rotation around the Y axis of the camera
float yaw = 0;
//the rotation around the X axis of the camera
float pitch = 0;
//the rotation around the Z axis of the camera
float roll = 0;
public Camera(float x, float y, float z)
{
//instantiate position Vector3f to the x y z params.
position = new Vector3f(x, y, z);
lookAt = new Vector3f();
}
public void lookThrough()
{
Matrix3f m = new Matrix3f();
Vector3f out = new Vector3f();
Vector3f.sub(position, lookAt, out);
out.normalise();
//set forward vector
m.m00 = out.x;
m.m01 = out.y;
m.m02 = out.z;
//set right vector
m.m10 = 1;
m.m11 = 0;
m.m12 = 0;
//set up vector
m.m20 = 0;
m.m21 = 1;
m.m22 = 0;
yaw = (float) -(Math.tan(m.m10/m.m00));
pitch = (float) -(Math.tan((-m.m20)/(Math.sqrt(Math.pow(m.m21, 2) + Math.pow(m.m22, 2)))));
roll = (float) -(Math.tan(m.m21/m.m22));
//roatate the pitch around the X axis
GL11.glRotatef(pitch, 1.0f, 0.0f, 0.0f);
//roatate the yaw around the Y axis
GL11.glRotatef(yaw, 0.0f, 1.0f, 0.0f);
//roatate the yaw around the Y axis
GL11.glRotatef(roll, 0.0f, 0.0f, 1.0f);
//translate to the position vector's location
GL11.glTranslatef(position.x, position.y, position.z);
}
}
There are a couple of things about your class that I would highlight:
1) You are fixing your 'right' and 'up' vectors, leaving only one degree of rotational freedom. As the camera re-orients in 3D space these will need to change. As it stands, your calculation for pitch always evaluates to 0, while your calculation to roll always evaluates to tan(1/0).
2) Though I'm not familiar with Java, you appear to be using the calculation (position - lookAt) to derive your forward vector. Ought it not be the reverse? The forward vector points away from the viewer's position.
3) Again - not familiar with java - but calling pow() to do a single multiplication is likely overkill.
1 & 2 could be the cause of your woes. Ultimately I would suggest taking a look at gluLookAt - assuming the GLU library is available in Java. If it is not, then look at the source code for gluLookAt (one variant is available here).
I'm working with a Java 3D application called "Walrus" that is used to display directed graphs. The code already has a feature to highlight a node and draw label adjacent in graph given its screen coordinates.
Upon rotating the screen, the node is no more highlighted.
What I have is the node coordinates in 3D. I need to draw label to it.
Code for highlight using 3D coordinates
Point3d p = new Point3d();
m_graph.getNodeCoordinates(node, p);
PointArray array = new PointArray(1, PointArray.COORDINATES);
array.setCoordinate(0, p);
m_parameters.putModelTransform(gc);
gc.setAppearance(m_parameters.getPickAppearance());
How can I draw Label with 3D coordinates( Raster graphics throws error Renderer: Error creating immediate mode Canvas3D graphics context )
How can I convert 3D coordinates to 2D screen and use existing code to draw label at 2D screen point
Thanks,
Dakshina
I have an algorithm/method for converting [x,y,z] into [x,y] with the depth parameter:
The x value is : (int) (x - (z / depth * x))
The y value is : (int) (y - (z / depth * y))
Essentially, the depth is the focal point. The vanishing point will be at [0,0,depth].
Here's what i used to convert my 3D coordinates into perspective 2D, x2 and y2 being the 2dimensional coordinates, xyz being the 3D coordinates.
use these formulas:
x2 = cos(30)*x - cos(30)*y
y2 = sin(30)*x + sin(30)*y + z
I picked the angle 30 as it is easy for perspective purposes, also used in Isometric grids for drawing 3D on 2D papers. As the z axe will be the vertical one, x and y are the ones at 60 degrees from it right and left. Isometric Grid Picture.
I'm still working on rotation, but without altering the axes, just coordinate rotation in 3D.
Enjoy.
I found the solution.
This is the function to display Text3D at image 2D coordinates
public void drawLabel(GraphicsContext3D gc, double x, double y, int zOffset, String s) {
boolean frontBufferRenderingState = gc.getFrontBufferRendering();
gc.setBufferOverride(true);
gc.setFrontBufferRendering(true);
Point3d eye = getEye();
double labelZ = zOffset * LABEL_Z_OFFSET_SCALE
+ LABEL_Z_SCALE * eye.z + LABEL_Z_OFFSET;
double xOffset = LABEL_X_OFFSET * m_pixelToMeterScale;
double yOffset = LABEL_Y_OFFSET * m_pixelToMeterScale;
Point3d p = new Point3d(x + xOffset, y + yOffset, 0.0);
{
// Project given (x, y) coordinates to the plane z=labelZ.
// Convert from image-plate to eye coordinates.
p.x -= eye.x;
p.y -= eye.y;
double inversePerspectiveScale = 1.0 - labelZ / eye.z;
p.x *= inversePerspectiveScale;
p.y *= inversePerspectiveScale;
// Convert from eye to image-plate coordinates.
p.x += eye.x;
p.y += eye.y;
}
Transform3D scale = new Transform3D();
scale.set(LABEL_SCALE);
Vector3d t = new Vector3d(p.x, p.y, labelZ);
Transform3D translation = new Transform3D();
translation.set(t);
translation.mul(scale);
Transform3D transform = new Transform3D(m_imageToVworld);
transform.mul(translation);
gc.setModelTransform(transform);
//-----------------
int fontSize=(int)(10*m_magnification);
if(fontSize>20)
fontSize=20;
//---------------
// XXX: Courier may not be available on all systems.
Text2D text = new Text2D(s, new Color3f(1.0f, 1.0f, 1.0f),
"Courier", fontSize, Font.BOLD);
gc.draw(text);
gc.flush(true);
// NOTE: Resetting the model transform here is very important.
// For some reason, not doing this causes the immediate
// following frame to render incorrectly (but subsequent
// frames will render correctly). In some ways, this
// makes sense, because most rendering code assumes that
// GraphicsContext3D has been set to some reasonable
// transform.
gc.setModelTransform(m_objectTransform);
gc.setFrontBufferRendering(frontBufferRenderingState);
}
This is the function to take 3D coordinates and convert them to image 2D coordinates and render using above function
private boolean displayOnScreenLabel(int node, String label) {
boolean success = false;
try {
Transform3D transform = m_parameters.getObjectToEyeTransform();
Point3d nodeC = new Point3d();
m_graph.getNodeCoordinates(node, nodeC);
transform.transform(nodeC);
Point3d eye = m_parameters.getEye();
double perspectiveScale = 1.0 / (1.0 - nodeC.z / eye.z);
double centerX = eye.x + nodeC.x * perspectiveScale;
double centerY = eye.y + nodeC.y * perspectiveScale;
GraphicsContext3D gc = m_canvas.getGraphicsContext3D();
m_parameters.drawLabel(gc, centerX, centerY, m_labelZOffsetCounter++, label);
success = true;
} catch (final java.lang.OutOfMemoryError error) {
JOptionPane.showMessageDialog(m_frame, "The 3D Graphics is unable to find enough memory on your system. Kill the application!", "Out Of Memory!", JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {
success = false;
}
return success;
}