PDA

View Full Version : Specular reflection not OK



Simon666
03-10-2003, 08:26 AM
Hello everybody,

For a long time I have asked myself questions about this. Take for instance the code below. It will draw a sphere with a certain lighting. This light is directional light and coming from the negative Y-Axis : GLfloat position[] = {0.0f,-1.0f,0.0f,0.0f};

Yet, and here is the problem: the specular lighting does not seem in order. It is shown as being fixed on a certain spot, and does NOT change when you move the camera around. This is nowhere near what you would expect as reflection.

Can anybody tell me where the problem is located and how to solve this?



void CNewRightView: http://www.opengl.org/discussion_boards/ubb/biggrin.gifrawSphereWithGlut()
{

GLfloat ambient[] = {0.6f, 0.6f,0.7f,1.0f};
GLfloat diffuse[] = {0.7f, 0.7f,0.7f,1.0f};
GLfloat position[] = {0.0f,-1.0f,0.0f,0.0f};
GLfloat spec[] = {1.0f, 1.0f,1.0f,1.0f};
GLfloat specma[] = {0.3f, 0.3f,0.3f,1.0f};

glShadeModel(GL_SMOOTH); // Smooth rendering
glFrontFace(GL_CCW); // Counter clock-wise polygons face out

glEnable(GL_DEPTH_TEST); // Hidden surface removal
glEnable(GL_LIGHTING); // Enable lighting

glLightfv(GL_LIGHT1,GL_POSITION,position); // Setup and enable light 0
glLightfv(GL_LIGHT1,GL_AMBIENT,ambient);
glLightfv(GL_LIGHT1,GL_DIFFUSE,diffuse);
glLightfv(GL_LIGHT1,GL_SPECULAR,spec);
glEnable(GL_LIGHT1);

glEnable(GL_COLOR_MATERIAL); // Set Material properties to follow glColor values
glMaterialfv(GL_FRONT,GL_SPECULAR,specma);
glMateriali(GL_FRONT,GL_SHININESS,128);

glColor3d(0.5,0.5,0.5);

glutSolidSphere(0.05,50,50);

glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT1);
}

[This message has been edited by Simon666 (edited 03-12-2003).]

Deiussum
03-10-2003, 09:47 AM
That code doesn't show where you "move the camera around."

If you are doing so in the GL_PROJECTION matrix, you shouldn't be. That should only be used for setting up the shape of the viewing volume. (e.g. gluPerspective, glOrtho, etc.)

When you set the GL_POSITION of a light, it takes the MODELVIEW matrix into account, so it also makes a difference where you call that at.

Simon666
03-10-2003, 11:12 PM
Hello,

First of all, thanks for replying. The camera is set in the CCamera class. I use glRotated and glTranslated to view the scene from the desired angle.

vincoof
03-10-2003, 11:33 PM
If you just "move" the camera you shouldn't notice any difference.
If you "rotate" the camera, there should be a little difference, at least as long as the MODELVIEW matrix is the current matrix.

Simon666
03-11-2003, 12:05 AM
Originally posted by vincoof:
If you just "move" the camera you shouldn't notice any difference.
If you "rotate" the camera, there should be a little difference, at least as long as the MODELVIEW matrix is the current matrix.
Could you tell me what this means, and what I would need to change? I currently don't understand what you mean? http://www.opengl.org/discussion_boards/ubb/frown.gif

vincoof
03-11-2003, 03:01 AM
Translation only does not change the specular highlight (except in local viewer mode or with point light). If the light is directional, and if the viewer is considered at an infinite distance (it is the default state of OpenGL) then calling glTranslate has no effect on the specular contribution.

But if you call glRotate with a non-nul angle, then the specular highlight might move and seems to "float" around the object.

Simon666
03-11-2003, 03:16 AM
Originally posted by vincoof:
Translation only does not change the specular highlight (except in local viewer mode or with point light). If the light is directional, and if the viewer is considered at an infinite distance (it is the default state of OpenGL) then calling glTranslate has no effect on the specular contribution.

But if you call glRotate with a non-nul angle, then the specular highlight might move and seems to "float" around the object.
OK, I call glRotate with an angle different from zero in my CCamera class, but how would I solve this problem then?

vincoof
03-11-2003, 03:52 AM
It does not really solve the problem. It could explain why you thought there was a problem when in fact there wasn't. It's natural to think that the specular highlight floats, but the simple translation does not give the feeling of floating, so it's a common mistake to think that the specular is wrong when in fact it's ok. But if you call glRotate then obviously there is a problem.

Could you post screenshots showing the problem ?

Simon666
03-11-2003, 04:22 AM
Originally posted by vincoof:
Could you post screenshots showing the problem ?[/B]
Here is a picture showing the problem. I use positional light coming from the negative Y direction. Yet nomatter under what angle I look at the scene, the reflected spot on the sphere stays at the same place, which can be found by drawing a line from the center in the direction (0,-1/sqrt(2),1(sqrt(2))), or so it seems. Note that the diffuse reflection is OK and shows clearly that the directional light is coming from the negative Y-axis.

GLfloat position[] = {0.0f,-1.0f,0.0f,0.0f};
glLightfv(GL_LIGHT0,GL_POSITION,position);

http://allserv.rug.ac.be/~skdmeule/Problem.bmp

[This message has been edited by Simon666 (edited 03-11-2003).]

vincoof
03-11-2003, 05:50 AM
I'm sorry but the image looks correct. Perhaps you could setup online an executable of this sample program ?

vincoof
03-11-2003, 06:45 AM
Thanks for the program. Now I really see what you mean.
The most possible explanation is that you work with projection matrix instead of modelview matrix.
Do you call glMatrixMode(GL_MODELVIEW) in your code ?

Also, have you tried to call glGetError ?

Simon666
03-11-2003, 07:30 AM
Do you call glMatrixMode(GL_MODELVIEW) in your code ?
Yes, on several places. If I understand it correctly, it is necessary for perspective view?

Also, have you tried to call glGetError ?
I've never even heard of this, so no. What is it used for and how does one use it?

vincoof
03-11-2003, 08:10 AM
Generally, when you setup your projection matrix you may call something like that (typically when the window is resized) :
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum or gluPerspective
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();


glGetError is used to get errors from the GL
it is a function that returns an int (an enumerant) which corresponds to first error ever encountered since the last call to glGetError.
If glGetError returns GL_NO_ERROR, it means that no problem was detected by the GL (it does not ensure that 100% of the problems are checked, but a majority of them). If not GL_NO_ERROR it can be something like GL_INVALID_ENUM or GL_INVALID_VALUE ... if so, you'd better look at the place where the error occurs.

[This message has been edited by vincoof (edited 03-11-2003).]

Simon666
03-11-2003, 08:33 AM
I will try it once. If you look at my code, you can see that for perspective it goes pretty much like this:

void CCamera::Set()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

if (SpecialView==true)
{
// Stuff for top, bottom, left, right, front and back view
}
else
{
if ((AutoRotate==1)&&(abs(RelevantChange)==2))
{
Normal_Azim+=AutoRotateAmount;
}

// Ensure azimuth, elevation and twist are between -180 and 180 degrees

gluPerspective( Focus , Ratio , Maximum2( Distance/100, Distance - 10 ), Distance + 10 );
glTranslated( 0, 0, -Distance );

glRotated( Normal_Twist ,0,0,1);
glRotated(-90+Normal_Elev ,1,0,0);
glRotated(-90-Normal_Azim ,0,0,1);
}

glTranslated(-Target.GetX(),-Target.GetY(),-Target.GetZ());

glMatrixMode( GL_MODELVIEW );

glPushMatrix();
}


void CCamera::Reset()
{
glTranslated( Target.GetX(), Target.GetY(), Target.GetZ());

if (SpecialView==true)
{
// Stuff for top, bottom, left, right, front and back view
}
else
{
glRotated(90+Normal_Azim ,0,0,1);
glRotated(90-Normal_Elev ,1,0,0);
glRotated(-Normal_Twist ,0,0,1);

glTranslated( 0, 0, Distance );
}

glPopMatrix();
}

The camera is set by several rotations, characterised by a viewing direction specified by an azimuth, elevation and twist. This observer is looking in this direction at a certain Target, characterized by x,y and z coordinates and by a certain distance of the observer from the target.

This is how I set my camera, this happens in the OnDraw function of my view. The rendering of the scene is done between these functions:

// Basic scheme of OnDraw (simplified)

C***View::OnDraw(CDC* pDC)
{
pDoc->Camera.Set();

// Render scene

pDoc->Camera.Reset();
}

[This message has been edited by Simon666 (edited 03-11-2003).]

vincoof
03-11-2003, 08:42 AM
call your camera settings inside the modelview state.
You're doing :

glMatrixMode(GL_PROJECTION);
frustum stuff
rotate and translate according to camera position and orientation
glMatrixMode(GL_MODELVIEW);

but you should do :
glMatrixMode(GL_PROJECTION);
frustum stuff
glMatrixMode(GL_MODELVIEW);
rotate and translate according to camera position and orientation

and perhaps you should call glLoadIdentity just after glMatrixMode(GL_MODELVIEW)

Simon666
03-11-2003, 09:41 AM
Well, I've simplified my function to set the camera and this is how they look now:

void CCamera::Set()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

gluPerspective( Focus , Ratio , Maximum2( Distance/100, Distance - 10 ), Distance + 10 );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

glTranslated( 0, 0, -Distance );

glRotated( Normal_Twist ,0,0,1);
glRotated(-90+Normal_Elev ,1,0,0);
glRotated(-90-Normal_Azim ,0,0,1);

glTranslated(-Target.GetX(),-Target.GetY(),-Target.GetZ());
}

void CCamera::Reset()
{
glTranslated( Target.GetX(), Target.GetY(), Target.GetZ());

glRotated(90+Normal_Azim ,0,0,1);
glRotated(90-Normal_Elev ,1,0,0);
glRotated(-Normal_Twist ,0,0,1);

glTranslated( 0, 0, Distance );
}

Yet the result is still the same. Do I need to set the light position somewhere in between these lines?

vincoof
03-11-2003, 10:14 AM
Results are the same ? That is really hard to believe ...

Could you please post the new executable ?

vincoof
03-12-2003, 02:02 AM
ah, but this is prefectly correct !
If that's not the behaviour you wanted, then I don't know know what you want http://www.opengl.org/discussion_boards/ubb/smile.gif

Simon666
03-12-2003, 04:55 AM
Originally posted by vincoof:
ah, but this is prefectly correct !
If that's not the behaviour you wanted, then I don't know know what you want http://www.opengl.org/discussion_boards/ubb/smile.gif
No it isn't. The behaviour has still not changed since the previous time I posted the exe, unless you see something else than I do (You never know-I have a crappy graphics card at work). The behaviour is also physically incorrect.

[This message has been edited by Simon666 (edited 03-12-2003).]

Deiussum
03-12-2003, 05:34 AM
It looks right to me too. Unless you don't want the light to move with the scene. If that is the case, you should set the glLight params after the transformations you do for each sphere.

[This message has been edited by Deiussum (edited 03-12-2003).]

Simon666
03-12-2003, 05:50 AM
Originally posted by Deiussum:
It looks right to me too. Unless you don't want the light to move with the scene. If that is the case, you should set the glLight params after the transformations you do for each sphere.
Really??? What I see is that judging by the diffuse lighting on the sphere the directional light is coming from the negative Y-axis, and the reflected spot is always at the same spot, namely on the spot on the surface of the sphere obtained by drawing a line from the center in the direction (0,-1/sqrt(2),1/sqrt(2)). Is this reflected spot dependant of the viewpoint on your computers, as should be in physical reality? http://www.opengl.org/discussion_boards/ubb/confused.gif

acerb
03-12-2003, 05:51 AM
Hi,

May I ask which RAD/IDE do you use to program your application?

Thanks

Simon666
03-12-2003, 06:33 AM
May I ask which RAD/IDE do you use to program your application?
I'm not familiar with the terms RAD and IDE, I don't know what you mean, I guess I'm supposed to say I use Visual C++ 6.0 to program this on, on a Windows 2000 Pro computer. The link to the source code is in the first post of this thread.

JustHanging
03-12-2003, 06:52 AM
Hi,

I haven't tested your program, but how about setting GL_LIGHT_MODEL_LOCAL_VIEWER to true. You don't seem to do that (forgive me if I missed the line in your code), and I don't think it's enabled by default. You set it with a glLightModel call if I recall correctly.

-Ilkka

Simon666
03-12-2003, 07:22 AM
Originally posted by JustHanging:
Hi,

I haven't tested your program, but how about setting GL_LIGHT_MODEL_LOCAL_VIEWER to true. You don't seem to do that (forgive me if I missed the line in your code), and I don't think it's enabled by default. You set it with a glLightModel call if I recall correctly.

-Ilkka
Consider yourself lucky you're not around here, otherwise I could have kissed you from happiness. http://www.opengl.org/discussion_boards/ubb/biggrin.gif Thanks, it did the trick, I really appreciate it. http://www.opengl.org/discussion_boards/ubb/smile.gif


[This message has been edited by Simon666 (edited 03-12-2003).]

vincoof
03-12-2003, 10:35 AM
The result should *almost* not change, but if it does the trick then I see why you thought it was physically "incorrect".

Though, let me point out that this method is a bit slower, and in general in a complex scene the difference is almost inexistant. Maybe you can see the difference with your spheres but if your application is meant to manage complex scenes, maybe you'll prefer the other (fast) method. my last 2c

Simon666
03-13-2003, 01:37 AM
Originally posted by vincoof:
The result should *almost* not change, but if it does the trick then I see why you thought it was physically "incorrect".

Though, let me point out that this method is a bit slower, and in general in a complex scene the difference is almost inexistant. Maybe you can see the difference with your spheres but if your application is meant to manage complex scenes, maybe you'll prefer the other (fast) method. my last 2c
That doesn't matter much to me. I have to thank you too because your notes were crucial too. If I add the line glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,1); I had to change my functions for the camera indeed to:

void CCamera::Set()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

gluPerspective( Focus , Ratio , Maximum2( Distance/100, Distance - 10 ), Distance + 10 );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

glTranslated( 0, 0, -Distance );

glRotated( Normal_Twist ,0,0,1);
glRotated(-90+Normal_Elev ,1,0,0);
glRotated(-90-Normal_Azim ,0,0,1);

glTranslated(-Target.GetX(),-Target.GetY(),-Target.GetZ());
}

void CCamera::Reset()
{
glTranslated( Target.GetX(), Target.GetY(), Target.GetZ());

glRotated(90+Normal_Azim ,0,0,1);
glRotated(90-Normal_Elev ,1,0,0);
glRotated(-Normal_Twist ,0,0,1);

glTranslated( 0, 0, Distance );
}

But that is for perspective. I don't know what it should be for projection as I have special views (front,back,top,bottom,left,right). Using the code in the function below the specular reflection once again doesn't appear where it should be.

void CCamera::Set()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

double x1 =-Distance*Focus/75,
x2 = Distance*Focus/75,
y1 = x1/Ratio,
y2 = x2/Ratio;

glOrtho( x1, x2, y1, y2, -10, 10 );

glRotated( Special_Twist,0,0,1);
glRotated(-90+Special_Elev,1,0,0);
glRotated(-90-Special_Azim,0,0,1);

glTranslated(-Target.GetX(),-Target.GetY(),-Target.GetZ());
}

void CCamera::Reset()
{
glTranslated( Target.GetX(), Target.GetY(), Target.GetZ());

glRotated(90+Special_Azim ,0,0,1);
glRotated(90-Special_Elev ,1,0,0);
glRotated(-Special_Twist ,0,0,1);
}

Deiussum
03-13-2003, 05:26 AM
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

double x1 =-Distance*Focus/75,
x2 = Distance*Focus/75,
y1 = x1/Ratio,
y2 = x2/Ratio;


glOrtho( x1, x2, y1, y2, -10, 10 );

glRotated( Special_Twist,0,0,1);
glRotated(-90+Special_Elev,1,0,0);
glRotated(-90-Special_Azim,0,0,1);



A good general rule of thumb to follow is to never use glRotate, glTranslate, glScale or gluLookAt on the GL_PROJECTION matrix. It will mess up your lighting and fogging calculations, as those calculations only take the GL_MODELVIEW matrix into account.

Add
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

between your glOrtho and glRotated calls and you should be good.

Simon666
03-20-2003, 09:21 AM
Originally posted by Deiussum:
A good general rule of thumb to follow is to never use glRotate, glTranslate, glScale or gluLookAt on the GL_PROJECTION matrix. It will mess up your lighting and fogging calculations, as those calculations only take the GL_MODELVIEW matrix into account.

Add
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

between your glOrtho and glRotated calls and you should be good.
OK, I've done that, but the specular lighting just disappears then. The code I use for the camera is (simplified):

void CCamera::Set()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

double x1 =-Distance*Focus/75,
x2 = Distance*Focus/75,
y1 = x1/Ratio,
y2 = x2/Ratio;

glOrtho( x1, x2, y1, y2, -10, 10 );

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glRotated( Special_Twist ,0,0,1);
glRotated(-90+Special_Elev,1,0,0);
glRotated(-90-Special_Azim,0,0,1);


glTranslated(-Target.GetX(),-Target.GetY(),-Target.GetZ());

glPushMatrix();
}

void CCamera::Reset()
{
glTranslated( Target.GetX(), Target.GetY(), Target.GetZ());

glRotated(90+Special_Azim ,0,0,1);
glRotated(90-Special_Elev ,1,0,0);
glRotated(-Special_Twist ,0,0,1);

glPopMatrix();
}

You can check this in my exe at:
http://allserv.rug.ac.be/~skdmeule/DySiFil.exe

For the special views, press the 1,2,3,4,5 and/or 6 keys on your keyboard, use 7 to restore the original, perspective view.

The source is at:
http://allserv.rug.ac.be/~skdmeule/STLViewer.zip

Could you tell me why there are no specular reflections in case of projection instead of perspective?

[This message has been edited by Simon666 (edited 03-20-2003).]

vincoof
03-21-2003, 03:45 AM
I think this is the correct behaviour since in ortho the eye is in the center of the scene. I would expect the eye to be infinite then, so in ortho you should set LOCAL_VIEWER to FALSE but obviously you could restore it to true when switching to perspective

[This message has been edited by vincoof (edited 03-21-2003).]

dorbie
03-21-2003, 04:07 AM
You should clearly apply model and view transformations on the modelview stack, but you also need to position the light at the correct time when you have the appropriate matrix on the stack.

When you are transforming the view and expect the light to be in object space (the scenario you seem to require) you need to position the light after you have placed the viewing matrix on the modelview stack. You also need to do this EVERY TIME you change the viewing matrix, i.e. probably each frame in your application after the viewing transformation is placed on the modelview matrix.

The highlight remaining fixed is symptomatic of a light source in eye space and this is typical of lights positioned before the viewing matrix is on the stack, or not repositioned when the viewing matrix changes.

Your light seems to position itself in object space but if you're manipulating the wrong matrix for viewing it would throw off the position of the light which is only transformed through the modelview and held in eye space for the computation.

Structurally you may also want to position the light outside your low level object space drawing since you may want to support animated objects with lights in 'world' space.

So you want to apply the view matrix, position the light in the world, multiply the model matrix (for any object animations), then draw the object. All of this on the modelview matrix stack.


[This message has been edited by dorbie (edited 03-21-2003).]

Simon666
03-24-2003, 08:03 AM
Originally posted by vincoof:
I think this is the correct behaviour since in ortho the eye is in the center of the scene. I would expect the eye to be infinite then, so in ortho you should set LOCAL_VIEWER to FALSE but obviously you could restore it to true when switching to perspective
I tried using this but setting GL_LIGHT_MODEL_LOCAL_VIEWER but then specular reflection angles take the view direction to be parallel to and in the direction of the -z axis. This seems to not result in "correct" lighting, nor in the kind of lighting I desire. Could it be the problem with this GL_LIGHT_MODEL_LOCAL_VIEWER is that in case of projection the eye is on infinite which causes a problem?

I tried dorbie's suggestion also by setting the light position glLightfv(GL_LIGHT0,GL_POSITION,position); on various places in my camera setting function to no effect.




[This message has been edited by Simon666 (edited 03-24-2003).]

vincoof
03-24-2003, 01:08 PM
Originally posted by Simon666:

I tried using this but setting GL_LIGHT_MODEL_LOCAL_VIEWER but then specular reflection angles take the view direction to be parallel to and in the direction of the -z axis. This seems to not result in "correct" lighting, nor in the kind of lighting I desire. Could it be the problem with this GL_LIGHT_MODEL_LOCAL_VIEWER is that in case of projection the eye is on infinite which causes a problem?
After thinking of it I think it's right that the specular term also messes up in that case. Still, it is because the eye position is in the center of the fustum, but the problem is different that the distortion you're experiencing in perspective view when LIGHT_MODEL_LOCAL_VIEWER is FALSE.
If you want specular lighting, I think you should not set the eye in the center of the frustum. That is, instead of setting the near/far plane pair to [-10,+10] you should set it to eg [+10,+30] (and of course be careful that objects still lie in the field of view).



Originally posted by Simon666:

I tried dorbie's suggestion also by setting the light position glLightfv(GL_LIGHT0,GL_POSITION,position); on various places in my camera setting function to no effect.

I think that your light is positioned correctly. If you want to see where the light ends, you could render some kind of representation of the light direction.
For instance, before glEnable(GL_LIGHTING) :

glColor3f(1.f, 1.f, 0); // Yellow
glBegin(GL_LINES);
glVertex2f(0,0);
glVertex4fv(position);
glEnd();
glColor3f(1.f, 1.f, 1.f); // White, ie neutral
glEnable(GL_LIGHTING);
...

Simon666
03-28-2003, 04:36 AM
Originally posted by vincoof:
I think that your light is positioned correctly.
My light is positioned correctly, as can be seen by that fact that the diffuse lighting is drawed correctly: the sphere seems half lit by a light shining from the negative Y-direction. But I still have the problem that the specular reflection is drawed incorrect in case of projection (perspective was solved a couple of posts higher). Any suggestions?

vincoof
03-28-2003, 07:11 AM
Have you tried to render in the Z range [10,30] instead of [-10,+10], as "suggested" above ?

Simon666
03-31-2003, 12:02 AM
Originally posted by vincoof:
Have you tried to render in the Z range [10,30] instead of [-10,+10], as "suggested" above ?
I've tried [5,15], to have something not central. With [10,30] their is nothing to see as my scene has coordinates in the range of [-2,2].

vincoof
03-31-2003, 02:03 AM
Originally posted by Simon666:
With [10,30] their is nothing to see as my scene has coordinates in the range of [-2,2].
[/B]

Well then, translate your world !
In the camera setting, call eg glTranslate(0,0,-20)

Simon666
04-02-2003, 12:45 AM
Originally posted by vincoof:
Well then, translate your world !
In the camera setting, call eg glTranslate(0,0,-20)
It works!!! Great! Thanks! http://www.opengl.org/discussion_boards/ubb/smile.gif One last question: could you explain why this happens if the eye is in the center of the frustrum as you say?

vincoof
04-02-2003, 01:17 AM
When LIGHT_MODEL_LOCAL_VIEWER is TRUE, the specular contribution is computed from the eye-to-vertex vector. In orthographic view, the frustum is a cube and you should imagine that the resulting image is the projection of objects to the positive-z quad of the cube. In that case, if the eye is in the center of the cube, it is really weird to think that what we call an "eye" is inside what is being seen. It seems more natural that the eye is outside what is being seen, which would be the case if the viewinf frustum (the cube) was displaced or if LIGHT_MODEL_LOCAL_VIEWER was FALSE.

It's not easy to explain that with words. Some pictures would probably help but I hope you get the point.