Page 1 of 1

[0.17.x] LuaRendering:draw_polygon vertices order

Posted: Sat Jan 18, 2020 6:44 pm
by cogito123
Hi,

In which order do I have to pass vertices into draw_polygon to make it not look like 1 big mess? I already tried passing them as clockwise, counter clockwise, but none of them seem to give visually appealing result. I mean, it works ok for triangles, but that's not what this function is about if my understanding is correct.
clockwise
clockwise
cw.png (832.45 KiB) Viewed 3131 times
counter clockwise
counter clockwise
ccw.png (455.5 KiB) Viewed 3131 times

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Sat Jan 18, 2020 7:01 pm
by Bilka
draw_polygon is implemented as a TriangleStrip: https://docs.microsoft.com/en-us/window ... gle-strips. You can see this nicely in the clockwise picture, it is drawing triangles between groups of 3 vertices.

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Mon Jan 20, 2020 8:13 am
by darkfrei
Is here easy way to convert custom ngon to TriangleStrip?

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Mon Jan 20, 2020 9:34 am
by DaveMcW
1. Point A = Point B = starting point. Draw Point A.
2. Point B = next clockwise point. Draw Point B.
3. Point A = next counterclockwise point. Draw Point A.
4. Goto 2.

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Thu Apr 30, 2020 10:27 pm
by smaudet
It would be nice if this API were fixed, I'd love to have SVG imports in the game, but...

Code: Select all

local game_surface = game.surfaces[1]
local player = game.player
local shape = {
    {target={9.46484375, 0}},
    {target={1.003906011581421, 0.953125}},
    {target={1.95703125, 1.003906011581421}},
    {target={0, 8.462890625}},
    {target={8.462890625, 1.003906011581421}},
    {target={0, 8.462890625}},
    {target={1.95703125, 1.003906011581421}},
    {target={7.974608898162842, 0.953125}},
    {target={0.953125, 7.974608898162842}},
    {target={1.003906011581421, 1.95703125}},
    {target={0.953125, 7.974608898162842}},
    {target={6.972655773162842, 9.46484375}},
    {target={9.46484375, 7.974608898162842}},
    {target={6.972655773162842, 8.462890625}},
    {target={9.46484375, 7.974608898162842}},
    {target={6.972655773162842, 9.46484375}},
}

game.print(rendering.draw_polygon({
    vertices = shape ,
    color = {r = 1, g = 1, b = 1, a = 0.5},
    surface = game_surface,
    time_to_live = 30 * 60,
    target = player.position
}))
Expected:
Image

Actual:
Image

I suppose I should clarify, I generated the vertices from inkscape:

0.953125,0.0,
0.953125,7.974609,
9.4648438,7.974609,
9.4648438,0.0,
0.953125,0.0,
0.953125,0.0,
1.9570312,1.003906,
8.4628906,1.003906,
8.4628906,6.972656,
1.9570312,6.972656,
1.9570312,1.003906,
1.9570312,1.003906,

And tessellated them with libtess, and wrote a script to output the shape code above.

YES, I know I could achieve the same shape with two rect calls...however I'm not trying to create two rectangles, I actually have a much more complicated polygon I wanted to use, and the draw_polygon code being as broken/un-intuitive as it is means that I need to figure out the api's quirks to even use the tesselated results...

Triangles work OK but otherwise this call sucks. :/

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Fri May 01, 2020 5:23 am
by smaudet
I found some issues with my vertex generation code but unless anyone can see anything else I think this is the best the API is capable of (on 0.17 at least). The "Triangle Strips" page linked to is...sparse, to say the least, on details of implementation (how are triangles found? does it care about order?).

I have settled on this hacky implementation:

Code: Select all

local game_surface = game.surfaces[1]
local player = game.player

local secs = 20 * 60

local shape1 = {
    {target={9.4648438, 0}},
    {target={1.9570312, 1.003906}},
    {target={0.953125, 0}},

    {target={1.9570312, 1.003906}},
    {target={9.4648438, 0}},
    {target={8.4628906, 1.003906}},

    {target={8.4628906, 1.003906}},
    {target={9.4648438, 0}},
    {target={8.4628906, 6.972656}},
}

local shape2 = {
    {target={1.9570312, 1.003906}},
    {target={0.953125, 7.974609}},
    {target={0.953125, 0}},

    {target={0.953125, 7.974609}},
    {target={1.9570312, 1.003906}},
    {target={1.9570312, 6.972656}},

    {target={0.953125, 7.974609}},
    {target={1.9570312, 6.972656}},
    {target={9.4648438, 7.974609}},
}

local shape3 = {
    {target={9.4648438, 7.974609}},
    {target={1.9570312, 6.972656}},
    {target={8.4628906, 6.972656}},

    {target={9.4648438, 7.974609}},
    {target={8.4628906, 6.972656}},
    {target={9.4648438, 0}},
}

game.print(rendering.draw_polygon({
    vertices = shape1,
    color = {r = 1, g = 0, b = 0, a = 0.5},
    surface = game_surface,
    time_to_live = secs,
    target = player.position
}))

game.print(rendering.draw_polygon({
    vertices = shape2,
    color = {r = 0, g = 1, b = 0, a = 0.5},
    surface = game_surface,
    time_to_live = secs,
    target = player.position
}))

game.print(rendering.draw_polygon({
    vertices = shape3,
    color = {r = 0, g = 0, b = 1, a = 0.5},
    surface = game_surface,
    time_to_live = secs,
    target = player.position
}))
Image

I couldn't split it into two, it decided for some reason to try to draw random convex stuff in the middle (so I'm pretty sure this is not actually true triangle strip, if it were it would be working fine).

It only worked when I split it up into three like this, so I'm pretty sure it is a fault of the algorithm and not something I've done at this point. When I had all in one it just rendered a square box.

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Fri May 01, 2020 6:49 am
by DaveMcW
Graphics cards cannot draw concave polygons, so triangles are required if you want to draw something concave.

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Fri May 01, 2020 9:24 am
by posila
The MSDN article might not be clear because it takes into account clockwise and counter-clockwise definitions of triangles, which often matter, but not so much in 2D games.

Simply if you have list of vertices A B C D E F G H, every consequtive tripple of vertices will form a triangle. That is: ABC, BCD, DEF, EFG, FGH
Another useful thing to note, is that if a triangle has zero area, it's so called degenerate triangle, and GPU will throw it away. How can you use this? Let's say in above example, you don't want triangle DEF, so you simply repeat E: A B C D E E F G H. GPU will use this to form triangles ABC, BCD, CDE, DEE, EEF, EFG, FGH. DEE and EEF are denegerate triangles, so they won't result in any pixels being rasterized.

Terms "triangle strip" or "degenerate triangle" are common rendering terms and are very googlable, by the way.

Anyhow, quirk of the API is that the function is called draw_polygon which makes it sound more high-level than it is. It essentially takes list of points you give it, pass it to GPU and tell it to render it. There is no attempt to make any interpretation of input points and translate it to form GPU expects, like SVG would do.
I am not gonna rename the function at this point, what I can offer is adding parameter that changes it from triangle strip to triangle list, but I also feel it is kind of unnecessary, since people can use degenerate triangles, and using strip for everything allows for better batching of draw calls to GPU.

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Fri May 01, 2020 5:20 pm
by smaudet
Thanks for the clarification! I'll try to use degenerate triangles, I knew about them but was not sure if the API supported them.

I think the parameter might be nice, my tessellation was a triangle list I suppose, to turn it into a proper triangle strip sounds entertaining however it may be a bit daunting for a first time user.

Re: [0.17.x] LuaRendering:draw_polygon vertices order

Posted: Fri May 08, 2020 9:39 pm
by smaudet
Woo, got it working, thanks for the clarification. Maybe someday I'll cleanup my render pipeline and post on here:

Image

Code:

Code: Select all

local game_surface = game.surfaces[1]
local player = game.player

local secs = 20 * 60

local square = {
    {target={9.4648438, 0}},
    {target={1.9570312, 1.003906}},
    {target={0.953125, 0}},
    {target={1.9570312, 1.003906}},
    {target={0.953125, 7.974609}},
    {target={1.9570312, 6.972656}},
    {target={9.4648438, 7.974609}},
    {target={8.4628906, 6.972656}},
    {target={9.4648438, 0}},
    {target={8.4628906, 1.003906}},
    {target={1.9570312, 1.003906}},
}

local check = {
    {target={-5.19276, 2.204059}},
    {target={-3.17407, 4.666173}},
    {target={-5.40923, 2.419405}},
    {target={-5.40923, 2.419405}},
    {target={-5.19276, 2.204059}},
    {target={-5.19276, 2.204059}},
    {target={-3.17407, 4.666173}},
    {target={-3.20461, 4.202575}},
    {target={-3.17407, 4.666173}},
    {target={0, 0}},
    {target={0.24284, 0.185145}},
}

game.print(rendering.draw_polygon({
    vertices = square,
    color = {r = 0, g =1, b = 0, a = 0.2},
    surface = game_surface,
    time_to_live = secs,
    target = player.position
}))

game.print(rendering.draw_polygon({
    vertices = check,
    color = {r = 0, g = 1, b = 0, a = 0.2},
    surface = game_surface,
    time_to_live = secs,
    target = { player.position.x + 8, player.position.y + 1.5 }
}))
Although, hmm, the checkmark tears a bit. 🤔