Archive 17/01/2023.

Manually z-align parallel billboards

Pencheff

I have couple of billboard sets that lay on the same plane, say their nodes all have Z = 0 and are parallel.

I need the green plane on top right to be rendered over the white plane. One way is to change the green plane’s Z axis closer to the camera with very small value, but I don’t like the results (I really need them to be parallel). The other way I can think of is to use materials with different z-bias, I used that with Ogre3D, but the problem is I need to use different materials for every plane.
Any other ways I can do this ?

Modanung

Maybe you could couple the z-bias to the vertex colours using a custom shader? Or can it only be set per material?

Pencheff

Hmm yes that sounds logical. Thanks, I’ll try that.

sabotage3d

This looks really similar to my problem here: Alpha sorting issue.
It works if there is no transparency if there is between two batches one is opaque not sure why.

Modanung

If you use the vertex alpha channel you can still colour the vertices as you like.

Pencheff

I could but I will lose alpha, I still need to control every quad’s transparency.
In Ogre3D I had an option to control the rendering order of every entity by using setRenderQueueGroupAndPriority(), which solved most of the problems when having transparency.

What I’m trying to achieve is 2D functionality inside 3D, by having a “screen” component as master and “media” component as child nodes, then those get placed on a plane with common Z, camera moved back and adjusted so it captures the whole “screen” plane. Every child plane must have color/transparency and Z order.

Modanung

Could you add an extra channel?

Pencheff

Sorry I edited my post after your response.

I can add an extra channel to pass z-order, I’m still not sure how to control which item renders over another with vertex shader, unless I touch the vertexes to get closer to the camera and that breaks things. I’m not a shader expert, maybe there’s a legit way of doing it.

Modanung

Neither am I. I couldn’t tell you the exact implemention as of now. Just connecting blurs here. :wink:

sabotage3d

This is what worked for me in the same batch. For example in the Unlit shader you can add:

int index = int(iObjectIndex);
gl_Position.z = -index * 0.001;

Where ObjectIndex is an attribute per billboard or you can add shader override in two different materials to override the gl_Position.z. The advantage over modifying the position is won’t get closer to the camera.

Pencheff

Isn’t gl_Position modifying the vertex position ? What happens if you choose a bigger multiplier than 0.001, doesn’t this move the vertex closer ?
There’s a Drawable::sortValue_ and accessor methods, but it only seems to be used for input raycasting, if only it was used for sorting rendering order …

sabotage3d

I don’t think it modifies the vertex position. It is used in the depth directly:
vWorldPos = vec4(worldPos, GetDepth(gl_Position));
Where worldPos is the actual vertex position.

Pencheff

OK then, that sounds like a solution, it still limits me to use special material (with that shader), but it’s something.

Pencheff

Either I’m doing something wrong, or gl_Position doesn’t do what I desire. Here’s my VS, copied from Unlit:

#include "Uniforms.glsl"
#include "Samplers.glsl"
#include "Transform.glsl"
#include "ScreenPos.glsl"
#include "Fog.glsl"

varying vec2 vTexCoord;
varying vec4 vWorldPos;
#ifdef VERTEXCOLOR
    varying vec4 vColor;
#endif
uniform float cZorder;

void VS()
{
    mat4 modelMatrix = iModelMatrix;
    vec3 worldPos = GetWorldPos(modelMatrix);
    gl_Position = GetClipPos(worldPos);
    gl_Position.z = -cZorder;
    vTexCoord = GetTexCoord(iTexCoord);
    vWorldPos = vec4(worldPos, GetDepth(gl_Position));

    #ifdef VERTEXCOLOR
        vColor = iColor;
    #endif
}

When I change the cZorder, the billboard only flickers, no matter the values.

Pencheff

Oh, my bad, my material is same for both planes I’m testing this on, I need to clone materials so every component gets its own cloned instance.

Pencheff

@sabotage3d, it works fine thanks. Any other ideas how to do this without having to use special material for the purpose ?

sabotage3d

You can try Material::SetRenderOrder it might work in your case.

Pencheff

That is exactly what would I was looking for. Now the element on top still bugs like in the screenshot, but if I set an appropriate BiasParameters that should do the trick.

Pencheff

I can’t seem to find a way to do this with BiasParameters, so the best technique so far is the one with gl_Position.z adjustment.