OpenGL realistic car movement - java

I have a problem for now quite a long time...
In my OpenGL game, you can see in the picture, is a car with a height-terrain.
So to calculate the angle for the car, I created 4 Boxes, which are following around the car, so they always have the same position in relation of the car's rotation. So my algorithm for that works quite well, but when I streer the car, it gets useless, because I'm only rotating around the static X and Z axis of the cartesian-coordinate system.
Do someone know how the "move" the solid axis, so I could rotate around like custom axis? Or my second Idea was something about interpulation between Xrotation and zrotation...
Pls help :(
Here my code:
Vector3f x1 = new Vector3f(26, cubex1.getPosition().y, 0);
Vector3f x2 = new Vector3f(0, cubex2.getPosition().y, 0);
Vector3f xdif = new Vector3f(x1.x - x2.x, x1.y - x2.y, x1.z - x2.z);
float anglex = -(float) Math.toDegrees(cubex1.getPosition().angle(xdif, new Vector3f(1, 0, 0)));
if(cubex1.getPosition().y < cubex2.getPosition().y){
super.setRotX(-anglex);
}else{
super.setRotX(anglex);
}
Vector3f z1 = new Vector3f(0, cubez1.getPosition().y, 14);
Vector3f z2 = new Vector3f(0, cubez2.getPosition().y, 0);
Vector3f zdif = new Vector3f(z1.x - z2.x, z1.y - z2.y, z1.z - z2.z);
float anglez = -(float) Math.toDegrees(cubez1.getPosition().angle(zdif, new Vector3f(0, 0, 1)));
super.setRotZ(anglearoundplayer / anglez);
if(cubez1.getPosition().y < cubez2.getPosition().y){
super.setRotZ(-anglez);
}else{
super.setRotZ(anglez);
}
I am using the Vectors of different boxes the get the angle in relation of a flat surface...

Related

In ARCore, how do I best place a triangle in my world near a Pose, that I can use for ray intersection?

I'm working with ARCore in Android Studio using java and am trying to implement ray intersection with an object.
I started with Google's provided sample (as found here: https://developers.google.com/ar/develop/java/getting-started).
Upon touching the screen, a ray gets projected and when this ray touches a Plane, a PlaneAttachment (with an Anchor/a Pose) is created in the intersection point.
I would then like to put a 3D triangle in the world attached to this Pose.
At the moment I create my Triangle based on the Pose's translation, like this:
In HelloArActivity, during onDrawFrame(...)
//Code from sample, determining the hits on planes
MotionEvent tap = mQueuedSingleTaps.poll();
if (tap != null && frame.getTrackingState() == TrackingState.TRACKING) {
for (HitResult hit : frame.hitTest(tap)) {
// Check if any plane was hit, and if it was hit inside the plane polygon.
if (hit instanceof PlaneHitResult && ((PlaneHitResult) hit).isHitInPolygon()) {
mTouches.add(new PlaneAttachment(
((PlaneHitResult) hit).getPlane(),
mSession.addAnchor(hit.getHitPose())));
//creating a triangle in the world
Pose hitPose = hit.getHitPose();
float[] poseCoords = new float[3];
hitPose.getTranslation(poseCoords, 0);
mTriangle = new Triangle(poseCoords);
}
}
}
Note: I am aware that the triangle's coordinates should be updated every time the Pose's coordinates get updated. I left this out as it is not part of my issue.
Triangle class
public class Triangle {
public float[] v0;
public float[] v1;
public float[] v2;
//create triangle around a given coordinate
public Triangle(float[] poseCoords){
float x = poseCoords[0], y = poseCoords[1], z = poseCoords[2];
this.v0 = new float[]{x+0.0001f, y-0.0001f, z};
this.v1 = new float[]{x, y+ 0.0001f, z-0.0001f};
this.v2 = new float[]{x-0.0001f, y, z+ 0.0001f};
}
After this, upon tapping the screen again I create a ray projected from the tapped (x,y) part of the screen, using Ian M his code sample provided in the answer to this question: how to check ray intersection with object in ARCore
Ray Creation, in HelloArActivity
/**
* Returns a world coordinate frame ray for a screen point. The ray is
* defined using a 6-element float array containing the head location
* followed by a normalized direction vector.
*/
float[] screenPointToWorldRay(float xPx, float yPx, Frame frame) {
float[] points = new float[12]; // {clip query, camera query, camera origin}
// Set up the clip-space coordinates of our query point
// +x is right:
points[0] = 2.0f * xPx / mSurfaceView.getMeasuredWidth() - 1.0f;
// +y is up (android UI Y is down):
points[1] = 1.0f - 2.0f * yPx / mSurfaceView.getMeasuredHeight();
points[2] = 1.0f; // +z is forwards (remember clip, not camera)
points[3] = 1.0f; // w (homogenous coordinates)
float[] matrices = new float[32]; // {proj, inverse proj}
// If you'll be calling this several times per frame factor out
// the next two lines to run when Frame.isDisplayRotationChanged().
mSession.getProjectionMatrix(matrices, 0, 1.0f, 100.0f);
Matrix.invertM(matrices, 16, matrices, 0);
// Transform clip-space point to camera-space.
Matrix.multiplyMV(points, 4, matrices, 16, points, 0);
// points[4,5,6] is now a camera-space vector. Transform to world space to get a point
// along the ray.
float[] out = new float[6];
frame.getPose().transformPoint(points, 4, out, 3);
// use points[8,9,10] as a zero vector to get the ray head position in world space.
frame.getPose().transformPoint(points, 8, out, 0);
// normalize the direction vector:
float dx = out[3] - out[0];
float dy = out[4] - out[1];
float dz = out[5] - out[2];
float scale = 1.0f / (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
out[3] = dx * scale;
out[4] = dy * scale;
out[5] = dz * scale;
return out;
}
The result of this however is that, no matter where I tap the screen, it always counts as a hit (regardless of how much distance I add between the points, in Triangle's constructor).
I suspect this has to do with how a Pose is located in the world, and using the Pose's translation coordinates as a reference point for my triangle is not the way to go, so I'm looking for the correct way to do this, but any remarks regarding other parts of my method are welcome!
Also I have tested my method for ray-triangle intersection and I don't think it is the problem, but I'll include it here for completeness:
public Point3f intersectRayTriangle(CustomRay R, Triangle T) {
Point3f I = new Point3f();
Vector3f u, v, n;
Vector3f dir, w0, w;
float r, a, b;
u = new Vector3f(T.V1);
u.sub(new Point3f(T.V0));
v = new Vector3f(T.V2);
v.sub(new Point3f(T.V0));
n = new Vector3f(); // cross product
n.cross(u, v);
if (n.length() == 0) {
return null;
}
dir = new Vector3f(R.direction);
w0 = new Vector3f(R.origin);
w0.sub(new Point3f(T.V0));
a = -(new Vector3f(n).dot(w0));
b = new Vector3f(n).dot(dir);
if ((float)Math.abs(b) < SMALL_NUM) {
return null;
}
r = a / b;
if (r < 0.0) {
return null;
}
I = new Point3f(R.origin);
I.x += r * dir.x;
I.y += r * dir.y;
I.z += r * dir.z;
return I;
}
Thanks in advance!

Sphere collision test reacts too quickly

I'm writing a game for Android using Java and OpenGL. I can render everything perfectly to screen, but when I try to check whether two objects collide or not, my algorithm detects a collision before it occurs on the screen.
Here's how I test for collision:
for(int i=0; i<enemies.size(); i++) {
float enemyRadius = enemies.elementAt(i).worldSpaceBoundingSphereRadius();
float[] enemyPosition = enemies.elementAt(i).getWorldSpaceCoordinates();
for(int j=0; j<qubieBullets.size(); j++) {
float bulletRadius = bullets.elementAt(j).worldSpaceBoundingSphereRadius();
float[] bulletPosition = bullets.elementAt(j).getWorldSpaceCoordinates();
float[] distanceVector = Vector3f.subtract(enemyPosition, bulletPosition);
float distance = Vector3f.length(distanceVector);
if(distance < (enemyRadius + bulletRadius)) {
enemies.remove(i);
qubieBullets.remove(j);
i--;
j--;
// Reset enemy position
}
}
}
When the enemy cube (represented by a sphere for collision detection) closes in on the player, the player shoots a bullet (also a cube represented by a sphere) toward the enemy. My expectations are that the enemy gets reset when the bullet hits him on screen, but it happens way earlier than that.
The methods for calculation world space position and radius:
public float[] getWorldSpaceCoordinates() {
float[] modelSpaceCenter = {0.0f, 0.0f, 0.0f, 1.0f};
float[] worldSpaceCenter = new float[4];
Matrix.multiplyMV(worldSpaceCenter, 0, getModelMatrix(), 0, modelSpaceCenter, 0);
return new float[] {worldSpaceCenter[0]/worldSpaceCenter[3], worldSpaceCenter[1]/worldSpaceCenter[3], worldSpaceCenter[2]/worldSpaceCenter[3]};
}
public float worldSpaceBoundingSphereRadius() {
float[] arbitraryVertex = new float[] {1.0f, 1.0f, 1.0f, 1.0f};
float[] worldSpaceVector = new float[4];
Matrix.multiplyMV(worldSpaceVector, 0, getModelMatrix(), 0, arbitraryVertex, 0);
float[] xyz = new float[] {worldSpaceVector[0]/worldSpaceVector[3], worldSpaceVector[1]/worldSpaceVector[3], worldSpaceVector[2]/worldSpaceVector[3]};
return Vector3f.length(xyz);
}
Is it my code or math that's wrong? I can't think of anything more to try, and would be helpful if someone could point me in the right direction.
Your worldSpaceBoundingSphereRadius() is most likely the culprit. arbitraryVertex is a Vector of (1,1,1) so your math will only work if the cube model has edges of length 2 * sqrt(1/3). What you want to do is find the exact length of your cube's model's edge, use the formula from my comment (rad = sqrt( 3 * (x/2) * (x/2) )) and use that radius for your arbitraryVertex (rad,rad,rad,1).
Also, your dividing the results of your multiplication by the homogenous coordinate (worldSpaceVector[0]/worldSpaceVector[3]). With a proper rotation, translation, or scale, the homogenous coordinate should always be exactly 1 (if it started as one). If it isn't, you might have a projection matrix in there or something else that isn't a basic transformation.
EDIT:
Since you're using worldSpaceBoundingSphereRadius() to get only the radius, you want only the scaling component of getModelMatrix(). If that returns scaling and translation, this translation will apply to your radius and make it much larger than it actually is.

Billboard facing the camera has wrong rotation near 180 degrees

I've implemented a particle system. I'm drawing their textures on billboards that should be rotated towards the camera.
This works fine except for the case when the angle between particle->camera and the normal comes near to 180 degrees. Then the particle starts rotating around itself many times.
The angle is calculated using cos(angle) = dot(a, b) / (length(a) * length(b), the length are both 1 cause the Vectors are normalized.
The axis is calculated using the cross product of those two vectors.
glDisable(GL_CULL_FACE);
//calculate rotation
Vector3f normal = new Vector3f(0, 0, 1);
Vector3f dir = Vector3f.sub(new Vector3f(GraphicsData.camera.x, GraphicsData.camera.y, GraphicsData.camera.z), new Vector3f(x, y, z), null);
if(dir.length() == 0)
{
glEnable(GL_CULL_FACE);
return;
}
dir = (Vector3f) dir.normalise();
float angle = (float) Math.toDegrees(Math.acos(Vector3f.dot(normal, dir)));
Vector3f rotationAxis = Vector3f.cross(normal, dir, null);
rotationAxis = (Vector3f) rotationAxis.normalise();
System.out.println("Angle: + " + angle + " Axis: " + rotationAxis);
glBindTexture(GL_TEXTURE_2D, ParticleEngine.particleTextures.get(typeId).texture.getTextureID());
glColor4f(1f,1f,1f, time >= lifeTime - decayTime ? ((float)lifeTime - (float)time) / ((float)lifeTime - (float)decayTime) : 1f);
shaderEngine.createModelMatrix(new Vector3f(x, y, z), new Vector3f(angle * rotationAxis.x, angle * rotationAxis.y, angle * rotationAxis.z), new Vector3f(sx, sy, sz));
shaderEngine.loadModelMatrix(shaderEngine.particle);
glCallList(ParticleEngine.particleTextures.get(typeId).displayListId + textureIndex);
glEnable(GL_CULL_FACE);
What am i doing wrong calculating the rotation?
public static void createModelMatrix(Vector3f pos, Vector3f rot, Vector3f scale)
{
GraphicsData.camera.modelMatrix = new Matrix4f();
GraphicsData.camera.modelMatrix.setIdentity();
GraphicsData.camera.modelMatrix.translate(pos);
GraphicsData.camera.modelMatrix.rotate((float) Math.toRadians(rot.x), new Vector3f(1,0,0));
GraphicsData.camera.modelMatrix.rotate((float) Math.toRadians(rot.y), new Vector3f(0,1,0));
GraphicsData.camera.modelMatrix.rotate((float) Math.toRadians(rot.z), new Vector3f(0,0,1));
GraphicsData.camera.modelMatrix.scale(scale);
}
More a long comment or perhaps a partial answer to the problem:
If you are computing the cross product anyway, then use that
norm( a × b ) = sin(angle) * norm(a)*norm(b)
dot(a,b) = cos(angle) * norm(a)*norm(b)
to determine
angle = atan2( norm(a×b), dot(a,b) )

Drawing using textureRegion

I'm trying to make a movable car in java, using libgdx and box2d;
I made a car, m_car, with position set in middle of the car.
In every step, i take take the current position of the m_car, decrese that values with the cars width/height, so i have the left bottom corner. When is on a straight ground, it shows well, the texture is where is should be, but when the ground have an angle, the texture position its under, or upper the car.
I don't understand how TextureRegion works, i think that when the angle is not 0, i dont take the point of drawing well, and i dont know how to solve it. help me pls :)
Ty.
Edit:
my code is a mess, its not an actual project, its an ideea, and i took pieces, and put them down to see how they work, so when il start the project, i would know what to do, this is my car declaration:
private void car2(){
m_hz = 5.0f;
m_zeta = 0.7f;
m_speed = 50.0f;
BodyDef bd = new BodyDef();
bd.type = BodyType.DynamicBody;
part1(bd);
part2(bd);
part3(bd);
wheels(bd);
m_car.setAwake(true);
}
private void part3(BodyDef bd) {
PolygonShape shape = new PolygonShape();
shape.setAsBox(0.01f, 0.35f,new Vector2(1.01f - 3, 4.85f - 4), 0);
m_car.createFixture(shape, 1.0f);
}
private void part1(BodyDef bd){
PolygonShape chassis = new PolygonShape();
Vector2 vertices[] = new Vector2[6];
vertices[0] = new Vector2(-2, -0.5f);
vertices[1] = new Vector2(-2, 0.5f);
vertices[2] = new Vector2(1.25f, 0.5f);
vertices[3] = new Vector2(2.5f, 0.15f);
vertices[4] = new Vector2(2.5f, -0.5f);
vertices[5] = new Vector2(-2, -0.5f);
chassis.set(vertices);
bd.position.set(new Vector2(3, 4));
m_car = m_world.createBody(bd);
m_car.createFixture(chassis, 1.0f);
}
private void part2(BodyDef bd){
PolygonShape chassis = new PolygonShape();
Vector2 vertices[] = new Vector2[5];
vertices[0] = new Vector2(3, 4.5f);
vertices[1] = new Vector2(3, 5.25f);
vertices[2] = new Vector2(3.80f, 5.25f);
vertices[3] = new Vector2(4.25f, 4.5f);
vertices[4] = new Vector2(3, 4.5f);
for (int i = 0; i < 5; ++ i){
vertices[i].x -= 3;
vertices[i].y -= 4;
}
chassis.set(vertices);
//m_car = m_world.createBody(bd);
m_car.createFixture(chassis, 1.0f);
}
private void wheels(BodyDef bd){
CircleShape circle = new CircleShape();
circle.setRadius(0.4f);
FixtureDef fd = new FixtureDef();
fd.shape = circle;
fd.density = 1.0f;
fd.friction = 0.9f;
bd.position.set(2f, 3.5f);
m_wheel1 = m_world.createBody(bd);
m_wheel1.createFixture(fd);
bd.position.set(4.5f, 3.5f);
m_wheel2 = m_world.createBody(bd);
m_wheel2.createFixture(fd);
WheelJointDef jd = new WheelJointDef();
Vector2 axis = new Vector2(1.0f, 0.5f);
jd.initialize(m_car, m_wheel1, m_wheel1.getPosition(), axis);
jd.motorSpeed = 0.0f;
jd.maxMotorTorque = 20.0f;
jd.enableMotor = true;
jd.frequencyHz = m_hz;
jd.dampingRatio = m_zeta;
m_spring1 = (WheelJoint) m_world.createJoint(jd);
jd.initialize(m_car, m_wheel2, m_wheel2.getPosition(), axis);
jd.motorSpeed = 0.0f;
jd.maxMotorTorque = 10.0f;
jd.enableMotor = false;
jd.frequencyHz = m_hz;
jd.dampingRatio = m_zeta;
m_spring2 = (WheelJoint) m_world.createJoint(jd);
}
some explenation: why i have for for vertices to decreese 3 and 4 ? i didnt know that if i set position to the bodydef, the vertices consider that point to be 0, 0, when i found out, was easyer to me to just decrese (cuz its just for test, to see how it works)
and this is how i draw:
float angle = (float) Math.toDegrees(m_car.getAngle());
batch.draw(textureRegion, x, y, 3f, 4f,
4.5f, 2.75f, 1f, 0.61f, angle);
For a realistic car in Box2D you might find this useful: http://www.iforce2d.net/b2dtut/top-down-car
About your problem with the angle: You need to supply the angle of the car to the spriteBatch. TextureRegion doesn't know ANYTHING about where or how it is supposed to be rendered. You need to tell the spriteBatch about those informations.
You can use a Sprite for that. A Sprite can be manipulated with setRotation(), setPosition() etc and then being draw with Sprite.draw(spriteBatch) instead of `spriteBatch.draw(sprite)
Furthermore, be careful with your PIXEL_TO_METER conversion and remember to update your Cameras properly.

opengl camera rotation around object

I'm fighting with the code, to make it rotate camera around the object. The code that I'm using is:
eyeX = (float) (obj.x + 500*Math.cos(Math.toRadians(angle))*Math.sin(Math.toRadians(angle)));
eyeY = (float) (obj.y + 500*Math.sin(Math.toRadians(angle))*Math.sin(Math.toRadians(angle)));
eyeZ = (float) (obj.z + 500*Math.cos(Math.toRadians(angle)));
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, obj.x, obj.y, obj.z, 0, 1, 0);
Where obj is the model I want to rotate the camera around, and angle is incremented by 1 with every draw. Can somebody shed a light to this problem, what I'm doing wrong?
What exact camera motion are you trying to achieve?
If you want to turn around obj on the XZ plane while remaining at a constant height, you should do:
eyeX = (float)(obj.x + 500*Math.cos(Math.toRadians(angle));
eyeY = (float)(y0); //constant height
eyeZ = (float)(obj.z + 500*Math.sin(Math.toRadians(angle));
Also, if y0 != 0, then (0, 1, 0) is not a proper "up" vector and will distort you view.

Categories

Resources