[SOLVED] blf.position -> How to calculate the z value (depth buffer?)

Hello,

I’m currently working on a script for text output with the blf-module for my own small gui system.

The blf module has an method called position() and I know what to insert for x and y, but not for the z value (this is important, I will explain why in the next paragraph).

At the moment the z value is set to 1, but that means that the text is always visible above anything else. But because I want to implement a dropdown menu (all gui elements are blender objects, only the text gets drawn by python/blf/bgl), I need to know how to hide the text below the menu. So I have to change the z value according to the object on which position the text should be drawn (my script searches for objects with the property “text” and draws a text at their positions).

But the question is: How to calulate the z value? I think it has something to do with the depth buffer, but I don’t know how to calculate it (I only found a formula for calculating it “backwards” (reconstructing position from depth buffer) and one to calculate it from camera space or something like that (I know nothing about openGL/coordinate transformations or depth buffers and so on))

This is my current code to calculate the z value, but it doesn’t seem to work. I use orthographic projection.


# obj = object, on which position the text should be drawn


# camera clipping values
z_far  = cam.far
z_near = cam.near

# distance between cam clipping and camera to object
cam_view_length = cam.far - cam.near
distance_obj_cam = cam.worldPosition.z - obj.worldPosition.z

# calculate the percentage of distance_obj_cam according to the cam_view_length
pos_z = distance_obj_cam / cam_view_length

# invert and offset to prevent z fighting
pos_z = 1 - pos_z + 0.01

The z values are about 0.7 (the camera is 30 units away from the objects and the clipping distance is about 100), but it doesn’t work.
Is the depth buffer range between -1 and 1? I tried this as well but this doesn’t work either.

I tried the following:


pos_z = 1 - pos_z * 2 + 0.01

Thanks for your helphttps://blendpolis.de/core/images/smilies/smile.png Btw I’m not a native english speaker so if you don’t understand something just ask.

Momel

I need to know how to hide the text below the menu

well, parent to a plane, move plane backwards,
simple fade in fade out animation,
change it’s position to behind the background.

or do you really need to work with the z-offset?

blender itself refers the z-offset in materials as:
materials.offset_z, maybe you can work with that.

Other then that i did not work with z offset other then with/in the material itself.

Hi, thanks for your answer :slight_smile:

I don’t use blender text objects, i use the blf module. That’s why parenting won’t work, there is no text to parent… Or what do you mean by that?

I don’t calculate the distance with getDistanceTo(), i had this in my code before but because i use orthographic projection i think only the z distance is important (not all the objects that should have text above them are centered, but the z position is the same).

Also, the z-offset from the material doesn’t help that much because it’s just an offset, i need a position. But I will try it, maybe I have missed something.

Thanks anyways :slight_smile:

I’m not sure that the z value is even used in the blf.position function. Instead, you can control the layering of text by changing the order in which you make your draw calls. Text drawn later will appear on top of any text drawn beforehand.

Yes, it is. If I decrease the value to about 0.5, the text doesn’t get drawn anymore because it gets drawn behind the other gui elements. If I choose a value a little bit above that threshold, the text is drawn above my background plane but below the dropdown menu. That’s how it should work, but I don’t want to adjust the value manually, because with this solution the dropdown text isn’t shown above the menu but below that. So you can’t see it.

My problem isn’t that some text is on top of other texts (in fact, all the text is currently colored white so you can’t see the difference). My problem is that the text gets drawn over other game objects. If I used bgl to draw the gui that would definitly work, but as I don’t (I use game objects because I can use packed textures with it and have more control over mouse input) this doesn’t work…

Here is an image of the problem (the settings menu is just a prototype, so it doesn’t look that good):

Well, I don’t know if this will help, but I randomly found this and thought about your problem: https://docs.blender.org/api/blender_python_api_current/bge.types.KX_Scene.html#bge.types.KX_Scene

Relevant code:


# Get the depth of an object in the camera view.
from bge import logic

object = logic.getCurrentController().owner
cam = logic.getCurrentScene().active_camera

# Depth is negative and decreasing further from the camera
depth = object.position[0]*cam.world_to_camera[2][0] + object.position[1]*cam.world_to_camera[2][1] + object.position[2]*cam.world_to_camera[2][2] + cam.world_to_camera[2][3]

Maybe you will be able to use this somehow.

Hi, thank you :slight_smile:

world_to_camera is something that might work, I found this a while ago, but i don’t know how to interpret the values of that matrix. (I now nothing about transformation matrices etc.).

Unfortunately that code only returns the negative z-distance between the camera and another object when the camera is looking down in orthographic mode. But world_to_camera could solve the problem (i found a lot of formulas for calculating the depth buffer with coordinates in camera space (or was it screen space, i don’t know it anymore)), so I will try to figure out how to use it.

If you/someone know(s) some good resources for learning the math behind such transformation stuff, please let me know.

Again, thank you very much :slight_smile:

Finally found a solution :slight_smile:

There is a possibilty to pass the z-coordinate from 3D space to blf.position().

Drawing code as suggested in the blf API docs:

width = render.getWindowWidth()
height = render.getWindowHeight()

bgl.glMatrixMode(bgl.GL_PROJECTION)
bgl.glLoadIdentity()

bgl.gluOrtho2D(0, width, 0, height)

bgl.glMatrixMode(bgl.GL_MODELVIEW)
bgl.glLoadIdentity()

If you change it to the following, it works with z-coordinates in orthographic projection:

bgl.glMatrixMode(bgl.GL_PROJECTION)
bgl.glLoadIdentity()

#0.1 and 100 are the clipping values of the camera
bgl.glOrtho(0, width, 0, height, 0.1, 100)

# Delete this:
#bgl.glMatrixMode(bgl.GL_MODELVIEW)
#bgl.glLoadIdentity()

The x and y coordinates remain the same, you have to use the screen position of them.

If you are running in the BGE you can extract the near and far planes from the camera, instead of hardcoding values like you did. I saw too many GL stuff written this way that would assume a certain camera configuration when it could easily be changed.

def bglstuff(controller):
    owner = controller.owner
    camera = owner.scene.active_camera

    # ... stuff

    bgl.glMatrixMode(bgl.GL_PROJECTION)
    bgl.glLoadIdentity()

    bgl.glOrtho(0, width, 0, height, camera.near, camera.far)
1 Like

I actually did that, it was just not a part of the code posted above. But thank you :slight_smile:

1 Like