Fast Mesh Vertex Setting

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
Tanner
Party member
Posts: 166
Joined: Tue Apr 10, 2012 1:51 am

Fast Mesh Vertex Setting

Post by Tanner »

Are you using meshes with thousands or tens of thousands of vertices? Are you updating those vertices every frame? Do you long for speed, blazing speed above all else, including memory safety and your game targets platforms where you have access to LuaJIT's FFI?

Image

It doesn't seem to be on the wiki anywhere but this little gem does appear in the changelog for Love version 0.10.0: "Added the ability for love.graphics.newMesh and Mesh:setVertices to accept a Data object." Under the hood, what this means, is that instead of iterating over a Lua table and pulling vertex data from it, `memcpy` can be used on a piece of contiguous memory to buffer your vertex data. What this means is you're faster than this. Don't think you are, know you are. Come on. Stop trying to hit me and hit me.

Example implementation: https://gist.github.com/TannerRogalsky/ ... 9ff571cff2

Essentially, we 'abuse' `love.image.newImageData` to allocate us a block of memory, cast that pointer into something useful using the FFI and then gain a 10 to 20 times speed increase when setting vertices.
==BENCHMARKS ==

# Lua Table
0.01018577840228970278479980748898
0.01030243035248539114345778244797
0.01036473468815287020394766415166
0.01040154481597710400819778442383
0.01147316898359864410783526267323

# Data Object
0.00056909972287068875691079528067
0.00057624589825555996326633678706
0.00060287722488671811535421163342
0.00062500485667250872331979216767
0.00064352708351280958967710610352
Benchmarks performed on a MacBook Pro (Retina, 13-inch, Early 2015).
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

Re: Fast Mesh Vertex Setting

Post by UnixRoot »

Has anyone actually tried this approach? For me, the FFI variant is definitely not 10 - 20 time faster.

Code: Select all

FFI =    
average 0.00000201060671953970970000000000
Table = 
average 0.00000219103070769008190000000000
What I'm doing wrong?

Code: Select all

       vertices = {
           {x1, y1},            -- 1 top left
           {(x1+x2)/2, y1},     -- 2 top center
           {x2, y2},            -- 3 top right
           {x5, y5},            -- 4 center right
           {x3, y3},            -- 5 bottom right
           {(x4+x3)/2, y3},     -- 6 bottom center
           {x4, y4},            -- 7 bottom left
           {x6, y5},            -- 8 center left
           {(x5+x6)/2, y5}      -- 9 center center
        }

           for i=1,9 do
              local vertex = data[i - 1]
                vertex.x = vertices[i][1]
                vertex.y = vertices[i][2]
             end

            mesh:setVertices( imageData )  -- the FFI Pointer is on imageData

grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Fast Mesh Vertex Setting

Post by grump »

I haven't tried this specific implementation, but it ought to be faster in general. It's just that 9 vertices is nothing - way too few to measure any difference in this 2 microsecond range.

You should also use love.data.newByteData. Not need to abuse ImageData anymore.
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

Re: Fast Mesh Vertex Setting

Post by UnixRoot »

grump wrote: Thu Nov 18, 2021 8:08 pm I haven't tried this specific implementation, but it ought to be faster in general. It's just that 9 vertices is nothing - way too few to measure any difference in this 2 microsecond range.

You should also use love.data.newByteData. Not need to abuse ImageData anymore.
Sure its only 9 vertices, but im drawing around 1000 of these Meshes. I cant use instancing, because every mesh has a different shape.
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Fast Mesh Vertex Setting

Post by grump »

UnixRoot wrote: Thu Nov 18, 2021 8:23 pm Sure its only 9 vertices, but im drawing around 1000 of these Meshes. I cant use instancing, because every mesh has a different shape.
It is what it is. You won't get any speed improvements from FFI with data sizes that small because the bottleneck is probably not the slowness of tables.

1000 draw calls is a lot. Maybe you can combine them into fewer or even just one single mesh? Post more details?
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

Re: Fast Mesh Vertex Setting

Post by UnixRoot »

Sure, I'm trying to build a 2.5D racing game engine from scratch. I'm streaming polygonal segments on the fly while driving. Curves and hills are fake and not real 3D. I'm already culling segments with backfaces, behind hills, etc. I dont know how it can be further optimized, because i have to calculate 6 meshes with 9 vertices per segment, to get 4 lanes with different textures and rumble strips ourside. I could draw them with only 4 vertices, but I need to subdivide them because of the affine texture mapping. But the polycount isn't my problem, the bottleneck has to be somewhere else. I wish I could draw them instanced.

Image

Image
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Fast Mesh Vertex Setting

Post by grump »

1. Measure what is slow before trying to optimize. Don't guess.
2. Don't draw 1000 tiny meshes. Use one big one. Update it in a ring buffer-like fashion and draw it in 2 draw calls with setDrawRange.
3. Use one texture instead of four. Combine them into one atlas and adjust your texture coordinates accordingly.
4. If you want to speed things up by using ffi, then don't make a table first - especially not a new table every 9 vertices. Update the ffi data directly.
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

Re: Fast Mesh Vertex Setting

Post by UnixRoot »

Thanks for your answer.
Measure what is slow before trying to optimize. Don't guess.
It's the calculation of the perspective projection for every vertex inside the draw range and then setting those vertices.
Don't draw 1000 tiny meshes. Use one big one.
The track isn't 3D. It's not even 2D. Technically it's only a 1D line with commands on how much the line "bends". But it doesn't even bend for real, it's not 3D coordinates, the polygons do not rotate into the curve. They're all perfectly parallel. It's the same technique they used for the outrun arcade cabinet but without a pre rendered street graphic to pick lines. I can't really build one big mesh.
If you want to speed things up by using ffi, then don't make a table first
If I build one big mesh, I could only build what's inside the draw range, and I have to build it on the fly, it can't be prebuilt. This would be pure horror. The other points simply don't exist.. Nothing you can build in a 3d software and just render.

I still have to calculate the screen projection for every point, every frame. I still have to build and iterate through a huge table which stores the actual points, every frame. Where should I store all ov the vertices, if not in a table.

You can't just build a mesh and translate and rotate it without touching the vertex data again, like it would be in a real 3d engine. I really have to set new vertex positions for each vertex on the screen every frame.

That's how those 2.5D pseudo 3D engines work.
Use one texture instead of four. Combine them into one atlas and adjust your texture coordinates accordingly.


In one big mesh, how would I set the UV coordinates of segment 100 lane 2, to use the dirt texture and segment 200 lane 3 + 4 to use the energy texture for example. For this I would have to set even more vertex attributes every frame. In one big (impossible) mesh, this would be a really nasty task.

Oh and texture atlases bleed, if you use mip mapping. Even if you use padding. With more padding, you just move the problem towards the horizon.

http://www.extentofthejam.com/pseudo/

The technique is explained here, if you're interested.
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Fast Mesh Vertex Setting

Post by grump »

All this can be solved by tweaking your approach to make it more GPU friendly. If you're doing all these calculations on the CPU you might even be better off doing it all on the CPU incl. texturing, idk. Changing your data to make it more digestable for the GPU is your best bet.

It's more or less guesswork at this point. Make a real mesh and you're good. It seems unlikely that you can solve the performance problem with tiny tweaks to a bad approach.

The table thing can obviously be changed. Just don't use the intermediate table. The bleeding problem is solvable by either padding the atlas, or by using array textures.

There's a pseudo 3d racer for love2d on Github that looks good; i think it's called Downforce. Take a look for inspiration.

Good luck!
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

Re: Fast Mesh Vertex Setting

Post by UnixRoot »

grump wrote: Fri Nov 19, 2021 9:32 am All this can be solved by tweaking your approach to make it more GPU friendly. If you're doing all these calculations on the CPU you might even be better off doing it all on the CPU incl. texturing, idk. Changing your data to make it more digestable for the GPU is your best bet.

It's more or less guesswork at this point. Make a real mesh and you're good. It seems unlikely that you can solve the performance problem with tiny tweaks to a bad approach.

The table thing can obviously be changed. Just don't use the intermediate table. The bleeding problem is solvable by either padding the atlas, or by using array textures.

There's a pseudo 3d racer for love2d on Github that looks good; i think it's called Downforce. Take a look for inspiration.

Good luck!
Yeah you're right. But I dont want it to be a 3D racer. With a "real" mesh and "real" projection its a 3D engine. I could do it, I have plenty of 3D experience, but I really wanted to do it the old way, with pseudo 3D segments. Your approach is probably better, but it wouldnt be pseudo 3D anymore. That's not what i want.

Now to the texture thing. padding doesn't solve the bleeding problem for smaller mip levels. At the segments near the player, it works great, but towards the horizon it still starts to bleed really bad, when the smaller mip levels are rendered. You can use more padding to move the problem father away, but you can't get rid of it. I already tried it.

How can i use an array texture as a texture for a mesh? I've read the documentation but I dindnt find anything usefull how to select the right layer to texture a mesh with it.
Last edited by UnixRoot on Fri Nov 19, 2021 12:35 pm, edited 4 times in total.
Post Reply

Who is online

Users browsing this forum: No registered users and 14 guests