Camera movement around the model - java

I want to make my camera move behind the model when it rotates, just like in a Third Person Perspective game - to have it "look" always on the back of the model. Im provided with a framework so the syntax may be bit different than normal opengl. I use the standard camera
Mat4 mv = MatrixMath.lookAt(this.eyeX,this.eyeY,this.eyeZ,this.at,this.up);
and to rotate the camera i tried
this.mouseRotation += 20.0f;
this.eyeX = (float) Math.sin(this.mouseRotation / 180.0f * 3.14f) * 2.0f;
this.eyeZ = (float) Math.cos(this.mouseRotation / 180.0f * 3.14f) * 2.0f;
mouseRotation is the angle which the model is located so obviously the camera should be also move to a position located 20 degrees further on the "circle". But instead of this the object rotates around itself, and the camera makes a circular movement but not around the model, but next to it, still looking at the same point.
Any ideas how to make this work?

From your example, I believe the short answer is to add this.at (which should be the position of your object) into your this.eye so that that the eye is positioned relative to the object.
In more detail, say your object's position is at this.at, and you want the camera to follow the object at some distance, say 'd' "behind" the object. If you have a unit vector (i.e., one's whose length is 1.0) pointing out of the front of the object, then the this.at - d should be the position of the camera (i.e., this.eye). In order to get the camera to rotate around the object, first apply a rotation to 'd' (in the example above, you appear to be rotating around the 'Y' axis [since you're only modifying eyeX and eyeZ]), so that
this.eye = this.at - rotation(Y) * d;

Related

can't implement the movement of 2d mechanism

I implement Chebyshev walking mechanism, like this
And I've got a problem so the edges of the mech don't move like they're meant to
For now I have a GUI with some controls using Java8 Swing, it draws a mech, but movement is a problem as i said
here is my GitHub and the class with a problem method DFS_movement()
So I want this mech to move like the actual one with the constant lengths of the edges an all this stuff
Maybe you need the formulas, i.e. the equations of the position (x,y) of the end that moves (almost) along a straight line with respect to the rotation angle a (that describes the circular motion of the "first" bar)? Here the origin of the coordinate system is at the point of rotation of the first bar and the rotation angle a is the angle between the first bar and the horizontal x-axis. If that is the case, the equations are:
x = 2*A - 2*A*sqrt( (5 + cos(a))/(5 - 4*cos(a)) )*sin(a)
y = 2*A*sqrt( (5 + cos(a))/(5 - 4*cos(a)) )*(2 - cos(a))
A is the length of the first barm the one that rotates around its fixed end, attached to the origin of the coordinate system. The distance between the origin and the other fixed point of the linkage is 2A.

Box2D - Controlled Movement with Physics

I am creating a Java desktop 2D Game using LibGDX.
I need to be able to move objects (controlled by the player with W/A/S/D).
The movement speed is always the same (read out from a field of the moving object).
While they are moving, they should still be affected by physics.
This means that when moving away from a magnet would make you move slower, moving towards it makes you faster and moving past it would cause you to move a curve. (see blue part of image)
Also a single impulse in while moving would knock you away but you keep moving (see red part of image)
You should also be able to change direction or stop, only stopping your own movement, so you will still be affected by physics.
So I need to apply constant forces that will still be accessible (and removable) after the next step.
Can I do this with Box2D?
-If yes, how?
-If no, any other libraries that can do this? I don't really need density and stuff like that, the use cases in the image is pretty much all I need (+ Collision Detection).
*A magnet would be a body constantly pulling other bodies in a certain range to itself
*Kockback would just be a simple impulse or the collision of a projectile with the object.
EDIT: If you know The Binding of Isaac, thats the kinda physics I'm aiming for.
Set the distance where the magnet has his influence:
float magnetRadius = 30;
Set the attractive force of the magnet:
float magnetForce = 400;
Get the position of the player and of the magnet:
Vector2 magnetPos = magnet.getWorldCenter();
Vector2 playerPos = player.getWorldCenter();
Now calculate the distance between the player and the magnet:
Vector2 magnetDist = new Vector2((playerPos.x - magnetPos.x), (playerPos.y - magnetPos.y));
float distance = (float) Math.sqrt((magnetPos.x) * (magnetPos.x) + (magnetPos.y) * (magnetPos.y));
Then, if the player is inside the magnet's radius, you must apply a force to him that depends on the distance of the player from the magnet:
if (distance <= magnetRadius) {
float vecSum = Math.abs(magnetDist.x)+Math.abs(magnetDist.y);
Vector2 force = new Vector2((magnetForce*magnetDist.x * ((1/vecSum)*magnetRadius/distance)), (magnetForce*magnetDist.y * ((1/vecSum)*planetRadius/distance)));
player.applyForceToCenter(force, true);
}

Quaternion rotations based on vector and point

I have a program I'm building that uses 3D.
It is basically made of an object (some kind of a cube) that users can rotate and move around, while I can watch their view of the object by inspecting the same object on the server with an arrow directed at their point of view.
The client sends it's location, direction facing, and up as 3 vectors to the server.
I am trying to get my arrow to be rendered based off their location and rotation.
I'm doing this with the following code (using LibGDX for 3D):
Vector3[] vs;
Vector3 tmp = new Vector3();
batch.begin(wm.cam);
for (SocketWrapper s : clientAtt.keySet()) {// for every client
vs = clientAtt.get(s); // read the 3 vectors: { position, direction, up }
tmp.set(vs[2].nor());
vs[1].nor();
// arr.transform is the transform of the arrow
arr.transform.set(vs[0], new Quaternion().setFromCross(tmp.crs(Vector3.Z).nor(), vs[1]));
batch.render(arr);
}
And this is the definition of arr:
arrow = new ModelBuilder().createArrow(0, 0, 0, 1, 0, 0, 0.1f, 0.1f, 5, GL20.GL_TRIANGLES, new Material(ColorAttribute.createDiffuse(Color.RED)), VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal);
arr = new ModelInstance(arrow);
If I only rotate around the Y axis, everything works, but if I use the X/Z axis it goes crazy.
I'm trying to figure out where my math is wrong and how to fix it.
Thanks.
Quaternion is used to define only a rotation, not the orientation. For example: it defines how to transform any given (unit) vector to another vector so that it is rotated the amount you specified. But it does not define which vector that is. Even more: there are an infinite amount of possible transformations that can achieve that.
The setFromCross method lets you specify that rotation by providing two arbitrary vectors. The Quaternion will then be set so that it would transform the first vector to the second vector, by rotating it around an axis perpendicular to the vectors you provided.
So, in your case:
setFromCross(tmp.set(up).crs(Vector3.Z).nor(), direction)
This sets the Quaternion so that it would rotate the cross product of your up vector and the Z+ vector to your direction vector, along the axis that is perpendicular to those two vectors. That might work for you in some cases, but I doubt that is what you actually want to do. So, to answer your question: that is probably where your math goes wrong.
Although this goes beyond the scope of your question, let's look at how you could achieve what you want to achieve.
First define the orientation of your model when it is not rotated. E.g. which side is up, which side is forward (direction) and which side is right (or left). Let's assume for this case that, in rest, your model's up side it Y+ (upRest = new Vector3(0, 1, 0);), it is facing X+ (directionRest = new Vector3(1, 0, 0)) and it's right is Z+ (rightRest = new Vector3(0, 0, 1);).
Now define the rotated orientation you want to have. You already have that, except for the right for which we can use the cross product (perpendicular) vector: upTarget = new Vector3(vs[2]).nor(); directionTarget = new Vector3(vs[1]).nor(); rightTarget = new Vector3().set(upTarget).crs(directionTraget).nor(); Note that you might need to swap the up and direction target vectors in the cross product (.set(directionTarget).crs(upTarget).nor();)
Because the orientation in rest is axis aligned, we can take a nice little shortcut by one of the properties of a matrix. A Matrix4 can be defined as: a vector of 4 vectors. The first of those four vectors specifies the rotated X axis, the second specifies the rotated Y axis, the third vector specifies the rotated Z vector and the fourth vector specifies the location. So, use this one-liner to set the model to the orientation and position we want:
arr.transform.set(directionTarget, upTarget, rightTarget, vs[0]);

Java3D: Rotating the universe by increments

I'm trying to develop a Java3D method for rotating the universe in increments from the current viewing direction to the direction at the center of an object.
In other words, I want the 3D universe to rotate in, say, 100 short steps, so that an object that I click on appears to move gradually to the center of the screen.
I've reviewed the various answers to 3D rotation questions here on StackOverflow (as well as on the Web), but pretty much all of them are specific to rotating objects, not the world itself.
I've also tried to review my linear algebra, but that's not helping me to identify Java-specific functions that accomplish my requirements.
So far I've tried defining a set of incremental XYZ coordinates and dynamically using lookAt() in each pass through the loop. That almost works, but I don't see any way to preserve or obtain viewpoint values from one complete rotation pass to the next; each rotation pass starts out looking at the origin.
I've also tried defining a rotation matrix by obtaining the difference between the target and start transforms and dividing by the number of increments (and removing the scaling value), then adding that incremental rotation matrix to the current view direction at each pass through the loop. That works just fine for an increment value of 1. But splitting the rotation into two or more increments always generates the "BadTransformException: Non-congruent transform above ViewPlatform" error. (I've read the meager documentation of this exception in the Java3D API reference; it might as well have been written in Urdu for all I could make out from it. There seems to be no plain-English definition of 3D-context terms like "affine" or "shear" or "congruent" or "uniform" anywhere that Google can see.)
I then tried to cudgel my code into providing an AxisAngle4d, obtaining the angle (in radians), dividing that angle into my desired increments, and rotating by the incremental angle value. That rotated the world, all right, but nowhere near the object I picked, and not to any pattern I could see.
In desperation I tried using rotX and rotY (setting Z to the endpoint) on the extracted angle, and even blindly threw a couple of Math.cos() and Math.sin() wrappers in there. Still no joy.
My instincts are telling me that I've got the basics in place and that there's a relatively simple solution in Java3D. But clearly there's a comprehension wall I'm hitting. Rather than continue that, I thought I'd go ahead and see if anyone here can suggest a solution in Java3D. Code is preferred, but I'm willing to try to follow an explanation in linear algebra if that will get me to a code solution.
Below is the core of the method I'm using to schedule rotation increments using Java's Timer method. The part I need help with is just before the ActionListener. Presumably that's where the magic code would go that creates some kind of incremental rotation value I can apply (in the loop) to the current view direction in order to rotate the universe without getting "non-congruent" errors.
private void flyRotate(double endX, double endY, double endZ)
{
// Rotate universe by increments until target object is centered in view
//
// REQUIREMENTS
// 1. Rotate the universe by NUMROTS increments from an arbitrary (non-origin)
// 3D position and starting viewpoint to an ending viewpoint using the
// shortest path and preserving the currently defined "up" vector.
// 2. Use the Java Timer() method to schedule the visual update for each
// incremental rotation.
//
// GLOBALS
// rotLoop contains the integer loop counter for rotations (init'd to 0)
// viewTransform3D contains rotation/translation for current viewpoint
// t3d is a reusable Transform3D variable
// vtg contains the view platform transform group
// NUMROTS contains the number of incremental rotations to perform
//
// INPUTS
// endX, endY, endZ contain the 3D position of the target object
//
// NOTE: Java3D v1.5.1 or later is required for the Vector3D getX(),
// getY(), and getZ() methods to work.
final int delay = 20; // milliseconds between firings
final int pause = 10; // milliseconds before starting
// Get translation components of starting viewpoint vector
Vector3d viewVector = new Vector3d();
viewTransform3D.get(viewVector);
final double startX = viewVector.getX();
final double startY = viewVector.getY();
final double startZ = viewVector.getZ();
// Don't try to rotate to the location of the current viewpoint
if (startX != endX || startY != endY || startZ != endZ)
{
// Get a copy of the starting view transform
t3d = new Transform3D(viewTransform3D);
// Define the initial eye/camera position and the "up" vector
// Note: "up = +Y" is just the initial naive implementation
Point3d eyePoint = new Point3d(startX,startY,startZ);
Vector3d upVector = new Vector3d(0.0,1.0,0.0);
// Get target view transform
// (Presumably something like this is necessary to get a transform
// containing the ending rotation values.)
Transform3D tNew = new Transform3D();
Point3d viewPointTarg = new Point3d(endX,endY,endZ);
tNew.lookAt(eyePoint,viewPointTarg,upVector);
tNew.invert();
// Get a copy of the target view transform usable by the Listener
final Transform3D tRot = new Transform3D(tNew);
//
// (obtain either incremental rotation angle
// or congruent rotation transform here)
//
ActionListener taskPerformer = new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
if (++rotLoop <= NUMROTS)
{
// Apply incremental angle or rotation transform to the
// current view
t3d = magic(tRot);
// Communicate the rotation to the view platform transform group
vtg.setTransform(t3d);
}
else
{
timerRot.stop();
rotLoop = 0;
viewTransform3D = t3d;
}
}
};
// Set timer for rotation steps
timerRot = new javax.swing.Timer(delay,taskPerformer);
timerRot.setInitialDelay(pause);
timerRot.start();
}
}
As is often the case with these things, there may be a better way to do what I'm trying to accomplish here by stepping back and rethinking the problem. I'm open to constructive suggestions there as well.
Thanks very much for any assistance with this!
UPDATE
Let me try to define the goal a little more concretely.
I have a Java3D universe containing many Sphere objects. I can click on each object and dynamically obtain its predefined XYZ coordinates.
At any moment, I am looking at all currently visible objects with a "camera" at a particular XYZ position and a view direction, which are contained in a transform holding the rotation matrix and translation vector.
(Note: I can both rotate the universe and translate through it using the mouse independently of clicking on objects. So there will be times when the view transform containing the camera's current rotation matrix and translation vector is not pointing at any target object with known XYZ coordinates.)
Given the camera transform and the object's XYZ coordinates, I want to rotate the universe around my current camera position until the selected object is centered in the screen. And I want to do this as a sequence of discrete incremental rotations, each of which is rendered so that the visible universe appears to "spin" in the viewing window until the selected object is centered. (I'm following this up with a translation to the object; that part at least is working!)
Example: Suppose the camera is at the origin, "up" is 1.0 along the Y-axis, and the selected object is centered ten units directly to my left. Assuming I had a 180-degree field of view, I could click on the half of the sphere that is visible all the way to the left of the screen and halfway between the top and bottom of the screen.
When I give the word, every visible object in the universe should appear to move in a sequence of evenly-spaced steps (let's say 50) from my left to my right until the selected object is exactly centered in the screen.
In coding terms, I need to work out the Java3D code by which I can rotate the universe around an imaginary line that runs through my camera position (currently at 0,0,0) and that is perfectly aligned with the Y-axis of the universe's coordinate system. (I.e., the axis of rotation sweeps through a plane where Z is always equal to the Z component of the camera's position.)
The complicating requirements are:
The camera can be translated somewhere in 3D space other than the origin.
Objects can be anywhere in 3D space with respect to the camera's current position and view, including being visible but off the screen (outside the view frustum) entirely.
Rotations should take the shortest path -- no spinning the universe more than 180 degrees at a time.
There should not be any "jump" or "twisting" of the visible universe as the first step in the rotation process; i.e., the current "up" vector (not the universe's absolute "up" vector) should be preserved.
So there's the question: given a transform holding the (virtual) camera's current translation and rotation information, and the XYZ coordinates in universe space of a target object, what Java3D code will rotate the universe around the camera in N equal steps until the object is centered in the screen?
Presumably this solution is in two parts: first, some 3D math (expressed in Java3D) to calculate the incremental rotation information given only the camera transform and object's XYZ coordinates; second, a loop that [applies the incremental rotation to the current viewing transform and updates the screen] until the loop counter equals the number of increments.
It's that 3D math part that's beating me. I'm not seeing and can't bash out a way to obtain some form of incremental rotation information from the current camera transform and target object position that I can then apply to the camera transform. At least, I haven't found any way that doesn't cause jumping or twisting or unequal incremental movement steps (or a "non-congruent transform above ViewPlatform" exception).
There must be a simple solution....
So if I understand correctly, your goal is to rotate the camera so it centers on the selected object, but that rotation should not be about an arbitrary vector, but instead should preserve the camera's "up" direction.
A solution that might work then:
First, calculate the rotation angle (let's call it A) about the "up" vector necessary so that the camera is facing the object you want.
Second, calculate the translation distance/direction (let's call it D) necessary along the "up" vector so that the object lines up as necessary with the camera. This will likely just be the difference in the Z/Y coordinate between the camera/object.
Find dA and dD by diving A/D by N, the number of increments you want to take to smooth the motion.
In a timer/time loop increment A/D by dA/dD respectively N times, taking them to the final values. Remember that you are rotating the camera about it's "up" vector and current location, not about the origin..
If you want an even smoother, more realistic looking rotation, consider using SLERP.

Perspective 3D Projection in Java

I'm working on creating a simple 3D rendering engine in Java. I've messed about and found a few different ways of doing perspective projection, but the only one I got partly working had weird stretching effects the further away from the centre of the screen the object was moved, making it look very unrealistic. Basically, I want a method (however simple or complicated it needs to be) that takes a 3D point to be projected and the 3D point and rotation (possibly?) of the 'camera' as arguments, and returns the position on the screen that that point should drawn at. I don't care how long/short/simple/complicated this method is. I just want it to generate the same kind of perspective you see in a modern 3D first person shooters or any other game, and I know I may have to use matrix multiplication for this. I don't really want to use OpenGL or any other libraries because I'd quite like to do this as a learning exercise and roll my own, if it's possible.
Any help would be appreciated quite a lot :)
Thanks, again
- James
Update: To show what I mean by the 'stretching effects' here are some screen shots of a demo I've put together. Here a cube (40x40x10) centered at the coords (-20,-20,-5) is drawn with the only projection method I've got working at all (code below). The three screens show the camera at (0, 0, 50) in the first screenshot then moved in the X dimension to show the effect in the other two.
Projection code I'm using:
public static Point projectPointC(Vector3 point, Vector3 camera) {
Vector3 a = point;
Vector3 c = camera;
Point b = new Point();
b.x = (int) Math.round((a.x * c.z - c.x * a.z) / (c.z - a.z));
b.y = (int) Math.round((a.y * c.z - c.y * a.z) / (c.z - a.z));
return b;
}
You really can't do this without getting stuck in to the maths. There are loads of resources on the web that explain matrix multiplication, homogeneous coordinates, perspective projections etc. It's a big topic and there's no point repeating any of the required calculations here.
Here is a possible starting point for your learning:
http://en.wikipedia.org/wiki/Transformation_matrix
It's almost impossible to say what's wrong with your current approach - but one possibility based on your explanation that it looks odd as the object moves away from the centre is that your field of view is too wide. This results in a kind of fish-eye lens distortion where too much of the world view is squashed in to the edge of the screen.

Categories