Fixed size (can't find a better name...)

Hi there…

As usual, I am working on my Modeller/Viewer…

I am having troubles trying to reproduce one of the features of 3DSMax R3.

You know, those lights that you always see even when you zoom out…

Whatever you do, they always have the same size on the screen… Does anyone know how to reproduce that ?

I guess I have to glScalef before rendering my lights (I render them as spheres…) but I can’t seem to find the values to pass to glScalef.

Any help would be welcome…

Eric

Ok. So you want to rendr a scene, and you want to scale everything but the lights. There is where you can use the wonderful matrix stack: define the scene transform matrix, push it, define another matrix for the lights without the ‘scale it’ reference, and when you need the scene transforms again pop it. It should do the job.

No, that’s not exactly what I want to do !

I have a 3D World viewed in Perspective. I can freely walk in this world. What I want is that some specific objects keep the same size wherever the viewer is (I don’t want them to be affected by the perspective).

Well, I have found a solution but I wonder how 3DSMaxR3 does it…

I’ll explain a little…

In my program, I have got a tree with all the objects.

Basically, I render a scene with calling :

RootEntity.Render();

Which in turns will render everything…

For each object, I use :

glPushMatrix();
SETPOSITION();
glPopMatrix();

I have got several objects all derived from a class called C_M3D_Entity which contains all positional stuff… The Render() member is virtual.

For my specific objects mentioned above, I have added this code to the Render function (which is called after SETPOSITION !) :

GLfloat Matrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX,Matrix);
HGL_Vector3Df V(Matrix[12],Matrix[13],Matrix[14]);
float N=V.Norm();
float d=1+N/5000;
glScalef(d,d,d);

And it works pretty well…

For those who wonder what the hell an HGL_Vector3Df is, it’s just one of the objects available in my library (HeavenGL… Stupid name, I know but I am a coder, not a writer !).

So basically, for those objects, I retrieve the distance that separate them from the viewer (N in the code) and I scale of a number d=1+N/5000 (the 5000 is totally arbitrary : it depends on the size I want for the objects)…

Well, that was a bit long but now I’d be interested in some comments on this method ! (and not on the name of the library, please ! )

See ya.

Eric

Arf’ I am stupid…

The code you should read at the beginning is :

glPushMatrix();
SETPOSITION();
Render();
glPopMatrix();

Eric

Why don’t you just manually project the light source’s position to get the image coordinate, switch to ortho projection and render the sphere? I mean, your method works, but this is just another idea. :wink:

I agree. Just push an orthographic matrix on the projection stack, render the spheres, then pop it off and use the perspective projection for everything else. Or are we missing something…?

Hi guys !

I would like to do that and I can not see any reason why it should not work… except that I really don’t know what parameters to pass to my glOrtho function !

Any hints about that ???

Eric

I’m not quite sure about this, but…wouldn’t you just use the same near/far clipping planes as for the perspective transformation, as well as the top, bottom, left, right values of your near clipping plane? (perhaps that’s far instead…I’m not sure). I believe this will keep the correct values for z-buffering and all other clipping.

Howdy,

well, it depends. :wink: if you want an integer value in your vertex calls to map to a pixel in the frame buffer, then you’d use something like:

top=left=0;
right=width_of_screen_in_pixels;
bottom=height_of_screen_in_pixels;

now, if you do something like

glVertex2i(5, 5);

you’re now talking about the pixel 5,5. of course, sometimes this isn’t all very useful; i’ve frequently used ortho projection to a unit square, because it’s easier (in some cases) to think like that. but. eh. in this context mapping integer values to pixels will be your best bet.

hope this helps,
John

Y have the same problem, Eric, in my dev project, I need to provide this feature.
I think it is interesting to wach for a generic method. My problem is near :

  • Y want to draw a small quad with an icon to materialize my lights (and other things)
  • Y want that it was localized in 3d space, with z-buffering, so I need compute the quad size for a fixed size on screen taking care of Z coord
  • Y want it run both in pers and ortho mode

Here the method I will do : you need to manipulate matrices. In matrix multiplication stack you have, in order :
inversed_camera_matrix -> object matrix
(inversed_camera_matrix = the matrix to make all objects moing around the camera)
You must transform the position of the light with the inversed_camera_matrix, to obtain the light position in camera space. Now, with this new coords, you can do :
glLoadIdentity();
… draw a quad at position of the light …
The quad will be all time aligned with the z=0 plane.
Next, you have to find the size in wich you must draw the quad. This is a function of Z object coordinate. You must apply the well know projection functions in perspectiv or in orthographic mode (focal at infinit Z coord).
To optain a constant size on screen, you have to multiply the size you want by the ratio of the size of the window and the size of the frustrum in Z=0.
Well, it’s easier to explain than to do !
I am coding a layer over OGL that will provide such features.

Regards,

Gaby

Gaby,

Thanks for the hint !

But this thread was started on 26/04/2000 and I have found a solution since then !

What I do is:

  1. Translate the object to its position using glTranslate.
  2. Use a custom function called HGL_No_Scale(float D) that is as follows:

void HGL_No_Scale(double dDim)
{

GLdouble dRealProjectionMatrix[16];
GLint iRenderMode;
glGetIntegerv(GL_RENDER_MODE,&iRenderMode);
if (iRenderMode==GL_SELECT)
{
glGetDoublev(GL_PROJECTION_MATRIX,dRealProjectionMatrix);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
GLdouble dModelViewMatrix[16],dProjectionMatrix[16];
GLint iViewPort[4];
glGetDoublev(GL_MODELVIEW_MATRIX,dModelViewMatrix);
glGetDoublev(GL_PROJECTION_MATRIX,dProjectionMatrix);
glGetIntegerv(GL_VIEWPORT,iViewPort);
GLdouble dObjX1,dObjY1,dObjZ1;
GLdouble dObjX2,dObjY2,dObjZ2;
GLdouble WinX1,WinY1,WinZ1;
GLdouble WinX2,WinY2,WinZ2;
gluUnProject(0,0,0,dModelViewMatrix,dProjectionMatrix,iViewPort,&dObjX1,&dObjY1,&dObjZ1);
gluUnProject(1,0,0,dModelViewMatrix,dProjectionMatrix,iViewPort,&dObjX2,&dObjY2,&dObjZ2);
C_Vector3Dd vObjVector(dObjX2-dObjX1,dObjY2-dObjY1,dObjZ2-dObjZ1);
vObjVector.Normalize();
gluProject(0,0,0,dModelViewMatrix,dProjectionMatrix,iViewPort,&WinX1,&WinY1,&WinZ1);
gluProject(vObjVector.U,vObjVector.V,vObjVector.W,dModelViewMatrix,dProjectionMatrix,iViewPort,&WinX2,&WinY2,&WinZ2);
double dRef=sqrt((WinX2-WinX1)(WinX2-WinX1)+(WinY2-WinY1)(WinY2-WinY1));
double fFactor=dDim/dRef;
glScalef(fFactor,fFactor,fFactor);
if (iRenderMode==GL_SELECT)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadMatrixd(dRealProjectionMatrix);
glMatrixMode(GL_MODELVIEW);
}

}

You obviously need to call this function for each object. If you pass the same dDim parameter to the function, all the objects will be the same size on the screen (whatever their depth is). BTW, dDim depends on the window’s size. In my program, I calculate it as:

double dDim=(float) min(pGLParameters->m_iWidth,pGLParameters->m_iHeight)/5;

Which makes my arrows (this snippet is taken from the RenderAxes function which renders axes similar to the 3DS ones when you select an object) a fifth of the min dimension (i.e. width or height).

Now, I have just reread the code and I am sure you can get rid of the 2 gluUnproject and 2 gluProject functions by directly fiddling with the matrices (that’s probably where you talk about well-known projection functions).

I’ll have to have a look at that !

Regards.

Eric

P.S.: how did you come accross this very old thread ???