[0.17.x] LuaRendering:draw_polygon vertices order

Place to get help with not working mods / modding interface.
Post Reply
cogito123
Inserter
Inserter
Posts: 24
Joined: Thu Feb 28, 2019 7:05 pm
Contact:

[0.17.x] LuaRendering:draw_polygon vertices order

Post 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 2521 times
counter clockwise
counter clockwise
ccw.png (455.5 KiB) Viewed 2521 times

Bilka
Factorio Staff
Factorio Staff
Posts: 3158
Joined: Sat Aug 13, 2016 9:20 am
Contact:

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

Post 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.
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.

User avatar
darkfrei
Smart Inserter
Smart Inserter
Posts: 2904
Joined: Thu Nov 20, 2014 11:11 pm
Contact:

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

Post by darkfrei »

Is here easy way to convert custom ngon to TriangleStrip?

User avatar
DaveMcW
Smart Inserter
Smart Inserter
Posts: 3700
Joined: Tue May 13, 2014 11:06 am
Contact:

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

Post 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.

smaudet
Manual Inserter
Manual Inserter
Posts: 4
Joined: Fri Aug 14, 2015 4:57 pm
Contact:

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

Post 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. :/
Attachments
actual.png
actual.png (286.98 KiB) Viewed 2373 times
expected.png
expected.png (4.91 KiB) Viewed 2373 times

smaudet
Manual Inserter
Manual Inserter
Posts: 4
Joined: Fri Aug 14, 2015 4:57 pm
Contact:

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

Post 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.
Attachments
hack-solution.png
hack-solution.png (507.84 KiB) Viewed 2354 times

User avatar
DaveMcW
Smart Inserter
Smart Inserter
Posts: 3700
Joined: Tue May 13, 2014 11:06 am
Contact:

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

Post by DaveMcW »

Graphics cards cannot draw concave polygons, so triangles are required if you want to draw something concave.

posila
Factorio Staff
Factorio Staff
Posts: 5202
Joined: Thu Jun 11, 2015 1:35 pm
Contact:

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

Post 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.

smaudet
Manual Inserter
Manual Inserter
Posts: 4
Joined: Fri Aug 14, 2015 4:57 pm
Contact:

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

Post 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.

smaudet
Manual Inserter
Manual Inserter
Posts: 4
Joined: Fri Aug 14, 2015 4:57 pm
Contact:

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

Post 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. 🤔
Attachments
2020-05-08 17_36_31-Clipboard.png
2020-05-08 17_36_31-Clipboard.png (272.9 KiB) Viewed 2249 times

Post Reply

Return to “Modding help”