Drawing a perspective grid (Solved)

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
Blart
Prole
Posts: 9
Joined: Sun Mar 01, 2009 7:42 pm

Drawing a perspective grid (Solved)

Post by Blart » Sat Mar 07, 2009 8:16 pm

Solution found

Image

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. :?
Last edited by Blart on Mon Mar 09, 2009 2:47 am, edited 2 times in total.

osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: Drawing a perspective grid

Post by osuf oboys » Sat Mar 07, 2009 8:21 pm

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).
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.

User avatar
Blart
Prole
Posts: 9
Joined: Sun Mar 01, 2009 7:42 pm

Re: Drawing a perspective grid

Post by Blart » Sat Mar 07, 2009 9:01 pm

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.

osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: Drawing a perspective grid

Post by osuf oboys » Sat Mar 07, 2009 9:11 pm

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.
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.

User avatar
Blart
Prole
Posts: 9
Joined: Sun Mar 01, 2009 7:42 pm

Re: Drawing a perspective grid

Post by Blart » Sun Mar 08, 2009 3:25 am

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.

Image

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? :oops:

User avatar
Xcmd
Party member
Posts: 211
Joined: Fri Feb 13, 2009 10:45 pm

Re: Drawing a perspective grid

Post by Xcmd » Sun Mar 08, 2009 5:23 am

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.
We don't borrow, we don't read, we don't rent, we don't lease, we take the minds!

osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: Drawing a perspective grid

Post by osuf oboys » Sun Mar 08, 2009 6:11 am

Blart wrote:Mind sharing this trigonometry? :oops:
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?
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.

User avatar
Blart
Prole
Posts: 9
Joined: Sun Mar 01, 2009 7:42 pm

Re: Drawing a perspective grid

Post by Blart » Sun Mar 08, 2009 4:54 pm

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:

Code: Select all

y = (i * STEP) + GRID_TOP_YI
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. :death:

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.

User avatar
Blart
Prole
Posts: 9
Joined: Sun Mar 01, 2009 7:42 pm

Re: Drawing a perspective grid (Solved)

Post by Blart » Mon Mar 09, 2009 2:46 am

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). :P

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

:megagrin:

osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: Drawing a perspective grid (Solved)

Post by osuf oboys » Mon Mar 09, 2009 6:12 am

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)
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.

Post Reply

Who is online

Users browsing this forum: No registered users and 12 guests