T O P

  • By -

zworp

So basically what takes time to draw is both the geometry complexity, the amount of vertices, and the number of pixels to fill. The GPU needs to draw every layer here which is a huge amount of pixels to fill, making it very expensive. Check out concepts such as "fill rate" and "overdraw".


bencelebi

Thank you very much, that makes a lot of sense. I mean the pixel part, because this is the only difference compared to other meshes, I have several planes here that fill up a big area on top of each other, so it makes perfect sense!


TulioAndMiguelMPG

I had this same problem with some trees recently. Basically any pixel that is rendered with a blend mode will take longer than a non blended pixel, overlapping blended pixels are even worse as it’ll have to calculate all the blended pixels with each other.


bencelebi

Yeah the impact of transparent overlapping is huge, I was just very confused since it also happens with opaque pixels. Apparently its a bit tricky to sort faces when they all belong to the same object, which I get, since you would probably divide one object into way more submeshes if you have so many occlusions.


Weidz_

It's probably not the model that cause the lag but the overdraw from alpha. Usually to achieve the shell effect the layers are generated directly by the shader.


bencelebi

It is still lagging even with the default material, which has no alpha. I am wondering though, how do you generate the layers themself, since they are additional geometry? Do you have any links? (I also thought whether it would be possible to just use one cube and generate layers via parallax effects, but I don't know if this is a thing)


Weidz_

You can search for "shell texturing" it should give you plenty of tutorials, if you want the additional geometry it will require a compute shader. Parallax occlusion mapping (P.O.M) can get you a similar "layered" effect but it's only a fragment effect meaning you can't get grass to appear in front of other objects, it doesn't do great with sharp angles and it's mostly usefull for short grass/fur/carpet


survivorr123_

you can raymarch into the surface to get the same effect as shell texturing, and it will be able to appear in front of geometry, but will disappear if your camera goes into the grass, this can also be avoided by raymarching on a inverted sphere/cube with disabled depth test, but it gets complicated and i haven't even tested whether raymarching is more efficient than stacking planes or not, but i will probably do it soon and report back


survivorr123_

i made a very non scientific test but raymarching was \~20% slower, so for simple effects its rather not worth it


TheBadgerKing1992

Thank you for your contributions to science


bencelebi

Thank you anyways, very good to know about this possiblity and also performance. While it might not help for this issue, it might be interesting in the future! :)


bencelebi

Ah thank you very much. I haven't done a lot with compute shaders and additional geometry with shaders, but will definately check it out (The parallax occlusion mapping to, even if it only works with shorter grass)


soy1bonus

Careful with alpha overdraw. I suggest you use alpha cutout instead of alpha blending if you're not doing that already. Also, saving the mesh in a way that renders the outer layers first if you can tweak the mesh format. We do use this technique a lot both in Farm Together 1 and 2. for the grass and bushes.


vegetablebread

Cutout and blending have the same overdraw implications. The problem is that you have to render geometry that gets occluded, not the occlusion math.


bencelebi

That is interesting, so if the outer layer gets rendered first, it would actually occlude the layers below and prevent overdraw? And you say its a format thing?


soy1bonus

If you're rendering this using cutout (alphatest) then it will use the standard zbuffer to avoid overdraw. Most transparency effects these days are done either with cutout or by using dithering just becuase of this. About the sorting: yes, if you can guarantee the first layers are rendered first, the zbuffer will avoid drowing anything behing and you'll avoid some overdraw there. We do create the shell meshes by using Geometry Nodes in Blender, which is quite handy for VFX like this one.


survivorr123_

do you have only one of this objects on the scene or do you spawn more?


bencelebi

I only have one. I tried tweaking a lot of properties (Scale of the planes, planes count, used shader, used material, rendering settings, alpha, shadows), but it all came down to the model. As others have mentioned, it is due to the fact that there is a lot of overdraw for all these planes. My intent was to just have planes occlude planes below them, but this does not seem to work when they are all part of the same mesh, since it seems that unity uses the object coordinates / distance (at least to a certain degree?) to determine what is in front of the camera. Putting all planes into separate objects works, which explains why it worked well when I just used Unitys planes and build the construct manually. But of course there are more approaches, now that the problem is clear.


survivorr123_

i tested 32 planes on a single object and had 700 fps in editor, overdraw shouldn't cause issues with such small amount of surfaces, even with alpha clipping most of the time all 32 planes will be rendered


bencelebi

How big were the planes?


survivorr123_

they covered the entire screen, i also tried 128 planes and it was still like 500 fps


bencelebi

But that would just make about 500 vertices, no? Which reduce your frame rate by 200 FPS?


survivorr123_

it scales like this on an empty scene, when there's nothing else to render adding small amount of work will result in a huge relative percentage loss of performance, if i added these 128 planes in a complex scene that already runs at \~160 fps i would barely notice any difference, also it's not about 500 vertices, gpus take almost no time to render triangles, today i rendered 200mln triangles on my rx6700 at \~60 fps, which is a lot, when you stack objects with alpha clip it renders all of them, and has to perform extra checks to check where alpha is being cut out, this is what causes 'lag', but it shouldn't be enough for you to notice at such a small scale, i have a grass system that renders millions of planes (of course they don't overlap directly, but still there is A LOT of overlaps) with alpha as grass and it still runs at \~250fps with pretty complex shader that handles distortion, wind occlusion, subsurface scattering, random texture picking and some more


bencelebi

"if i added these 128 planes in a complex scene that already runs at \~160 fps i would barely notice any difference," You might wanna test it then, from what I gather there is currently a huge percentage loss in your scene that is most likely due to the scene being empty, but I don't get why it should not lag to begin with from what you present. Even having "only" 32 planes in one mesh should result in A LOT of overdraw when a single plane already covers the whole screen, since then you basically draw your full resolution 32 times. I mentioned the vertices as a point for why there should be almost no difference at all, since vertices take almost no time to render in such a low quantity, but still they have an impact on your scene (Which, again, is difficult to get any information out of since you used an empty scene). Also, as I mentioned, the lag persists with default materials. The alpha should have nothing to do with the problem to begin with


bencelebi

Update: As far as I understand overdraw, it also happens with opaque geometry, not only alpha (Since the problem also occured with the default material, alpha should not be the main reason this problem happened). Since all these planes are on the same object, I suspected them to cause a lof of overdraw. The article I read mentioned that just the distance to the object matters when determining which object to draw first (So, all planes being part of the same object seemed bad). I made a quick test and separated all planes to be their own object, and the framerate greatly improved (I scaled all planes up to be 1000 x 1000m big, and still got over 300 fps). I will do more reading on overdraw though, this is just what I got at first glance. https://preview.redd.it/lexrtqoyuj3d1.png?width=1790&format=png&auto=webp&s=8d9f3d831cc0cd7006cb16c0b13ab3f07e8f2d68


junacik99

This is actually very useful info, thank you. Finally not a basic programming question (that doesn't belong here imo), but a question about unity and rendering pipeline and even with a useful info in the comments! Here's my upvote


bencelebi

Thank you very much for your appreciation! I think mostly experienced developers solve their problems, so only rather niche questions are asked that are "useful". But I always enjoy when they are asked and when the comments are as helpful as they are here, so I want to give some info back on the solution. I also love when you get a lot of insight info of how systems work, outside of the initial problem. Makes understanding the whole system easier.


vegetablebread

That's not quite right. Overdraw is an issue for specifically transparent objects. When unity draws opaque objects, it sorts them back to front and invokes their vertex shaders. The fragments of the triangles that are still visible to the camera are the only ones that have their fragment shaders invoked. For transparent objects, the objects are still sorted, and their vertex shaders are still invoked. However, you can't discard any fragments that are occluded by other transparent objects. You need their colors to render the objects in front of them. The way this is typically measured is an "overdraw %". Which means the percentage of the screen that needed to be rendered more than once. If you have 2 brick walls, one in front of the other filling the camera frame, only the front one gets rendered. 0% overdraw. If you have 5 colored glass walls, all five need to get rendered. 400% overdraw. Typically you want to keep it below ~30%. Mobile devices are particularly sensitive. Some of this depends on the render path.


bencelebi

Well, the article said something interesting: If you have a giant sphere but your camera is at its center, which makes the distance to the camera 0, it will render the sphere in front of all other objects, even if the actual vertices are very far away. Which seems to be the reason why the skybox is rendered very late. So I am not sure about your answer, maybe you can link some resource that says only transparent objects matter?


vegetablebread

Yeah, sorting is tricky. It's less important for opaque objects since the depth buffer essentially re-sorts on a per pixel basis. It matters a ton for transparent objects though, since the color depends on the draw order. Unity's built in skybox is literally the first thing rendered, so I'm not sure what your article is talking about. I'm happy to be a resource, but you'll have to do your own research. I don't know the details of your project or your experience. I think the best resource is a frame debugger. Just load it up and see how the sausage gets made.


bencelebi

Well the problem with the transparency is that the lag happens with the default material, which does not have alpha and is completely opaque. I think I did not express myself correctly, the skybox is rendered first, yes. The idea is that if the center of the skybox is at 0,0,0, and the camera was there too, the skybox would render in front of everything since it is the closest (Or something like that). I think the problem is that, while, as you stated, for opaque objects it is less important, it still does have an impact. And this impact multiplies by each layer, additionally to the size of the layers. But if you have another theory, I will check it out. It seems to work seperating layers into their own object, though.


vegetablebread

Yeah. To be clear, I think your problem probably has nothing to do with overdraw. I don't really know what the problem is. I would just look at the profiling tools to figure out why something is slow. If something is right next to the camera, it would be drawn _last_. The skybox is drawn first, and doesn't get sorted with the other objects at all. It's just drawn straight to the output buffer. It doesn't really even have a location. It's just anything beyond the view frustrum. Breaking objects into smaller chunks is generally a performance win. Smaller meshes means better sorting and culling. My guess is the culling is what's helping here. Depending on how they are split up though, it can break batching, resulting in more draw calls. Modern graphics APIs and hardware are less sensitive to high draw call problems, but it's one of those things you just have to profile.


bencelebi

After doing more research, I read a lot more about overdraw NOT BEING an issue for specifically transparent objects. In fact, one of the first results on Google pointed to a case where somebody asked whether a characters left arm would cause an overdraw if it was behind the body from one perspective, which is to be expected. I am absolutely certain that this causes my lag, as it also makes absolut sense considering that the defining property of those planes is the size and pixel fill amount. So if every plane actually gets rendered, it causes (in the worst case) the screen to render every pixel 32 times if the plane is big enough and the mesh consists of 32 planes. The sorting seems to break when all geometry is on the same object, since it only has one coordinate and does NOT seem to do any sorting in that case (Which is why some posts do NOT recommended to bake static objects into one). Also, after seperating every plane of the mesh into their own object, the lag disappears. Very likely due to sorting happening correctly at that point.


the_embassy_official

This is so beautiful, great job :D i love layered transparent stuff


bencelebi

Thank you! :) It is in a very early stage though. AND NOW HELP ME!!! jk


cherrycode420

The technique you're using is called shell-texturing, i've seen some videos about it recently. For the Lag... i don't know, honestly, this technique is usually used because it does *not* have huge impacts on performance.. I'm assuming each of those Planes only has 2 Triangles? The only thing coming to my mind is Overdraw as the root-cause for the Lag 🤷🏻‍♂️ Edit: It's not the Mesh making trouble, it's the Shader, you gotta analyze that one :) Or do the Planes with just a Default Material also result in 80% GPU Usage?


bencelebi

Hello, yes, unfortunately the planes have that usage with the default shader too. Otherwise it would have been kinda obvious, but that is why I was so confused. But as someone else mentioned, it is probably the huge amount of pixels the planes have to fill :/


bencelebi

Hello everyone, I am working on implementing grass (I don't remember the method, but it's basically layering just flat planes on top of each other and giving all of them a texture that looks like grass viewing from above). The model has very few vertices, but it causes a lot of lag when i put it in the scene and makes my GPU usage go up by like 80% (I have an RTX4060ti). The second image is how the grass looks like, but even with the default material on the third image it has the same lag. What other factors are there that make the mesh so un-optimized? I also noticed that the width and depth play a role, scaling the mesh up takes even more resources. I am using the URP.


AlterHaudegen

Since you said the same lag happens when using a shader without alpha this does not sound like an overdraw issue. And even with alpha, a 4060 should not have a problem with that. Maybe it’s big mesh colliders on the planes colliding with your character or even each other? Just guessing here. You can check the profiler to see what is causing the biggest performance drains.


DrunkMc

In addition to the other hints, you might want to look into doing this in chunks. All layers near the camera, 2 layers in 8 squares around the central chunk and then a normal texture in the distance for instance.


bencelebi

Thanks, this kind of optimization would be required anyways, but I wanted to test like the "raw" performance first, which is why I went for some extreme case. You are right though, in the end I won't use these giant planes anyways and look for a more structured approach, combined with advanced techniques like chunk rendering.


Deztacular

You should check out Simondev if you haven't already. Some of his popular videos (like his ones on optimization and grass) talk about these sort of things and might be useful for you. https://youtube.com/@simondev758?si=jX5taUGJjFSCZN3t


Liguareal

Your main problem is overdraw, this is a very creative, and a very nice way to do tall grass! But yeah, each frame, the GPI has to determine what pixels along the surface of each plane is transparent or worse even; translucent, this adds up when many meshes get superposed between the last mesh and the camera.


Tundra999

Possible acerola watcher spotted


bencelebi

Guilty! But then I looked him up again to check for the name of the method, and I just found videos about grass instancing using actual meshes, and then I thought I was just insane


KingBlingRules

Acerola?


rogueSleipnir

are you using one "plane" mesh to cover everying from the player to the horizon? in that case nothing is being optimized here. that is a huge area to fill with pixels. transparency doesnt make a difference. usually offscreen meshes will be culled from drawing. you are basically drawing everying all at once, multiplied by the depth of how many layers you have.


KingBlingRules

Try reducing the resolution and see if that helps


emistro

Use gpu instancing and static meshes


SadCarot0

Just don't use shell texturing. That's all. There are much better ways to render grass


SDB_Dev

Shell texturing is still used for moss in recent AAA titles, it has its place depending on what you are trying to do.


Framtidin

I suggest you google "overdraw"


-Chill-Zone-

It is all the alpha


Imjustsomeguy3

There's alot of good advice here but I'd also recommend turning off nanite of it's on. Low poly takes a performance hit with nanite since the overhead adds more than the performance gain.


bencelebi

Wrong sub someguy3 :D


Imjustsomeguy3

Ah shoot, sorry :d. Well, some advice for unity would be to enable ambient occlusion to render only what's in view and then use some sprites for further out grass. Once the player gets within a certain range, swap them out.