• 10
• 12
• 12
• 14
• 15

using directly gluLookAt instead of glScalef

This topic is 911 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hello,

I have a 3D animation where I draw a set of particles. Before launching the animation, I initialize the view of the particles set (the set represents a galaxy) in order to give to the user a good starting full view.

I have commented the drawing function used :
w_width = 600;
w_height = 600;
g_nearPlane = 0.1f;
g_farPlane = 1000.0f;

void GLWidget::draw()
{

// Boolean for initializing the first display of the scene
if (isDisplayFirst)
{
isDisplayFirst = false;

// Create VBO
createVBO();

// Reset line scale value
// lineScaleValue = abs(Galaxy->pos[3]-Galaxy->pos[0])*3;
lineScaleValue = 100.0f;

// Initialize View
glViewport(0, 0, w_width, w_height);

glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix

// perspective good initial
gluPerspective(45.0f, (float) w_width/w_height, g_nearPlane, g_farPlane);

glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrixi

// I would like to remove the two lines below and put directly
// gluLookAt (0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// This way, the camera would be put at z = 3 / 0.03 = 100

gluLookAt (0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glScalef(0.03f, 0.03f, 0.03f);

}

rotateScene();

glClearColor(0.0 ,0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_NV);

glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE);

glUseProgram(mprogram);
glUniform1f( glGetUniformLocation(mprogram, "pointScale"),m_pointScale);

// Drawing particles
if (not hideClassicMatter)
{
GLuint vbo_disk = 0;

glBindBuffer(GL_ARRAY_BUFFER, vbo_disk);
glVertexPointer(4, GL_DOUBLE, 4*sizeof(double), Galaxy->pos);
glEnableClientState(GL_VERTEX_ARRAY);

glColor4f(1.0f, 1.0f, 1.0f, 0.2f);
glDrawArrays(GL_POINTS, 0, Galaxy->getNumParticles_disk());

glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
}

// Drawing particles
if (not hideDarkMatter)
{
GLuint vbo_halo = 0;

glBindBuffer(GL_ARRAY_BUFFER, vbo_halo);
glVertexPointer(4, GL_DOUBLE, 4*sizeof(double), &Galaxy->pos[4*Galaxy->getNumParticles_disk()]);
glEnableClientState(GL_VERTEX_ARRAY);

glColor4f(0.0f, 0.0f, 1.0f, 0.2f);
glDrawArrays(GL_POINTS, 0, Galaxy->getNumParticles_halo());

glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
}

glDisable(GL_BLEND);
glDisable(GL_POINT_SPRITE);
}


gluLookAt (0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glScalef(0.03f, 0.03f, 0.03f);


I would have :

gluLookAt (0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

But with this replacement, I have strange results, it seems that a lot of particles are hidden or have disappeared.

To illustrate this, I show you on the two figures below this problem; The first one corresponds to the original code (using gluLookAt (0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glScalef(0.03f, 0.03f, 0.03f):

The second one corresponds to the replacement case ( using only gluLookAt (0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)) :

As you can see, a lot of particles seem to have disappeared.

Maybe the problem is about a wrong near or far values but I have set :

g_nearPlane = 0.1f;
g_farPlane = 1000.0f;

From your experience, What this issue is related to ?

Thanks

Share on other sites

Lots of things to understand here.  Understand the terms model, view and modelview  matrices.

glScalef() is applied in the model matrix. It happens on a model/object. You are directly scaling 3d vectors in the world.

View is how you see the model after it has been scaled etc.

The final 3d vector that is computed goes through the modelviewmatrix and then is projected on the screen.

*So, if you call glLoadIdentity(), and draw your spiral without scale or translation, you can place your camera ANYWHERE relative to that.

***So to answer your question "using directly glulookat instead of glscalef*** makes no sense. Please understand that before continuing. The camera matrix (gluLookAt) should ALWAYS be the same applied to every object in your 3D world. The camera doesn't change positions based on what object is being drawn.

So your issue is with something else. I don't see anything wrong. I would debug this by first making the cameraZ position be changeable at run-time. When you press a button, increase the camera z position by like .01. Does the object get further away? Can you see what is happening when you do this?

Share on other sites

i think you should tweak GL_POINT_SPRITE size to some bigger dimension (try multiplying actual point size by 30.0)

Edited by WiredCat

Share on other sites

Thanks for your remarks, I think where the issue comes from :

I have in the source code above (GLWidget.cpp) :

extern const char *vertexShader;

GLWidget::GLWidget(QWidget *parent) : QGLWidget(parent)
{
m_pointScale = 100.0f;
w_width = 600;
w_height = 600;
g_nearPlane = 0.1f;
g_farPlane = 1000.0f;

...

}

void GLWidget::draw()
{

// Boolean for initializing the first display of the scene
if (isDisplayFirst)
{
isDisplayFirst = false;

// Create VBO
createVBO();

// Reset line scale value
// lineScaleValue = abs(Galaxy->pos[3]-Galaxy->pos[0])*3;
lineScaleValue = 100.0f;

// Initialize View
glViewport(0, 0, w_width, w_height);

glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix

// perspective good initial
gluPerspective(45.0f, (float) w_width/w_height, g_nearPlane, g_farPlane);

glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrixi

// I would like to remove the two lines below and put directly
// gluLookAt (0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// This way, the camera would be put at z = 3 / 0.03 = 100

gluLookAt (0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glScalef(0.03f, 0.03f, 0.03f);

}

rotateScene();

glClearColor(0.0 ,0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_NV);

glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE);

glUseProgram(mprogram);
glUniform1f( glGetUniformLocation(mprogram, "pointScale"),m_pointScale);

// Drawing particles
...
// see the following into above code snippet

}

void GLWidget::initializeGL()
{
glClearColor(0.0 ,0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE);
}

with

vertexShader

#define STRINGIFY(A) #A

uniform float pointRadius;  // point size in world space
uniform float pointScale;   // scale to calculate size in pixels
void main()
{
// calculate window-space point size
vec3 posEye = vec3(gl_ModelViewMatrix * vec4(gl_Vertex.xyz, 1.0));
float dist = length(posEye);
gl_PointSize = pointRadius * (pointScale / dist);

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);

gl_FrontColor = gl_Color;
}
);



If I replace

gl_PointSize = pointRadius * (pointScale / dist);

by

gl_PointSize = 20.0

then the particles are displayed but their size doesn't increase when I zoom the scene.

Could you explain how to keep the original formula (gl_PointSize = pointRadius * (pointScale / dist);) and in the same time having scaling when zooming ?

it seems that variable

float dist = length(posEye);

is too high in this formula, so the size of the particles are too small to be visible.

How to circumvent this issue knowing I have the following values for particle radius and pointScale :

m_particleRadius = 0.6f;
m_pointScale = 100.0f;


Thanks

Share on other sites

Interesting problem that I've never thought of. I still just use quads.

I did a quick search. I think the best way to do this:

1.) Look at the position of the particle system as a whole.

2.) Given a real-life/world size of a single particle at that location. You know what size ALL particles should project to (in screen space).
->Take a point/quad with some distance relative to the camera. Run it through the projection matrix. This will give you how big the particle is rendered.

I think what this is effectively changing is your pointRadius variable. You will have to send this as a uniform to your shader. The zooming is controlled by chaning the FOV in gluPerspective, so any change to the FOV, changes how big things are rendered and you must recompute the size.