PDA

View Full Version : 2d rectangle between 2 objects in 3d

jmanji
11-18-2010, 04:49 AM
This drives me mad for two days now and is hard for me to explain. Let's say we have 2 objects in a scene, one at (0,0,0) and another moving one that is now located further, at (1,0,-1). How could I draw a 2d rectangle between them? I have tried many trigonometric functions with no luck. Is there any way to map the second object's coordinated on the first object's z coordinate? Thank you.

jmanji
11-18-2010, 05:09 AM
I did not mention that the rectangle has fixed width(not length) and the objects will be at the middle of two opposite sides(with the fixed width).

strattonbrazil
11-18-2010, 08:37 AM
Yeah, it is difficult to understand what you want. Let me make a few assumptions. First, your rendering from a perspective camera so your scene is in 3d. Second, since all rectangles are 2d, I assume when you say 2d rectangle, you want it drawn in screen space, correct? By that I mean as the two objects move around, the rectangle's sides remains parallel to the viewport. In this isn't the case, a picture is worth a thousand words.

Anyway, I'm assuming you just want to render a square in 2d based on where your 3d objects fall on the screen. To do this, use gluProject. That will tell you where (0,0,0) and (1,0,-1) fall on the screen and you just do the 2d math accordingly.

jmanji
11-18-2010, 09:18 AM
You are right, I made quickly a (sucky)picture to express what I mean. The camera is behind object A and a little higher than it. Object B moves around object A(in front of it) in all axes. http://imgur.com/BaYfj.jpg

The context behind this, is that I want to render a 2D laser beam texture. After finding this rectangle, I could add a little depth to it, but the thing is that it must always face the camera, have fixed width and always be orthogonal.

I was aware of gluProject, but isn't it a little slow? After finding the screen coordinates, shouldn't I switch to orthographic projection? I was hoping there was another way. Actually I was looking for global coordinates in my scene and not screen coordinates.

strattonbrazil
11-18-2010, 09:56 AM
I'll start backwards. gluProject is slow but only relative to really fast operations. Using gluProject is a CPU operation and isn't terrible if you only do it a couple of times as opposed to running your entire mesh through it. It's the same with switching to an orthographic projection. Most games do a perspective projection than switch to orthographic to render the HUD. This isn't expensive compared to the bottleneck of shading and vertex processing usually. Of course switching back and forth repeatedly per frame is a little silly.

The picture really helps. Is the width of the laser relative to object A or the screen? i.e. if object A gets bigger, does the laser?

jmanji
11-18-2010, 10:20 AM
Thank you for you time so far strattonbrazil. I use a HUD anyway, but until now I do not do it in orthographic. As I mentioned, I was hoping that after finding how to render this rectangle, then in perspective projection I could add some depth according to the object B's depth. because the laser beam should look like heading somewhere in front. In orthographic I believe that extra calculations on the vertices are required to achieve this effect of depth (because I think depth is not visible in this projection). Also I believe that there must be another way, because I have tried using several sin and cos combinations depending on the camera angle and object B's movement and the result is close what I want, but not quite there.

Answering you question, if object A gets closer to the camera, I guess the laser should also become bigger, at least at its base. If in perspective projection, of course this will be done automatically as the camera moves.

If I do not come up with something, I will try orthographic or just think of another way.

strattonbrazil
11-18-2010, 10:56 AM
The all depends on your camera's orientation. The way you described won't actually require an orthographic projection. Here's what I would do.

First, calculate the vector from object A to object B (let's call it AB). This will be the vector along which the length of the rectangle runs. Now, we need a basis vector going off to the side. That can be your up vector of the camera. First, rotate this vector by the screen angle of AB so that the new angle is perpendicular to AB. Let's call that vector X. Make sure X is normalized and multiply it by half the width you want the laser to be in world space.

If all that is done properly, here are your coordinates of the rectangle:

v1: (objectA pos) + X
v2: (objectA pos) + X + AB
v3: (objectA pos) - X + AB
v4: (objectA pos) - X

The only tricky part of all this is to make sure you rotate the basis vector correctly so it rotates around your look vector.

jmanji
11-18-2010, 11:03 AM
Wow, thanx! I will try this and write here the results.

jmanji
11-18-2010, 02:17 PM
Ok, I think we are quite close, but not there yet. Maybe I did something wrong, I am noob after all. Here is my code(LWJGL), using your terms:

Vector3f AB = new Vector3f(xPosTarget- xPos,
yPosTarget - yPos,
zPosTarget - zPos);

Vector3f X = new Vector3f(0.0f, 1.0f, 0.0f);

//Rotate camera up vector around x axis
X.setY(X.y*(float)Math.cos(Math.toRadians(Camera.g etYAngle()))
-X.z*(float)Math.sin(Math.toRadians(Camera.getYAngl e())));

X.setZ(X.y*(float)Math.sin(Math.toRadians(Camera.g etYAngle()))
+ X.z*(float)Math.cos(Math.toRadians(Camera.getYAngl e())));

//Rotate camera up vector around y axis
X.setX(X.x*(float)Math.cos(Math.toRadians(90-MouseHandler.getXAngle())) +
X.z*(float)Math.sin(Math.toRadians(90-MouseHandler.getXAngle())));

X.setZ(-X.x*(float)Math.sin(Math.toRadians(90-MouseHandler.getXAngle())) +
X.z*(float)Math.cos(Math.toRadians(90-MouseHandler.getXAngle())));

X.normalise();

GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex3f(xPos + X.x, yPos + X.y, zPos + X.z);
GL11.glVertex3f(xPos + X.x + AB.x, yPos + X.y + AB.y, zPos + X.z + AB.z);
GL11.glVertex3f(xPos - X.x + AB.x, yPos - X.y + AB.y, zPos - X.z + AB.z);
GL11.glVertex3f(xPos - X.x, yPos - X.y, zPos - X.z);
GL11.glEnd();

MouseHandler.getXAngle() gets the overall rotation angle around the y axis. When the beam moves from top left to top right, 90+MouseHandler.getXAngle() ranges from 0 to 180, and is 90 when beam faces exactly at the front.

And here result http://i.imgur.com/JIiAU.jpg , as I rotate the objectB (sorry for not rendering an ObjectA, but you get the point). I will keep working on it and post in case of progress.

jmanji
11-19-2010, 06:24 AM
Still nothing. The rectangle rotates correctly when moving horizontally, but I do not know what should it do If objectB is going down. When using the laser, my camera is fixed and looks a little down, at the base of the laser. I do this to make the base side perpendicular to AB:

Vector3f X = new Vector3f(0.0f,
1.0f,
0.0f);

//Rotate up vector around z axis, make it perpendicular to AB
float x3 = X.x;
float y3 = X.y;
X.setX(x3*(float)Math.cos(Math.toRadians(90-MouseHandler.getXAngle()))
+ y3*(float)Math.sin(Math.toRadians(90-MouseHandler.getXAngle())));
X.setY(x3*(float)Math.sin(Math.toRadians(90-MouseHandler.getXAngle()))
- y3*(float)Math.cos(Math.toRadians(90-MouseHandler.getXAngle())));
And because I know you like pictures, so this is how it behaves now: http://imgur.com/qOZlT.jpg
When rotating around z it works fine. But how should it react when going down? Cannot find the right way.

strattonbrazil
11-19-2010, 08:18 AM
I don't understand your rotation scheme. Is your camera lookDir always (0,1,0)?

Suppose you have your camera lookDir in world space. You want to find the basis perpendicular to that and AB. Assuming AB is in world space as well, you can just cross them and forget all this rotation business. Since we're just rotating by 90 degrees, cross products will be easier.

X = lookDir X AB
normalize X
scale X by half your laser width
calculate quad as you were doing before

This will work until AB lines up with lookDir.

jmanji
11-19-2010, 09:08 AM
No, it is not (0,1,0), it rotates depending on mouse movement. At the first code I posted, I thought that since you said up vector, I should take the initial up vector and rotate it with the angle I look up or down. At the second code, I was just wrong I guess. Sorry, I had not used vectors before.

What you said now actually works! I used the look vector of my camera and the rectangle rotates exactly as I had imagined. I do not need the scaling part though, because it makes the its size vary according to AB length, I do not want this.

One last thing. Why did you use the cross product? Does it always produce a vector perpendicular to another? Is there any link maybe explaining this?
Thanks a bunch mate!

strattonbrazil
11-19-2010, 10:36 AM
Excellent!

Cross products are pretty fundamental to vector algebra. The math to generate them is very slightly difficult to explain, but I can explain what they do.

Given vector A and vector B, crossing the two will result in a perpendicular vector C (assuming A and B are not parallel). For example, in the XYZ world, if you cross the X-axis with the Y-axis, you'll get the Z-axis. Ordering is important, however, as if you cross Y with X, you'll get negative Z. Also, the cross of two normalized vectors is a normalized vector.

When you cross lookDir and AB, you get your basis X vector, but since AB isn't normalized, X probably isn't normalized either (i.e. it's pointing in the correct direction, but could be any length). If you then normalize it, you should be able to scale it without AB being a factor in it's length anymore.