Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

A confusing vector manipulation; rotation scenario (w/ diagrams, video)

Discussion in 'Scripting' started by AlwaysSunny, Mar 27, 2015.

  1. AlwaysSunny

    AlwaysSunny

    Joined:
    Sep 15, 2011
    Posts:
    260
    My 3D RTS has a classic "orbit" camera. The field of play is a literal circle, the center of which is always the camera's focus.
    When the cursor is within that circle, I draw chords which laterally bisect across the cursor's X and Z positions as a visual cue for the player.
    This works fine until I rotate the camera rig. My new perspective means these lines are no longer parallel to the screen edges.
    It's my desire to get the lines to stay parallel to the screen edges, regardless of the orbit camera rig's rotation.

    orbit camera help.jpg

    I figure an example beats an explanation. Here's all the code worth seeing for the vertical chord:

    Code (csharp):
    1.  
    2.    // get two points of sufficient distance from the mouse point p  
    3.    Vector2 lineTop = new Vector2(p.x, radius*2);  
    4.    Vector2 lineBottom = new Vector2(p.x, -radius*2);
    5.  
    6.    // test the line segment between the two points against the playing field circle
    7.    // write the resultant intersections back into the variables
    8.   Geometry.LineCircleIntersections( radius, lineTop, lineBottom, out lineTop, out lineBottom );
    9.  
    So for whatever reason, I'm having trouble wrapping my head around what must transpire to force these chords to be parallel to the screen edges regardless of the orbit cam's orientation.

    I grasp that I need to - the phrasing I want to use is - "rotate" the lineTop & lineBottom points about the cursor before testing, to a degree informed by the camera rig's turntable rotation.

    But every time I try to diagram this, my brain says nope. If I rotate them about the world origin, they don't correspond to the cursor's position, so the rotation must be "about" the cursor, but "informed by" the camera rig.

    Further confusion stems from the necessary conversions between Vector2's and Vector3's, though it might be my imagination that this has anything to do with anything...

    I just know I'm missing something obvious here... but I'm coming up with the same failed ideas. I could sure use a fresh set of eyes if anyone has time!

    Big thanks,
     
    Last edited: Mar 27, 2015
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I'm missing the concept here, its pretty late. But here are some thoughts anyway.

    Can you draw the lines on the screen instead of the world? Or on a quad that is a child of the camera.
     
  3. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    You want the crosshairs to be in the plane of the circle while the camera can go around it, and at the same time you want the lines to be lined up with the edges of the screen? Meanwhile, the crosshair lines stay on the circle plane and intersect the circle's circumference?

    Is it ok if your circle is flat on one plane, say y = 0 everywhere around the circumference?

    I'm off to bed now so if nobody's given you an answer by the time I get up, I'll take a crack at it. Sounds like a neat control scheme. :)
     
  4. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    One more question: Are you able to control the center point of the crosshair how you want already? The problem is just the other points connecting it to the circle?
     
  5. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
    The lines can be thought of as being on their separate plane, even though that plane is coplanar with the turntable. So it should only be a matter of rotating that plane's coordinate system together with the camera. Meaning, you need to rotate the start and end coordinates of your lines around the pivot (the center of the turntable.)

    By the way, I really love the drawings.
     
  6. AlwaysSunny

    AlwaysSunny

    Joined:
    Sep 15, 2011
    Posts:
    260
    Thank you all for replying!

    Notice how the crosshair shape fails to rotate with the camera such that the lines are parallel to the screen edges. That's what I'm wanting to address. (Sorry for dark, low quality)


    Nah, my line drawing method used throughout the project works in world space, and I don't want to break that rule just for this. Other considerations seemed superfluous to mention, but the final four points (two ends of two perpendicular line segment chords) should be in world space, coplanar with the playing field as depicted.

    That's correct. The crosshairs are always coplanar with the playing field circle, and the camera can rotate around the playing field. Presently, the crosshairs don't care about the camera's orientation, so the "vertical" chord is always parallel to the world Z axis. When the camera rotates, that chord stays parallel to world Z, but I'd like it to stay parallel to the vertical edges of the screen. Inotherwords, I want the same visual result depicted in the middle graphic when the camera is rotated, like in the last graphic.

    This is also correct. The center point of the crosshair is the cursor's position on the playing field plane. The problem is calculating the four intersections with that circle such that the lines respect the camera's perspective.

    If I simply rotate the end points of the chords around the center of the turntable, their point of intersection is no longer the position of the cursor on the plane. Hence my tremendous headache and eagerness for assistance. ;)

    I still feel that the answer will involve "rotating" my test points about the cursor's position, to a degree informed by the turntable rotation. I'm confident that all the extra work needs to happen before I test for intersections. When I test this theory though, I feel quite lost as to how. I've tried the classic formula to achieve this, but it seemed to produce nonsensical results:
    x' = x cos θ - y sin θ
    y' = x sin θ + y cos θ

    My humble thanks for your time and interest; I was hoping to hook some folks that enjoy solving unusual problems...!
     
    Last edited: Mar 27, 2015
  7. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Ok, that's just what I thought you wanted. Wanted to make sure. That's a slick way of controlling the mouse, I like it. :)

    Assuming your Geometry.LineCircleIntersections() function is using a circle centered at 0,0,0 and it's in the x/y plane:

    The trouble to me looks like the lineTop/lineBottom vectors (I assume you also have lineLeft/lineRight somewhere and just left it out of the post for the sake of brevity). You're using +/-radius*2 for y which would keep it lined up in world coordinates instead of camera coordinates. The p.x term does the same. Both of those terms need to change with the rotation of the camera. So basically the trouble is your line vectors are fixed to the x and y axis in world space instead of something more lined up with the camera space.

    Instead what I'd do is make a lineTop/lineBottom vector that starts with camera.transform.Forward vector. That will be a 3D vector, but if your circle is on one of the main world axes (resting perfectly on the x/y or x/z plane for example) you can chop it down to a 2D vector just by ignoring one of the components. If your circle is on the plane this should have the effect of projecting the camera's transform.forward vector onto the circle plane so you can do the 2D calculation. So it ought to be something like this:

    Code (csharp):
    1.  
    2. Vector3 lineTop3D = transform.Forward //Change this to the camera object's forward transform if this script is not on the camera
    3. Vector2 lineTop;
    4. Vector2 lineTop.x = lineTop3D.x
    5.  
    6. Vector2 lineTop.y = lineTop3D.y
    7. //Or this, depending on the plane of the circle:
    8. Vector2 lineTop.y = lineTop3D.z
    9.  
    10.  
    Assuming this script is on the object with a camera in it. Otherwise you need to replace transform.Forward with the transform.Forward of that object. If that works, repeat it for the transform.Right vector to get the left/right points.

    Something like that should get you a vector lined up in the camera object's space, but corrected to sit on the circle's plane. If the circle plane is not lined up on one of the planes this way it should still be possible to do, you just have to create a vector perpendicular to the circle plane that can be subtracted from the transform.forward that will pop that vector to the circle plane. This is a little trickier to do but shouldn't be too bad and is why I was asking if the circle was on the x/y or x/z plane.

    Let me know if that doesn't help, I'll maybe make a little demo project to try it myself and share it here. If you can post your Geometry.LineCircleIntersections() function maybe I could try to make it work with that. Otherwise I would just solve it with some trig probably.
     
    Last edited: Mar 28, 2015
    AlwaysSunny likes this.
  8. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Come to think of it, you might give this a try:

    Code (csharp):
    1.  
    2. Vector2 lineTop = new Vector2(transform.forward.x, transform.forward.y);  
    3. Vector2 lineBottom = new Vector2(transform.forward.x, transform.forward.y);
    4.  
    Depending on the plane, maybe y above should be z. Not sure if this will do it or not, the trouble is I'm not sure how your circle intersection function works. If it's wrong it might change the behavior to a different wrong behavior that makes the problem more clear anyway. :p
     
  9. AlwaysSunny

    AlwaysSunny

    Joined:
    Sep 15, 2011
    Posts:
    260
    The idea of projecting the camera's forward and right vectors onto plane space makes sense to me. That's coming at the problem from a different angle altogether.

    This just might be the fresh idea I needed, thank you very much for the detailed brainstorming! I'm definitely going to play around with this alternate approach.

    I should be able to normalize these projected vectors to get two perpendicular vectors in plane space, each pointing in the desired directions. Adding the cursor's position gets me the correct placement... At that point, the rest of this will go smoothly if this all works as I foresee.

    Again, a great big thank-you for getting me to think outside the box. Or circle. I'm eager to try this out.

    followup : This worked out just fine! Now I feel terribly silly for not approaching it this way to begin with...
     
    Last edited: Mar 28, 2015
    Kiwasi likes this.
  10. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Great! Glad you figured it out. :)

    I tend to think of problems like these as first finding some point in the system that's probably going to be the easiest to compute. In your case it's the center of the crosshairs. Then I think of shooting vectors out from that point some distance to compute new points. I.e., I think of it as originating from that initial point. In your case it's four lines: Forward, backward, left, and right.

    So I think: "what direction do those lines need to go? Is there some other direction that sort of lines up with that? (In this case the camera forward and right vectors). Starting with that, is there a way I can pop that vector along some other normal or something to get it to the plane that I want? (In your case it's on the x/y or x/z plane already so it's just a matter of losing the y or z component and perhaps renormalizing the vector)."

    This basic thought process can go a pretty long way. Once you can visualize dot and cross products on vectors you can do some pretty crazy stuff like this:



    There are 76 different pieces there with forces computed all over the place. It was done through a similar thought process, just thinking "ok, here's a point I know. Now can I shoot out along some direction by some distance to find another point or circle or sphere or plane to intersect with? Once I know that second point, can I shoot out again in a different direction to get a third point?" Etc., until you've got a full automobile suspension or whatever going.

    Anyway, good job figuring it out. That's a clever thing you've come up with there. :)
     
    AlwaysSunny likes this.