# Making Points Look Good, and Shadows

CS 480 Lecture, Dr. Lawlor

First off, OpenGL draws GL_POINTs as ugly boxes by default.  You can make your points at least look round with:
`    glEnable(GL_POINT_SMOOTH);`
Second, points are a fixed size, specified in pixels with:
`    glPointSize(pixelsAcross);`
This is pretty silly, because in 3D the number of pixels covered by an object should depend strongly on distance (far away: only a few pixels; up close: many pixels).

Worse yet, you can't call glPointSize during a glBegin/glEnd geometry batch.  This means even if you did compute the right distance-dependent point size, you couldn't tell OpenGL about it without doing a zillion performance-sapping glBegin/glEnd batches.

Luckily, you can compute point sizes right on the graphics card pretty darn easily, like this:
`	/* Make gl_PointSize work from GLSL */        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);		static GLhandleARB simplePoint=makeProgramObject(	"void main(void) { /* vertex shader: project vertices onscreen */\n"	"	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"	"	gl_PointSize = 3.0/gl_Position.w;\n"	"}\n"	,	"void main(void) { /* fragment shader: find pixel colors */\n"	"	gl_FragColor = vec4(1,1,0,1); /* silly yellow */ \n"	"}\n"	);	glUseProgramObjectARB(simplePoint); /* points will now draw as above */`
(This uses my ogl/glsl.h functions to compile the GLSL code using OpenGL calls.)

This scales points by a hardcoded constant, here 3.0, divided by the "W" coordinate in the projection matrix.  Because we project 3D points onto the 2D screen by dividing by W, it make sense to divide the point's size by W as well.

Another more rigorous approach is to figure out the point's apparent angular size in radians, then scale radians to pixels by multiplying by the window height (in pixels) and dividing by the window field of view (radians).  A point of radius r has angular size asin(r/d) when viewed from a distance d, so:
`	float d=length(camera-vec3(gl_Vertex));	float angle=asin(r/d);	gl_PointSize = angle*glutGet(GLUT_WINDOW_HEIGHT)/fov_rad;`
Of course, we need to pass in the camera location via a glUniform, and similarly compute the conversion factor between radians and pixels in C++ and pass that into GLSL.
`	glUniform3fv(glGetUniformLocation(simplePoint,"camera"),1,camera);	glUniform1f(glGetUniformLocation(simplePoint,"angle2pixels"),		glutGet(GLUT_WINDOW_HEIGHT)/fov_rad);`
In practice, this GPU point scaling is extremely fast, and looks pretty nice!

`	/* Smooth shadow edges using GL Point Sprites            (magically makes texcoords appear in fragment program)         */        glEnable(GL_POINT_SPRITE_ARB);        glTexEnvi(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE_ARB,GL_TRUE);`
`	"void main(void) { /* fragment shader */\n"	"	vec2 center=vec2(gl_TexCoord)-vec2(0.5);\n"	"	float cendist=1.0-length(center)*2.0;\n"	"	gl_FragColor = vec4(0,0,0,clamp(cendist,0.0,1.0));\n"	"}\n"`