• Create Account

## Indicator arrow for offscreen objects

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

4 replies to this topic

### #1Misantes  GDNet+

2092
Like
0Likes
Like

Posted 21 July 2014 - 08:36 PM

Hello,

Perhaps I'm searching for the wrong terms, but I'm not quite finding an understandable answer to this question. Perhaps, I'm searching for the wrong terms, but of the ones I can find, they don't really give an good answer at all. At least one that I can make sense of. So, my genuine apologies if this question has been asked many times and I'm just failing to find their threads.

I'm trying to rotate a little 3D indicator arrow in the HUD that will point to an object, especially when the object is "offscreen." I understand how to rotate one object toward another generally speaking(in world coordinates), but I'm having difficulty since this arrow would take into account the ViewMatrix rotation, or screen space.

My initial attempts, I tried to use glm::project to parse out the screen coordinates and rotate toward those. This works great if the object is in view of the camera.

Something like this:

    ProjectionMatrix= glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100000.0f);
glm::vec3 projectedObject = glm::project(objPosition, ViewMatrix, ProjectionMatrix, glm::vec4(0,0,1920,1050));

quat rotation1 = RotationBetweenVectors(glm::vec3(0,0,1), glm::vec3(projectedObject.x - 960, projectedObject.y - 525, projectedObject.z) );
glm::mat4 Rotation;
Rotation = glm::mat4_cast(rotation1);

ModelMatrix =  glm::translate(glm::vec3(0,-.5, -20)) * Rotation ;

MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;


The RotationBetweenVectors function returns a quaternion representing the rotation toward the second object. From here.

But, if the object is offscreen, it doesn't work quite right, as it predictably goes back and forth as it hits the negative values. The z-axis also, predictably isn't quite working properly as glm:;project just gives a sort of positive/negative value, with little inbetween. In hindsight, I understand why this isn't working. I also tried the glm::lookat() function, but, since it doesn't take into account the current rotation of the viewmatrix, it also isn't quite working.

I can fanagle things to work a little better by doing:

quat rotation1;
if(projectedObject.z < 1)
rotation1 = RotationBetweenVectors(glm::vec3(0,0,1), glm::vec3(projectedObject.x - 960, projectedObject.y - 540, projectedObject.z) );
else
rotation1 = RotationBetweenVectors(glm::vec3(0,0,1), glm::vec3(-projectedObject.x - 960, -projectedObject.y - 540, -projectedObject.z) ); 

But, this is pretty inelegant, and only works for the X/Y axes, and not really the Z.

I guess I'm having difficulty quite visualizing what it is I need to do. I mean, I can visualize it, I'm just struggling to put this into an equation. But, in a nutshell, I need to take the current rotation of the ViewMatrix, and the calculate the rotation toward the destination object in screen space(or offscreen-space ). And, this is for the full spectrum of rotations as the game is in space. So, there would be no preferred "UP" vector.

Anyway, if anyone has an insight on how to go about this, I'd be truly grateful for the help. Let me know if you need clarification or additional code at all, as this was probably a little rambling.

In the meantime, I'm going to go read articles on billboarding, as I feel like it would be the same principle, just instead of always facing the camera, The object would always face the targeted object.

Thanks all,

Edited by Misantes, 21 July 2014 - 10:19 PM.

Beginner here <- please take any opinions with grain of salt

### #2JordanBonser  Members

832
Like
1Likes
Like

Posted 22 July 2014 - 06:36 AM

Maybe I'm confused about exactly what it is you are trying to achieve but could you not just do all of the calculations in world space?

if this indicator is a 3D arrow and the object you are pointing at is in the world then just set the arrow to point towards the object in world space. Then each update just make sure the 3D Arrow is placed in the same place relative to the camera so that it is in the same part of the HUD.

unless I'm missing something ?

Maybe you can link a video of a game that already has this feature so there is a better idea of what you want?

Edited by JordanBonser, 22 July 2014 - 06:38 AM.

### #3Misantes  GDNet+

2092
Like
0Likes
Like

Posted 22 July 2014 - 11:30 AM

Well, I originally tried what you suggested, but the issue is that, being part of the HUD, it doesn't exist in worldspace, per se. I could pass it the ship/player's coordinates, but those worldspace coordinates don't change when the camera/view matrix rotates. Which, is fine, I think, if I can figure out how to pass in the ModelView matrix of the object to be rotated towards. But, If I simply put in the world coordinates, and rotate the indicator towards the object, it won't matter which way I  move the camera, it will still point in the same direction (usually not the objects position in camera space) as the world space coordinates wouldn't have changed at all.

So, essentially, the indicator arrow has a sort of constant view matrix, while the object to be rotated towards uses the ViewMatrix that all the objects in the worldspace use. It's a matter of figuring out how to account for those, I think.

Here's a screenshot of a simple version of what I have working now. It's correct for the X/Y axes, and will point in the right direction regardless of where you rotate the camera/ship(using the workarounds in the original post). it's just a little confusing since it doesn't rotate toward the Z axis at all, it can be difficult to tell if you're headed quite in the right direction. You can suss it out eventually, by just following where it tells you, but it's a less than ideal solution. I'd like to be able to point along all axes, to get a better idea of where the object is in relation to where the player is facing.

Apologies for the awful graphics, it's very much still a work in progress. The indicator is the red icon below the ship (not the blue circle, that's a rotating selection thingermabobber, it looks better in motion ). Apologies for all the UI clutter. When I get the z axis working I'll need to redo the indicator arrow,as it won't really be visible as it currently stands if it's pointed toward the camera. But, that's another issue

So, right now, if, in the picture below, regardless of where I rotated, the arrow will point to the object, but only along the X/Y axes. So, if I were to just fly forward past it, the arrow would just point down(or left, or up, or whatever, until you rotated around to face it). I'd like it to be able to calculate the z axis so if I flew past it, the arrow would point back at the player indicating the object was behind you, if that makes sense.

#### Attached Thumbnails

Edited by Misantes, 22 July 2014 - 11:41 AM.

Beginner here <- please take any opinions with grain of salt

### #4phil_t  Members

7653
Like
2Likes
Like

Posted 22 July 2014 - 12:59 PM

Seems like it's even more straightforward if you want the z-axis involved too. Then your arrow indicator is just a regular 3d object that you render along with the rest of your 3d objects (or if you want it "always on top", then render it separately after clearing the depth buffer).

You just need to figure out the world matrix to apply the rotation to your arrow. You basically already have this: RotationBetweenVectors returns a quaternion and you can get a rotation matrix from that. One vector will be the "base" direction your arrow model points in, and the other will be some vector that points from an arbitrary world position* to the world position of the offscreen object.

Then use your regular view and projection matrices when drawing your arrow.

* The only subtlety then is choosing the world position for your arrow.

### #5Misantes  GDNet+

2092
Like
1Likes
Like

Posted 22 July 2014 - 06:37 PM

On both your advice, I'm implementing this now. There are a few hiccups though, I'll try to update as I go along.

The first issue I'm having, is that I can't use the same ViewMatrix as the rest of the objects, as then the indicator arrow then acts as a stationary object along with everything else (it just acts as an object in the world). I can counter this by translating the indicator's ModelMatrix against it, but then, predictably, it doesn't follow when I move the camera around and acts as a world object I'm looking at/around.

Additionally, I think I may be using the RotationBetweenVectors() incorrectly. By base view, should I pass in the rotated "forward" vector (the camera forward) or is vec3(0,0,1) sufficient? The direction ought to be simply the objPosition - playerWorldCoordinates, I would think. But, this doesn't result in the arrow tracking the object at all.

Perhaps I'm calculating my View and Model matrices incorrectly. I'm passing in the movement of the player to the object's ViewMatrix, if that makes sense. The objects ModelMatrix I'm using to calculate their relative movement to each other (orbits and that sort of thing). I.e. all the objects ViewMatrix represent the player movement (if the forward key is pressed, the objects ViewMatrix is translated backward). This might not be the ideal way to do things, but was far simpler than trying to calculate their orbits and player movement together. I'm happy to post the calculation of the ViewMatrix, but it's rather a lot of code (and rather messy to boot) as it consists of the control scheme.

Thanks for your patience, I'm sure I'm explaining things poorly.

edit*

If I make a second ViewMatrix that doesn't include the player movement, and translates the indicator to where I want it on the screen after the rotation, I'm getting closer to what you're talking about. I think my model is imported a little screwy now, so I'll try to suss that out.

Hm, nope. It seemingly works, but isn't tracking the object correctly. I think perhaps I'm using the RotationBetweenVectors() wrong:

rotation1 = RotationBetweenVectors(glm::vec3(0,0,1), objPosition - player.worldCoordinates);


The, I'm passing in a ViewMatrix that is based on the rotations in the ViewMatrix that the other objects use, but without the translation to worldcoordinates.

edit**

and, I'm just an idiot my worldcoordinate values are negative, since I use them to offset the position...So, if I just call:

rotation1 = RotationBetweenVectors(glm::vec3(0,0,1), objPosition + player.worldCoordinates);


So, as long as I use a ViewMatrix that only includes the camera quaternion rotations, but not the translation, and then use the above function for the ModelMatrix rotation, everything works beautifully!

Thanks for all your advice, you guys. It's truly been appreciative. I think I would have banged my head on this like a monkey trying to stick a square peg through a round hole for another week before without your help. I had discarded this method originally as things didn't work out quite right, and don't think I would have come back to it as,  in my head, it was just seeming as though it should be more complex. But, the solution was right under my nose >.<

I wish I could upvote more than once

Cheers, and thanks again!

it's difficult to tell from a still frame, but it's working

#### Attached Thumbnails

Edited by Misantes, 22 July 2014 - 08:41 PM.

Beginner here <- please take any opinions with grain of salt

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.