textured point sprites using vertex and fragment programs


while playing a little bit with point sprites I found a simple way to texture points using vertex and fragment programs (should be interesting especially for the Radeon people without a point sprite extension )
I thought somebody might find it useful, so here it is:

Actually the vertex program calculates the points distance attenuation and the window space position of the lower left corner of the point. Then this value is passed to the fragment program. With the fragment position and the lower left corners position its quite simple to get the texture coordinate and to sample the texture.

vertex program setup:

GLfloat viewport[4];
GLfloat viewport_scale[4] = {0.0f,0.0f,0.0f,0.0f};
GLfloat viewport_offset[4]= {0.0f,0.0f,0.0f,0.0f};


viewport_scale[0] = viewport[2] / 2.0f;
viewport_scale[1] = viewport[3] / 2.0f;

viewport_offset[0] = viewport[0] + viewport[2] / 2.0f;
viewport_offset[1] = viewport[1] + viewport[3] / 2.0f;

the vertex program

ATTRIB pos = vertex.position;

PARAM mvp[4] = { state.matrix.mvp } ;
PARAM mv[4] = { state.matrix.modelview } ;
PARAM pSize = state.point.size;
PARAM pAtt = state.point.attenuation;

PARAM vp_scale = program.local[0];
PARAM vp_offset= program.local[1];

PARAM eye= { 0.0, 0.0, 0.0, 1.0};

TEMP dist;
TEMP dist_sqr;
TEMP transformed;
TEMP finalsize;

MOV finalsize,{ 0,0,0,0 };

vertex in eye space

DP4 transformed.x, mv[0], pos;
DP4 transformed.y, mv[1], pos;
DP4 transformed.z, mv[2], pos;
DP4 transformed.w, mv[3], pos;

distance to eye ( 0,0,0,1)

SUB dist_sqr, transformed, eye;
DP3 dist_sqr, dist_sqr, dist_sqr;
RSQ dist, dist_sqr.w;
RCP dist, dist.w;

calc attenuation

pointsize = size * sqrt( 1/ ( a+ bd + cd^2))

MAD finalsize, pAtt.y, dist, pAtt.x;
MAD finalsize, pAtt.z, dist_sqr, finalsize;
RSQ finalsize.w, finalsize.w;

MUL finalsize.w,pSize.x, finalsize.w;

clamp and out

MAX finalsize.w, pSize.y,finalsize.w;
MIN finalsize.w,pSize.z,finalsize.w;
MOV result.pointsize, finalsize.w;

MOV result.color, vertex.color;

1 / pointsize for fp

RCP result.texcoord[1].x, finalsize.w;

project vertex

DP4 transformed.x, mvp[0], pos;
DP4 transformed.y, mvp[1], pos;
DP4 transformed.z, mvp[2], pos;
DP4 transformed.w, mvp[3], pos;
MOV result.position, transformed;

homogenous divide

RCP transformed.w, transformed.w;
MUL transformed.xyz,transformed, transformed.w;

viewport transformation

MAD transformed, transformed, vp_scale, vp_offset;

left bottom corner of point, offset center by {-pointsize/2,-pointsize/2}

MUL finalsize.w, finalsize.w, {0.5,0.5,0.5,0.5};
SUB result.texcoord, transformed,finalsize.w;

the fragment porgram


ATTRIB point_origin = fragment.texcoord[0];
ATTRIB one_over_point_size = fragment.texcoord[1];
ATTRIB pos = fragment.position;

TEMP texcoord;

dinstance to lower left corner

SUB texcoord, pos, point_origin;

normalize s,t texturcoordinates [0, pointsize] --> [0,1]

MUL texcoord, texcoord,one_over_point_size.x;

1-texcoord.y , so results are the same as NV_point_sprite

SUB texcoord.y,{1.0,1.0,1.0,1.0},texcoord;

TEX result.color, texcoord, texture[0], 2D;


If you see ways to improve (apart from usage of less vp/fp temporaries…) or have other ideas, please feel free to tell


what a cute piece of code! never seen it before, must have missed it