- Home /
Dynamically change draw order of procedurally generated planar meshes.
Hi everyone,
I have a draw order / z-fighting problem that I just can't find a solution for. Based on a xml file I procedurally generate planar meshes that all have the same z-value (areas from an osm file, if anyone is interested). These planes as they are defined in the xml file can overlap or very often a smaller plane is completely enclosed by a larger one. Due to the same z-value I obviously get z-fighting.
I now want to dynamically change the draw order of the planar meshes via script, so that smaller planes overlapping bigger ones are drawn on top. I tried incrementing material.renderQueue
for certain planes, which had no effect, however. Similarly I played around with the Offset
in the shaders. Unfortunately you cannot dynamically set this value (see this answer).
With smaller planes drawn on top of bigger ones, which themselves my be overlapped by even smaller ones, this kind of creates a hierarchy. This and the fact that the number of planes isn't previously known and can be very large, makes me think I cannot offset certain planes in the z-direction, however small the amount is, because the offsetting may accumulate to an amount that a gap could be visible for a perspective camera.
I also cannot use multiple cameras as I would have way to many cameras in the scene.
I'm looking for a solution that considers the following:
The z-values of the planar meshes have to stay the same due to the accumulation of z-offsets. Also I assume that if I move my perspective camera around I could have the planes moving relatively to each other i.e. moving different amounts as seen from the camera, due to the difference in z, even if no gap is visible?!
A change to a certain planar mesh may only change the object itself, not any other objects that have the same material for example, since the draw order is supposed to be based on the object's relation to other objects in terms of size, not it's material.
After the generation I export the meshes with this script to an .obj file. The draw order has to be persistent so that the imported .obj file looks exactly the same as the generated scene (another reason why a solution with multiple cameras would not work in my case).
This is what it looks like:
This is what I want it to look like:
I really hope there is a reasonably simple solution to that, because I've been looking for ages now. Any help is greatly appreciated!
Just bringing comments over from the test question
Fattie :
Schnod, you didn't even mention - vaguely or generally - what sort of game this is ?? Is it 2.5D, is it like Doom, is it $$anonymous$$ecraft, or what?
if 2.5D, this is pretty much stock-standard in 2.5D games fortunately
http://answers.unity3d.com/questions/473217/how-to-simulate-2d-layers-in-unity.html
also mentioned in http://answers.unity3d.com/questions/321762/how-to-assign-variable-to-a-prefabs-child.html
you ust have "general layers" (like background, z is 20, clouds, z is 15, enemies, z is 11 .. whatever)
and within that - almost certainly incorporated with your pool code - you have a stretegy for "micro layers" where you move everything apart by a small amount like 0.05 or whatever.
(this becomes a typical shitty general-computing problem of filling the gaps, reorganising them, whatever works for you)
It's hilarious that everything seems so easy when you first open 2DToolkit :)
Schnodahipfe :
It's not really a game, I generate a 3D city environment from the osm file: in addition to the 2D planes, there are 3D buildings sitting on top of them. I also have a perspective camera that looks at the environment from a certain angle, which is why I saw the problem with offsetting the planes in z, because if I have a lot of planes on top of each other at a certain point, the difference in z may be visible. Or am I mistaken? The problem is that the camera has to be perspective. On the other hand the camera can be put to a reasonably large near clipping plane as there is a $$anonymous$$imum distance between the camera and the environment, so that I can make the z-offset pretty small without having z-fighting.
Fattie :
You'd have to post a screen shot. The buildings are irrelevant so delete them.
If there are small gaps between your planes ("ground") .. yes of course you will see them.
Normally you'd have to stitch those together (mesh program$$anonymous$$g), carefully use tiles, or just arrange it so they absolutely butt against each other.
Generally it's almost impossible to help unless you post a screenshot, for this type of problem. Notice I offered a fantastic answer for next time you're making a side shooter :)
Schnodahipfe :
Am I assu$$anonymous$$g correctly that if I move my perspective camera around I could have the planes moving relatively to each other i.e. moving different amounts as seen from the camera, due to the difference in z? Even though I cannot see a gap between them?
If that is not the case I could just try and find the $$anonymous$$imum offset value where I don't get z-fighting with my camera and hope that the offsets don't accumulate to an amount that makes the planes look like they're actually on different "levels". However I'd much rather prefer a solution that uses something like render queues (or get those to work) and leave all the planes on the same z-axis.
Answer by Schnodahipfe · Jul 03, 2013 at 09:03 AM
So I worked around the problem wiht the help of the Offset
property in custom shaders (see here).
As I mentioned in my quesion, the Offset
shader property cannot be set dynamically via script. So the only solution I could come up with, was making several copies of the original shader I was using, each with a different Offset
value combination (`Offset -1, -1`; Offset -2, -2
; Offset -3, -3
etc.) and naming them accordingly (Illumin-Diffuse-Offset1, Illumin-Diffuse-Offset2, Illumin-Diffuse-Offset3 etc.). Then I assigned the appropriate shader to the materials at runtime.
In addition there was an issue with saving the meshes to an .obj file, because the information which material was assigned a new shader during runtime is lost. So I had to use a TextAsset to save this information. When the saved .obj file is imported I then read the text file and assign the shaders accordingly.