Converting a 3D position to a 2D screen position - math

I am trying to create a screen overlay for an existing computer game. This overlay should display icons that show certain locations in the 3D world. Now because I do not have access to the data I want to be able to get the screen positions, I have to figure it out using the following variables:
Player position (x,y,z)
Camera position (x,y,z)
Point position (x,y,z)
Camera Angle(FOV)
Using these variables I managed to get the right and left edge of the camera view. Using these 2 variables I am able to get the point between 0 and 1 where the icon should be displayed on the x axis. (0 is on the left edge, 1 is right edge) This seems to work quite well, but only if I am aligned to either the X or Z axis, as shown in the following example: http://i.imgur.com/OIZWBME.png
The problem is, I have no clue on how to make this work when the camera rotates. I've tried combining the 2 points that work alone, but also with other variables like the camera-player world rotation and angles.
Does anyone have any ideas on how I might be able to make this work? If I forgot to supply any info please let me know!
Tim

There are pretty good articles on wikipedia (https://en.wikipedia.org/wiki/3D_projection), and other tutorials online (http://www.codeproject.com/Articles/2158/A-short-discussion-on-mapping-3D-objects-to-a-2D-d).
Essentially, for this simple instance, it boils down to rotating everything in a virtual space before rendering. The points you want to draw are moved in relation to the camera position, so that the camera becomes the new axis point, and then you can draw as before.
A simple top down ascii-art example:
( []< is the camera, a, b, and c are points)
What you can already draw:
^ <-----y------>
|
| b
| []< a
x
| c
|
|
v
What you can't draw: (the camera moved and rotated)
<-----y------>
^ [ ]
| ^
| b
x a
| c
|
v
So you need to map (usually using matrixies) the camera's global position against the positions of everything else, so that you end up with:
After transformation:
<---------fake y------>
^
| a
|
fake | b
x: | []<
| c
|
v
Which you can now draw as normal. I'm not an expert on this, but does this help to get you started?

Related

Determining the adjacent face of a cube for a given direction (up, down, left or right)

I have a procedurally created cube. I have a reference to each of the six faces which I call front, back, left, right, top and bottom.
________
/ /|
/ T / |
|--------| R|
| | |
| F | /
|________|/
Each face has a procedurally created texture. The texture is square and is created by iterating the pixels of a pre-defined resolution size (width == height == resolution size).
The x coordinate of the pixel starts from left and increases to the right along the texture.
The y coordinate of the pixel starts from the bottom and increases upwards of the texture.
I am now creating a heightmap texture using averaging of the pixels around a given pixel. For this to work, on the occasions when a specific pixel is on the edge of a cubes face, I will need to access the pixel next to it which lies on another face.
My question: Is there a fast, easy way to determine an adjacent face for a given direction (up, down, left or right) starting from any face?
For example: Say I am dealing with the pixels on the Front face, and am iterating the pixels on the right-hand edge (where x == resolution). I know that I need to grab the adjacent pixel on the Right face, because if I walk to the right of the Front face I wrap around onto the Right face.
I could write the logic as a big bunch of conditional checks for every face, covering every scenario, but I'm sure there must be a more elegant way to achieve this?

How to calculate a vector to move towards based on a central origin point

Hey so I am having some issue with vector math that I need to resolve to make my code work. What I am trying to do is this:
Lets say we have three objects:
Object A is the central object
Object B is a few meters away from A on a 45 degree from A's position
Object C is also a few meters away from A but on a 90 degree angle from A's position
A bit like this:
B
AC
Now what I need to do is get a vector coordinate point 10m more away from A that both B and C will move to when A is activated. So, when I activate A, B will continue along the 45 deg angle to currentPos + newPos and C will move along the 90 degree angle to currentPos + newPos. All of this has to be based on the position of A. The objects have to be moving away from A's central position.
Vector math is something I am not too familiar with and I am sort of struggling a little here to figure out how to get the new position for B and C based on their current angle to A and A position, so thought I would ask you more knowledgable people for help.
Would you please write any responses in a straightforward manner, so I can easily convert the idea into code.
Thanks!
I am following your picture, which I would call a zero degree angle from A's position for C. Let us suppose we call your location of A (0,0).
It looks like in your case you could add (10,0) to C's current spot. For B, you could (5sqrt(2),5sqrt(2)). More generally, to move n units at an angle theta (measure in radians in most languages), add n(cos (theta), sine (theta)).
I am taking this approach because you said the angle was known and A was the center of our universe and everything is relative to it. If that were not the case, an approach that looked at B-A and C-A as vectors and took their sizes, then added the right amounts of them, might be called for instead.

3D: Check point inside elliptical cone

I seem to have searched the whole internet trying to find an implementation of checking if a 3d point is within an elliptical cone defined by (origin, length, horizontal angle, vertical angle). Unfortunately without success as I only really found one math solution which I did not understand.
Now I am aware on how to use implement it using a normal cone:
inRange = magnitude(point - origin) <= length;
heading = normalized(point - origin);
return dot(forward, heading) >= cos(angle) && inRange;
However there the height detection is far too tall. I would really like to implement a more realistic vision cone for the AI for a game but this requires having the cone shaped more like a human field of view being more wide than tall.
Thanks a lot for any help:)
Given a 3D elliptic cone, with base at B=(x_B,y_B,z_B), height h along the cone axis k=(k_x,k_y,j_z), major base radius a, minor base radius b and direction along the major axis i=(i_x,i_y,i_z) you need to find if a point P=(x,y,z) lies inside the cone. It is your choice on how to parametrize the major axis direction and I think your are trying to use spherical coordinates with two angles.
Here are the steps to take:
Establish a coordinate system with origin on the base B and with the local x axis along your major axis i. The local z axis should be towards the tip along k. Finally the local y axis should be
j=cross(k,i)=(i_z*k_y-i_y*k_z, i_x*k_z-i_z*k_x, i_y*k_x-i_x*k_y)
j=normalize(j)
Your 3×3 rotation matrix is defined by the columns E=[i,j,k]
Transform your point P=(x,y,z) into the local coordinates with
P2 = transpose(E)*(P-B) = (x2,y2,z2)
Now establish how far along the axis of the cone is with s=(h-z2)/h where s=0 at the tip and s=1 at the base.
If s>1 or s<0 then the point is outside
Otherwise if s>0 you need to check that (x2/(s*a))^2+(y2/(s*b))^2<=1 for the point to be inside.
If s=0 then check that x2=0 and y2=0 for the point being exactly at the tip.
If you cannot do basic vector algebra, like cross products, 3D transformations and normalization that I suggest you have some reading to do before you can understand what is going on here.
Note:
// | i_x i_y i_z |
// transpose(E) = | j_x j_y j_z |
// | k_x k_y k_z |

How to calculate a point on a circle knowing the radius and center point

I have a complicated problem and it involves an understanding of Maths I'm not confident with.
Some slight context may help. I'm building a 3D train simulator for children and it will run in the browser using WebGL. I'm trying to create a network of points to place the track assets (see image) and provide reference for the train to move along.
To help explain my problem I have created a visual representation as I am a designer who can script and not really a programmer or a mathematician:
Basically, I have 3 shapes (Figs. A, B & C) and although they have width, can be represented as a straight line for A and curves (B & C). Curves B & C are derived (bend modified) from A so are all the same length (l) which is 112. The curves (B & C) each have a radius (r) of 285.5 and the (a) angle they were bent at was 22.5°.
Each shape (A, B & C) has a registration point (start point) illustrated by the centre of the green boxes attached to each of them.
What I am trying to do is create a network of "track" starting at 0, 0 (using standard Cartesian coordinates).
My problem is where to place the next element after a curve. If it were straight track then there is no problem as I can use the length as a constant offset along the y axis but that would be boring so I need to add curves.
Fig. D. demonstrates an example of a possible track layout but please understand that I am not looking for a static answer (based on where everything is positioned in the image), I need a formula that can be applied no matter how I configure the track.
Using Fig. D. I tried to work out where to place the second curved element after the first one. I used the formula for plotting a point of the circumference of a circle given its centre coordinates and radius (Fig. E.).
I had point 1 as that was simply a case of setting the length (y position) of the straight line. I could easily work out the centre of the circle because that's just the offset y position, the offset of the radius (r) (x position) and the angle (a) which is always 22.5° (which, incidentally, was converted to Radians as per formula requirements).
After passing the values through the formula I didn't get the correct result because the formula assumed I was working anti-clockwise starting at 3 o'clock so I had to deduct 180 from (a) and convert that to Radians to get the expected result.
That did work and if I wanted to create a 180° track curve I could use the same centre point and simply deducted 22.5° from the angle each time. Great. But I want a more dynamic track layout like in Figs. D & E.
So, how would I go about working point 5 in Fig. E. because that represents the centre point for that curve segment? I simply have no idea.
Also, as a bonus question, is this the correct way to be doing this or am I over-complicating things?
This problem is the only issue stopping me from building my game and, as you can appreciate, it is a bit of a biggie so I thank anyone for their contribution in advance.
As you build up the track, the position of the next piece of track to be placed needs to be relative to location and direction of the current end of the track.
I would store an (x,y) position and an angle a to indicate the current point (with x,y starting at 0, and a starting at pi/2 radians, which corresponds to straight up in the "anticlockwise from 3-o'clock" system).
Then construct
fx = cos(a);
fy = sin(a);
lx = -sin(a);
ly = cos(a);
which correspond to the x and y components of 'forward' and 'left' vectors relative to the direction we are currently facing. If we wanted to move our position one unit forward, we would increment (x,y) by (fx, fy).
In your case, the rule for placing a straight section of track is then:
x=x+112*fx
y=y+112*fy
The rule for placing a curve is slightly more complex. For a curve turning right, we need to move forward 112*sin(22.5°), then side-step right 112*(1-cos(22.5°), then turn clockwise by 22.5°. In code,
x=x+285.206*sin(22.5*pi/180)*fx // Move forward
y=y+285.206*sin(22.5*pi/180)*fy
x=x+285.206*(1-cos(22.5*pi/180))*(-lx) // Side-step right
y=y+285.206*(1-cos(22.5*pi/180))*(-ly)
a=a-22.5*pi/180 // Turn to face new direction
Turning left is just like turning right, but with a negative angle.
To place the subsequent pieces, just run this procedure again, calculating fx,fy, lx and ly with the now-updated value of a, and then incrementing x and y depending on what type of track piece is next.
There is one other point that you might consider; in my experience, building tracks which form closed loops with these sort of pieces usually works if you stick to making 90° turns or rather symmetric layouts. However, it's quite easy to make tracks which don't quite join up, and it's not obvious to see how they should be modified to allow them to join. Something to bear in mind perhaps if your program allows children to design their own layouts.
Point 5 is equidistant from 3 as 2, but in the opposite direction.

Rectangle - a mathematical problem

I have found something NOT funny with rectangles:
Lets say, given are values of left, top, right and bottom coordinates and all those coordinates are intended to be inclusive.
So, calculating the width goes like:
width = right - left + 1
So far, so logical. But!
A width of zero (which makes sense, sometimes) would have to be stored as:
right = left - 1
which makes problems, when it comes to the following operations:
Sorting the rectangle coordinates (to make it go left to right, top to bottom)
Looping
Ok, of course those things can be handled with extra code for the special case of Width == 0, but, seriously, is there no better solution, no standard pattern or best practice to handle this?
Edit:
For the time being I have abandoned the "sorting" of the coordinates in my code and replaced it with an assertion stating that the rectangle must be left -> right, up -> down, but seriously...
To address this problem, most graphics libraries will draw rectangles from the left coordinate up to but not including the right coordinate. So if left=10 and right=20, then the ten pixels 10 through 19 will be drawn.
You can think of this as the pixel coordinate referring not to the lit-up portion, but the grid lines between pixels.
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
^ ^ ^ ^
0 1 2 3
It's important to distinguish between coordinates and pixels. You can think of the coordinate system as being an invisible grid which runs between pixels. Thinking of coordinates this way if you define a rect as { 0, 3, 0, 5 }, then you get 3 pixels by 5 pixels as expected.
| | | | | |
0 -x--+--+--+--+--x-
| | | | | |
1 -+--+--+--+--+--+-
| | | | | | <- pixels are rectangular areas between coordinate grid
2 -+--+--+--+--+--+-
| | | | | |
3 -x--+--+--+--+--x-
| | | | | |
0 1 2 3 4 5
If the edges (left, right, top, bottom) are inclusive then, by definition, the width (and height) of the rectangle cannot be 0. By "including" the side (which is a pixel), you're saying that it has to be at least 1 pixel wide.
Saying that
all those coordinates are intended to be inclusive
means that there actually are two distinct rectangles, one within another. That's where you get caught: when you write
width = right - left + 1
it really means:
inner_width = outer_right - outer_left + thickness
where thickness is the distance between corresponding sides of inner and outer rectangles.
So, to deal with the problem in abstract mathematical sense, you have to consider two rectangles instead of one.
Of course you can find a workaround for this, but what really is the problem here is going out of scope.
Your scope is a rectangle, and even if a width of zero would come in handy : there is no such thing as a rectangle with width zero.
Normally all functions have contracts and a predcondition of a functions that says docalculation(par_rectangle) is that par_rectangle in fact is a rectangle.
If you need a retangle-like object wich can be width zero, you first need to define it waterproof, and never just assert that rules for rectangles will apply on your definiton.

Resources