Text and/or textures position in 3D world

Dear all,
first let me apologize in case this forum is not the appropriate place for the topic I am about to discuss,
I am somewhat inexperience in the matter and would appreciate any help to re-locate this discussion
where it has to be, also I learn(ed) OpenGL on my own, thus I might not be as accurate as you would
require me to be when asking for help, but I am more than willing to cooperate and provide more details
about my problem. To end my introduction I need to say that I already opened a similar discussion in
this forum few months ago, somebody then tried to help me, but at that time for some reasons the OpenGL
website went down and when it came up again the thread I created was lost … I thought then that I could find
a solution by my self so I did not re-created it, but I am still unable to do so …

I am developing a program for chemistry/physics, to visualize molecules and so on, I would like to be able
to display atomic labels, in particular to position labels at the appropriate location in my 3D windows, say in front of the appropriate atom.

If I can create and display properly text or textures, I have to face some troubles with their locations in 3D space,
see the following snapshot:

[ATTACH=CONFIG]778[/ATTACH]
EDIT: for some reason the quality of the snapshot is reduced by the forum and I can not attached a better one, please check this link for better quality.

Overall the position of the texture seems to be ok, but if you look closely to the Ge (germanium) atoms:

  1. A 3D rotation of the model confirms that the textures are properly positioned on X and Y the axis defined by the
    GTK window, but the depth is incorrect, in the snapshot Ge38 located in the background should not be visible,
    it should be hidden by the chemical bond in front of it, the same is true for Ge38 and Ge85 that should be hidden
    by the yellow (sulfur) atoms.

  2. I noticed without being able to explain it that the textures/atomic labels are in displayed in layer drawn by order
    of appearance: to draw the labels I browse my atom list from 1 to N (N is the total number of atoms in the model)
    the label/texture for atom 1 will always be further away in the 3D plane, followed by atom 2 and so on, thus if
    I rotate the model and manage, hypothetically, to align the textures/labels I will always see the last that was drawn/textured
    on top of the other even if the atom in located in the background and should not be visible.

  3. Sometime textures are properly hidden by chemical bonds and other atoms, sometimes they are not … overall
    I am very confused about all this

Here is the (simplified version of the) code I wrote to display the textures/labels:

  

// the camera angles   
GLdouble cameraAngleX;
GLdouble cameraAngleY;

struct atom {
  int id;
  int sp;
  float x, y, z;
};

gboolean render_format;
GLfloat color[4];

void init_string_renderer ()
{

// I think that this is the part of the code that matters !

  GLdouble winx, winy, winz;
  GLint viewp[4];
  GLdouble model[16], pro[16];

  glGetFloatv (GL_CURRENT_COLOR, color);
  glGetDoublev (GL_MODELVIEW_MATRIX, model);
  glGetDoublev (GL_PROJECTION_MATRIX, pro);
  glGetIntegerv (GL_VIEWPORT, viewp);

  glPushAttrib (GL_ALL_ATTRIB_BITS);
  glDisable (GL_LIGHTING);
  glDisable (GL_CULL_FACE);
  glEnable (GL_BLEND);
  glDepthMask (GL_FALSE);
  if (render_format)
  {
    glEnable (texture);
  }

  glPushMatrix ();   // Push-1

  gluProject (0.0, 0.0, 0.0, model, pro, viewp, & winx, & winy, & winz);

  glMatrixMode (GL_PROJECTION);

  glPushMatrix ();   // Push-2

  glLoadIdentity ();
  glOrtho (0.0, viewp[2], 0.0, viewp[3], -1.0, 1.0);

  glMatrixMode (GL_MODELVIEW);

  glPushMatrix ();   // Pop-3

  glLoadIdentity ();

  winz = 2*winz - 1.0;

  glTranslated (winx, winy, winz);
}

void end_string_renderer ()
{
  glPopMatrix ();    // Pop-3

  glMatrixMode (GL_PROJECTION);

  glPopMatrix ();    // Pop-2

  glMatrixMode (GL_MODELVIEW);

  glPopMatrix ();    // Pop-1

  glDepthMask (GL_TRUE);
  glEnable (GL_CULL_FACE);
  glEnable (GL_LIGHTING);

  glPopAttrib ();
}

void render_screen_string (struct screen_string * s_string)
{
// Here I am just rendering a 2D texture/image, so I do not think 
// that the code matters.
}

void render_string (char * string)
{
  init_string_renderer ();
  render_screen_string ();
  end_string_renderer ();
}

void draw_label (struct atom at, int id)
{
  int k, p;
  char * str = NULL;
  string_init = FALSE;
  string_end = FALSE;

  glPushMatrix ();

  glTranslated (at.x, at.y, at.z);
  glRotated (-cameraAngleY, 0, 1, 0); // Heading back ...
  glRotated (-cameraAngleX, 1, 0, 0); // and pitching back and so that labels orbit around atoms.
  k = at.sp;
  
  str = get_the_label_for_atom_k ();

  render_string (str);

  glPopMatrix ();
}

If you went through all this information you already deserve a thank you, a second one will follow if you can help me in any way :wink:

S.

You are changing the projection matrix from what was used to render the atoms. That means the values in the depth buffer (produced with the previous projection matrix) have no real relation to the depth values produced while rendering the labels. You may as well clear the depth buffer, that way you at least avoid spurious occlusion of labels that should remain visible.
To make the labels interact correctly with the rest of your scene you need to render them with the same projection matrix - and probably scale up those labels in the background so that all labels have the same screen space size.

Labels that are rendered later obscure labels rendered earlier because OpenGL maintains the order of your drawing operations and your labels are rendered with depth buffer writes disabled (glDepthMask(GL_FALSE)), so the label rendering does not modify the depth buffer.

Thank you very much for your answer and it was so fast :slight_smile:
However I am only able to understand it partially, so I figured why I need to get rid of the “glDepthMask()” instructions,
but this is definitely not the most interesting part in your answer.
How could I not change the projection matrix if I want raster to a 2D texture, scale it properly, and do not stretch its width/height
so that the text is no deformed in my 3D window ?

I understand that I might be asking dummy questions, sorry about that, and thanks in advance for your help.

S.

The basic technique is called a billboard, a quad/plane that is rotated to always be parallel with the camera’s projection plane.

Let’s say you have an atom at world space position Pw = (x,y,z) with radius r and want to attach a label to it, something like this should allow you to compute the corners:
[ul]
[li] Set OpenGL Modelview matrix to identity.
[/li][li] Transform Pw to view space: Pv = V * Pw where V is your view matrix.
[/li][li] Apply an offset to Pv to get the label outside the atom: Pv := Pv + r * (0, 0, 1.1), i.e. move the point towards the camera (in view space that is simply along the positive z axis) by the radius +10%.
[/li][li] Scale the label width/height by Pv.z (i.e. by the distance from the camera). So the corners of your label are (Pv.x, Pv.y, Pv.z), (Pv.x + Pv.z * W, Pv.y, Pv.z), (Pv.x + Pv.z * W, Pv.y + Pv.z * H, Pv.z), (Pv.x, Pv.y + Pv.z * H, Pv.z)
[/li][/ul]

Thank you for all this information,
now If you allow me I would require your help further, again I learned by my-self and was not trained properly
to the OpenGL ‘way of’ telling things. I must confess that I do not know how to translate your notes
into code, I would guess the beginning:


glPushMatrix ();

glLoadIndentity ();

glFloat mat[3];
mat[0]=at.x;
mat[1]=at.y;
mat[2]=at.z;
//at.x, at.y and at.z being the coordinates of my atom

glMultMatrixf (mat); 


// with 'rad' the radius of the atom:
glTranslatef (0, 0, 1.1*rad);

str = get_the_label_for_atom_k ();
 
render_string (str);
glPopMatrix ();


Does any of this make sens ?

I thought that you could maybe pin-point me towards an appropriate example ?

Again thank you for your help.

S.

Hmm, I’m not that fluent with the fixed function pipeline commands any longer, you could try to search for “billboard” to find examples on the net?

I figured it out … I searched the web as you told me first, looking for information on “billboard”.
That was not so clear at first until I understand that I was already using this procedure, to always
the atomic label in front of the camera:


glTranslated (at.x, at.y, at.z);
glRotated (-cameraAngleY, 0, 1, 0); // Heading back ...
glRotated (-cameraAngleX, 1, 0, 0); // and pitching back and so that labels orbit around atoms.

the problem was in the rescaling that should be used after the rotation to size properly the texture.
Then I found out that there are two choices, the first would be to skip the part of the code where I change
the projection matrix, and then simply apply a glrescale*, however the rescaling vector is trick to calculate
and anyway the result is not as clean as the one obtain using the second method which consist in changing
the call to glOrtho:


glMatrixMode (GL_PROJECTION);

glPushMatrix ();   // Push-2

glLoadIdentity ();
glOrtho (0.0, viewp[2], 0.0, viewp[3], 0.0, 1.0);

glMatrixMode (GL_MODELVIEW);

glPushMatrix ();   // Pop-3

glLoadIdentity ();

glTranslated (winx, winy, -winz);

And then everything works just fine !