Page 1 of 2
Drawing a perspective grid (Solved)
Posted: Sat Mar 07, 2009 8:16 pm
by Blart
Solution found
Code: Select all
GRID_BOTTOM_WIDTH = 768
GRID_TOP_WIDTH = 384
GRID_BOTTOM_XI = 16
GRID_BOTTOM_YI = 472
GRID_BOTTOM_XF = GRID_BOTTOM_XI + GRID_BOTTOM_WIDTH
GRID_BOTTOM_YF = GRID_BOTTOM_YI
GRID_TOP_XI = ((GRID_BOTTOM_WIDTH - GRID_TOP_WIDTH) / 2) + GRID_BOTTOM_XI
GRID_TOP_YI = 256
GRID_TOP_XF = GRID_TOP_XI + GRID_TOP_WIDTH
GRID_TOP_YF = GRID_TOP_YI
GRID_SIZE = 6
GRID_BOTTOM_STEP = GRID_BOTTOM_WIDTH / GRID_SIZE
GRID_TOP_STEP = GRID_TOP_WIDTH / GRID_SIZE
...
love.graphics.line(GRID_BOTTOM_XI, GRID_BOTTOM_YI, GRID_BOTTOM_XF,
GRID_BOTTOM_YF)
love.graphics.line(GRID_TOP_XI, GRID_TOP_YI, GRID_TOP_XF, GRID_TOP_YF)
-- Verticle lines
for i = 0, GRID_SIZE
do
love.graphics.line(GRID_BOTTOM_XI + (GRID_BOTTOM_STEP * i),
GRID_BOTTOM_YI, GRID_TOP_XI + (GRID_TOP_STEP * i), GRID_TOP_YI)
end
The only thing I can't figure out is how to do the horizontal lines properly. They need to be drawn closer together as they get closer to the top.
There is one possibly good technique where first you find the center of the grid. This is done by finding the intersection of the two lines that form an 'x' over the square. This will give you the y-coordinate, while the x-coordinate can possibly be found by doing stuff with the slopes of the outermost vertical lines. Then you split the square into two halves at this line and recurse on them. I hope that wasn't too vague. This approach can only give a number of lines equal to a power of 2, which may be too many.
I was thinking of using some quadratic formula for the horizontal line spacing. But then I need to invent a quadratic formula.
Re: Drawing a perspective grid
Posted: Sat Mar 07, 2009 8:21 pm
by osuf oboys
Blart wrote:
[...] The only thing I can't figure out is how to do the horizontal lines properly. They need to be drawn closer together as they get closer to the top. [...]
That should be pretty easy by applying some trigonometry. However, better than taking this approach of always computing where things should go on the screen, I would suggest that you make a function that takes points in (world_x,world_y,world_z) and produces points in (screenx,screeny).
Re: Drawing a perspective grid
Posted: Sat Mar 07, 2009 9:01 pm
by Blart
osuf oboys wrote:Blart wrote: However, better than taking this approach of always computing where things should go on the screen, I would suggest that you make a function that takes points in (world_x,world_y,world_z) and produces points in (screenx,screeny).
Good advice, though it's not like I'm doing any 3D stuff.
What the grid is actually supposed to represent is a battlefield for a RPG game. The board is 2D, and has the various heroes and monsters moving around. I'm drawing the grid with perspective for some extra coolness.
So, I will have some function that translates the (x, y) coordinates of the board to a position on the screen for drawing the sprites. But first I want to get the grid graphics sorted out.
Re: Drawing a perspective grid
Posted: Sat Mar 07, 2009 9:11 pm
by osuf oboys
Blart wrote:osuf oboys wrote:Blart wrote: However, better than taking this approach of always computing where things should go on the screen, I would suggest that you make a function that takes points in (world_x,world_y,world_z) and produces points in (screenx,screeny).
Good advice, though it's not like I'm doing any 3D stuff.
What the grid is actually supposed to represent is a battlefield for a RPG game. The board is 2D, and has the various heroes and monsters moving around. I'm drawing the grid with perspective for some extra coolness.
So, I will have some function that translates the (x, y) coordinates of the board to a position on the screen for drawing the sprites. But first I want to get the grid graphics sorted out.
Interesting. You can use that function for drawing the lines as well though.
Re: Drawing a perspective grid
Posted: Sun Mar 08, 2009 3:25 am
by Blart
Here's preliminary work on the horizontal lines. This is the result I
don't want, though I did need to figure out how to make the ends of the horizontal lines meet the outermost vertical lines anyway.
Code: Select all
...
GRID_RIGHT_SLOPE
= (GRID_TOP_YI - GRID_BOTTOM_YI) / (GRID_TOP_XI - GRID_BOTTOM_XI)
GRID_RIGHT_SLOPE_ADD = GRID_TOP_YI - (GRID_TOP_XI * GRID_RIGHT_SLOPE)
GRID_LEFT_SLOPE
= (GRID_BOTTOM_YF - GRID_TOP_YF) / (GRID_BOTTOM_XF - GRID_TOP_XF)
GRID_LEFT_SLOPE_ADD = GRID_TOP_YF - (GRID_TOP_XF * GRID_LEFT_SLOPE)
STEP = (GRID_BOTTOM_YI - GRID_TOP_YI) / GRID_SIZE
...
-- Horizontal lines
for i = 0, GRID_SIZE
do
local y = (i * STEP) + GRID_TOP_YI -- **** Not actually how I want to calculate y-coordinates ****
local xi = (y - GRID_RIGHT_SLOPE_ADD) / GRID_RIGHT_SLOPE
local xf = (y - GRID_LEFT_SLOPE_ADD) / GRID_LEFT_SLOPE
love.graphics.line(xi, y, xf, y)
end
Also,
osuf oboys wrote:
That should be pretty easy by applying some trigonometry.
Mind sharing this trigonometry?
Re: Drawing a perspective grid
Posted: Sun Mar 08, 2009 5:23 am
by Xcmd
I tried doing this long long ago. I FAILED. FAILED HARD. But I was using BASIC and had very little understanding of this thing we call "Maths". This is some good work, however.
Re: Drawing a perspective grid
Posted: Sun Mar 08, 2009 6:11 am
by osuf oboys
Blart wrote:Mind sharing this trigonometry?
Given a point (x,y) in your game world, what's the point (X,Y) on the screen? You will need to write this function for your game sooner or later, and the same function will yield the answer to your question. Or have I mistaken your question and it is so that you do this in order to get an idea of what the function should be?
Re: Drawing a perspective grid
Posted: Sun Mar 08, 2009 4:54 pm
by Blart
osuf oboys wrote:Or have I mistaken your question and it is so that you do this in order to get an idea of what the function should be?
Here's the idea. So far I have this line:
This calculates, for a given world-y value
i, the screen-y value named
y. So, when
i = 0 (world coordinates)
y = GRID_TOP_YI (screen coordinates). Likewise,
i = GRID_SIZE (
GRID_SIZE is the maximum width and height of the world grid) should make
y = GRID_BOTTOM_YI. I anticipate that I can translate world-x values into screen-x values through the use of slopes, since that's what I've done to make the current horizontal lines be flush with the exterior vertical lines.
The function above is a linear function. What I want is a better function for translating world-y (
i) into screen-y (...
y) so that the grid overall looks more like it's slanted. I've been thinking recently of using a quadratic function. The "perspective" probably won't be exact, but at least it'll look better. Then again, I've been having trouble coming up with a quadratic function such that
f(0) = GRID_TOP_YI and
f(GRID_SIZE) = GRID_BOTTOM_YI. And I've lost my graphic calculator.
Edit
Another condition that my quadratic function should have is that
f(GRID_SIZE / 2) should equal the y-value of the intersection point between the lines that make an x over the plane.
Re: Drawing a perspective grid (Solved)
Posted: Mon Mar 09, 2009 2:46 am
by Blart
Good news. I've finally figured out how to handle the horizontal lines. It basically involved lots and lost of algebra that I never want to do again (though I probably will).
The full code:
Code: Select all
function intersectionPoint(axi, ayi, axf, ayf, bxi, byi, bxf, byf)
denom = ((byf - byi) * (axf - axi)) - ((bxf - bxi) * (ayf - ayi))
if denom == 0.0
then
return nil, nil
end
u = (((bxf - bxi) * (ayi - byi)) - ((byf - byi) * (axi - bxi)))
/ denom
x = axi + (u * (axf - axi))
y = ayi + (u * (ayf - ayi))
return x, y
end
---------------------------------------------------------------------------
-- Window width and height is (800, 600)
-- Placement of corners
GRID_BOTTOM_WIDTH = 768
GRID_TOP_WIDTH = 384
GRID_BOTTOM_XI = 16
GRID_BOTTOM_YI = 472
GRID_BOTTOM_XF = GRID_BOTTOM_XI + GRID_BOTTOM_WIDTH
GRID_BOTTOM_YF = GRID_BOTTOM_YI
GRID_TOP_XI = ((GRID_BOTTOM_WIDTH - GRID_TOP_WIDTH) / 2) + GRID_BOTTOM_XI
GRID_TOP_YI = 256
GRID_TOP_XF = GRID_TOP_XI + GRID_TOP_WIDTH
GRID_TOP_YF = GRID_TOP_YI
-- Placement of vertical lines
GRID_SIZE = 6
GRID_BOTTOM_STEP = GRID_BOTTOM_WIDTH / GRID_SIZE
GRID_TOP_STEP = GRID_TOP_WIDTH / GRID_SIZE
-- Placement of horizontal lines
-- x-coordinates
GRID_RIGHT_SLOPE
= (GRID_TOP_YI - GRID_BOTTOM_YI) / (GRID_TOP_XI - GRID_BOTTOM_XI)
GRID_RIGHT_SLOPE_ADD = GRID_TOP_YI - (GRID_TOP_XI * GRID_RIGHT_SLOPE)
GRID_LEFT_SLOPE
= (GRID_BOTTOM_YF - GRID_TOP_YF) / (GRID_BOTTOM_XF - GRID_TOP_XF)
GRID_LEFT_SLOPE_ADD = GRID_TOP_YF - (GRID_TOP_XF * GRID_LEFT_SLOPE)
-- y-coordinates
-- f(GRID_SIZE / 2) = GRID_HORIZ_MIDDLE
_, GRID_HORIZ_MIDDLE = intersectionPoint(GRID_BOTTOM_XI, GRID_BOTTOM_YI,
GRID_TOP_XF, GRID_TOP_YF, GRID_TOP_XI, GRID_TOP_YI,
GRID_BOTTOM_XF, GRID_BOTTOM_YF)
-- y = ax^2 + bx + c
-- c = GRID_TOP_YI
GRID_HORIZ_FUNC_A
= ((2 * GRID_BOTTOM_YI) + (2 * GRID_TOP_YI) - (4 * GRID_HORIZ_MIDDLE)) /
(GRID_SIZE^2)
GRID_HORIZ_FUNC_B = ((4 * GRID_HORIZ_MIDDLE) - (4 * GRID_TOP_YI)
- ((GRID_SIZE^2) * GRID_HORIZ_FUNC_A)) / (2 * GRID_SIZE)
---------------------------------------------------------------------------
function intersectionPoint(axi, ayi, axf, ayf, bxi, byi, bxf, byf)
denom = ((byf - byi) * (axf - axi)) - ((bxf - bxi) * (ayf - ayi))
if denom == 0.0
then
return nil, nil
end
u = (((bxf - bxi) * (ayi - byi)) - ((byf - byi) * (axi - bxi)))
/ denom
x = axi + (u * (axf - axi))
y = ayi + (u * (ayf - ayi))
return x, y
end
---------------------------------------------------------------------------
function draw()
love.graphics.setColor(0, 255, 0)
-- Verticle lines
for i = 0, GRID_SIZE
do
love.graphics.line(GRID_BOTTOM_XI + (GRID_BOTTOM_STEP * i),
GRID_BOTTOM_YI, GRID_TOP_XI + (GRID_TOP_STEP * i), GRID_TOP_YI)
end
-- Horizontal lines
for i = 0, GRID_SIZE
do
--local y = (i * STEP) + GRID_TOP_YI
local y = (GRID_HORIZ_FUNC_A * (i^2)) + (GRID_HORIZ_FUNC_B * i)
+ GRID_TOP_YI
local xi = (y - GRID_RIGHT_SLOPE_ADD) / GRID_RIGHT_SLOPE
local xf = (y - GRID_LEFT_SLOPE_ADD) / GRID_LEFT_SLOPE
love.graphics.line(xi, y, xf, y)
end
love.graphics.setColor(255, 0, 0)
love.graphics.line(GRID_BOTTOM_XI, GRID_BOTTOM_YI,
GRID_TOP_XF, GRID_TOP_YF)
love.graphics.line(GRID_TOP_XI, GRID_TOP_YI,
GRID_BOTTOM_XF, GRID_BOTTOM_YF)
end
And the results:
Pic 1
Pic 2
Pic 3
Pic 4
Re: Drawing a perspective grid (Solved)
Posted: Mon Mar 09, 2009 6:12 am
by osuf oboys
That's not entirely correct but looks good. Normally, you would compute the angle of the considered in-world point relative the point you're looking from. From this angle, you choose a screen coordinate (e.g. by subtracting something and then multiplying with something). This is easiest to compute first for a point straight ahead but below you. In other words, given the line OA (where O is where your eyes are at and A is the point we're computing), find it's angle from the direction you're looking in. I.e. let B be a point with O's y-coordinate and a large X-coordinate (we don't care which), then compute the angle BOA. For instance, O could be (0,2) and A could be (10, 0), so we let B be (10,2) and want the angle of O in this triangle. (math.atan2 is probably the most suitable for this)