101 Things to do in Vertex Shader :)

OK, I’m a newbie to Vertex Shaders, but I’m already amazed at what can be acheived in 128 instructions

I’ve looked through the Nvidia demos and source to get an idea of what can be done with them and started to think about my first attempt to write one. ideas…ideas…ideas… ah ha!

  1. Billboarding. How does this sound -

Pass your quad on as normal but them apply the transpose of the model view matrix.

he presto ?

Ideas 2 to 101 TBD

Never really thought about that… Sounds cool though! Nice and simple and fast!!

I think it would be a most excellent idea to draw a list up that people can contribute too, of what cool fast things you can do with a vertex shader.

Nutty

Vertex programs cannot create vertices, only modify vertices that you send down. Thus, you can’t create a billboard out of a single normal.

pass your quad as normal means:

pass your quad like you normally do but then applie in the shader the transpose of the 3x3 ( or how ever ) to get it billboarded…

cant wait to see it running, pocketmoon

what i like with the vertexshader is to set up the perpixellighingdata in hw, and sending the data there in as normal like before… great, too

i would prefer a new glBegin statement for billboards… perhaps you know it

glBegin( GL_POINT_SPRITE_NV );
{
glPointSize( 10.f );
glVertex3f( 10, 10, 10 );
}
glEnd( );

if not, look at dx8… would be so great… textured “pixels” ( huge pixelquads in fact… perfect for billboards… particlesystems etc… simply great )

Well that would be nice but a generic solution would perhaps be, well, too generic

I’m trying to billboard tree,what else!, onto a terrain, where else

If you unrotate by the whole model view matrix you just end up with the trees rotating in all planes! If you turn upside down the trees follow you!!

So for a flat terrain (y is up) you would only need to unrotate about the y axis perhaps ??

Even worse my terrain isn’t flat - it’s a sphere! So I only need to unrotate about the surface tangent hmmm I think I need to sleep on that one.

In fact - if anyone has a pointer on how to unrotate JUST around the surface tangent given the current mv matrix let me know!

Rob J.

I’m not to clear about what you’re trying to do. Are you trying to make a quad always face you?

> pass your quad like you normally do but
> then applie in the shader the transpose of
> the 3x3 ( or how ever ) to get it
> billboarded…

You also cannot do that, because a vertex program cannot see vertex data for other vertices, only for the current vertex. Unless you calculated and sent down the correct rotation matrix as constant data, but that would sort-of miss the point I think :slight_smile:

Originally posted by jwatte:
You also cannot do that, because a vertex program cannot see vertex data for other vertices, only for the current vertex. Unless you calculated and sent down the correct rotation matrix as constant data, but that would sort-of miss the point I think :slight_smile:

Seems to me like it might be possible (not that I’ve tried it or ever even thought about it before now). You could probably pass in the camera position and/or view vector as a contant values, and pass in the quad center as a per-vertex attribute. Although to do the rotation, dont you need to do an inverse cosine or sine? (Im too tired right now to remember). That may be difficult/imposible to calculate in a vertex shader, although you might be able to encode a lookup table in the constant registers.

Overall, I think you could probably hack through it somehow, but it might consume a sizable portion of the constants and instructions. However, if you arent doing any fancy effects on the quad (which I usually dont with billboards) you might be able to get away with this.

hm… it could be possible… but just with huge data overflow ( like sending all 4 vertices 4 times and other stuff, too )… i’m not sure, but it could possibly be done… be creative and you will find a way…

i would prefer the point_sprites… why? cause even the trees of 3dmark2k1 are done like this… yeah… look at it carefully and you see that the leavegroups are billboards… and its so damn simple to render a billboard with pointsprites… nvidia, put this in your next driver and i’ll be very happy ( means i possibly buy something i would not yet do )

letz see…

hm… btw… how bout this

you give this

for( int i = 0; i < 4; i ++ )
{
glVertexAttrib( 1, shift[ i ] );
glVertex( billboardcenter );
}

the program is simple:

!!VP1.0
PROJECT_TO_SCREEN( R0, V0 );
OUT = R0 + V1;

this should work… simply project the center of your billboard onto screen, then create there a quad ( or whatever you want ) around this point… zdivision is after, so the size should be autoscaled, too…

true?false?

but anyways… its much data overhead…

[This message has been edited by davepermen (edited 05-26-2001).]

> Overall, I think you could probably hack
> through it somehow, but it might consume a
> sizable portion of the constants and
> instructions. However, if you arent doing
> any fancy effects on the quad (which I
> usually dont with billboards) you might be
> able to get away with this.

The point is that the host CPU set-up cost for doing it is as much, or more, than it would be to just properly calculate the billboard quad vertices in the first place. So even if you “can” do it, why would you want to?

Sort of like matrix skinning. Sure, there’s space for like 20 bones in the constant pool, but who works with a skeleton that only uses 20 bones these days? Meanwhile, the call overhead per buffer is fairly huge compared to the render cost per triangle, so a properly tuned software skinner dumping all verts into AGP memory and rendering as one buffer is still the fastest way to go.

Good idea pocketmoon! I’ve always been annoyed that I had to send the vertices for my billboards in immediate mode, due to the need to fix their rotations each frame.

Not to put down all the naysayers in this thread (you know who you are), but here is the vertex program that will accomplish billboarding without sending any extra per-vertex information. It only took me about a half hour to write this up…vertex programs rule.

Just send in your vertices as quads (or whatever shape you want) in the z = 0 plane.

I have tested it and it works great. The only shortcoming is that it doesn’t adjust for perspective. EXTREMELY fast due to the tiny size of the program .

    
"!!VP1.0" 
// Apply inverse modelview rotation to all vertices
"DP3 R0.x, v[OPOS], c[0];"
"DP3 R0.y, v[OPOS], c[1];"
"DP3 R0.z, v[OPOS], c[2];"
"MOV R0.w, v[OPOS];"
 
// Transform vertices into clip space via modelview-projection matrix
"DP4 o[HPOS].x, R0, c[4];"
"DP4 o[HPOS].y, R0, c[5];"
"DP4 o[HPOS].z, R0, c[6];"
"DP4 o[HPOS].w, R0, c[7];"
 
// Send the color through unchanged
"MOV o[COL0], v[COL0];"
 
// End Vertex program
"END"

// Setup for billboarding VP
glTrackMatrix(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW, GL_INVERSE_NV);
glTrackMatrix(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);

Let me know if I omitted any info that would help people get this to work.

Enjoy

– Zeno

[This message has been edited by Zeno (edited 05-28-2001).]

If I may revert to my teanage years to find a suitable reply …

Zeno Rulez!

hm… nice… but why retained mode if not vertexprogram?

or whats with this?

static float bm[ 16 ];

void glBeginBillboarding( )
{
float m[ 16 ];
glGetFloatv( GL_MODELVIEW_MATRIX, bm );
m[ 0 ] = bm[ 0 ];
m[ 1 ] = bm[ 4 ];
m[ 2 ] = bm[ 8 ];
m[ 4 ] = bm[ 1 ];
m[ 5 ] = bm[ 5 ];
m[ 6 ] = bm[ 9 ];
m[ 8 ] = bm[ 2 ];
m[ 9 ] = bm[ 6 ];
m[ 10 ] = bm[ 10 ];
m[ 3 ] = m[ 7 ] = m[ 11 ] = m[ 12 ] = m[ 13 ] = m[ 14 ] = 0;
m[ 15 ] = 1;
glMultMatrixf( m );
}

void glEndBillboarding( )
{
glLoadMatrixf( bm );
}

void Draw (void)
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity (); // Reset The Modelview Matrix
glTranslatef (0.0f, 0.0f, -12.0f); // Translate 6 Units Into The Screen
glRotatef (angle, 0.0f, 1.0f, 0.0f); // Rotate On The Y-Axis By angle
glTranslatef( 0, 0, 6 );

glBegin (GL_QUADS); // Begin Drawing Triangles
glColor3f (1.f, 0.f, 0.f); glVertex3f( -1.0f, -1.0f, 0.0f);
glColor3f (0.f, 1.f, 0.f); glVertex3f( 1.0f,-1.0f, 0.0f);
glColor3f (0.f, 0.f, 1.f); glVertex3f( 1.0f,1.0f, 0.0f);
glColor3f (.5f, .5f, .5f); glVertex3f( -1.0f,1.0f, 0.0f);
glEnd (); // Done Drawing Triangles

glBeginBillboarding( );

glBegin (GL_QUADS); // Begin Drawing Triangles
glColor3f (1.f, 0.f, 0.f); glVertex3f( -1.0f, -1.0f, 0.0f);
glColor3f (0.f, 1.f, 0.f); glVertex3f( 1.0f,-1.0f, 0.0f);
glColor3f (0.f, 0.f, 1.f); glVertex3f( 1.0f,1.0f, 0.0f);
glColor3f (.5f, .5f, .5f); glVertex3f( -1.0f,1.0f, 0.0f);
glEnd (); // Done Drawing Triangles

glEndBillboarding( );

glFlush (); // Flush The GL Rendering Pipeline
}

nehe basecode with this little two funcs you should have nice billboarding…

ok, you have to call the func before rendering to make sure u use the right matrices… but heh… its working…

but ok… working with a vp… thats nice for gf3 fans… i like having it with hwtnl on my gf2… so…

btw, my code dont work really, and the vp not, too… they work equally, but not good for use… and why? cause you have to set up the matrix for every particle anyways to draw im around the zeropoint… else you dont get it at the pos you wanted cause he will not be rotated at the right place ( no! we cut out the rotation, and now hes not rotated! )

Daveperman -

I noticed this last night. My vertex program has more and more restrictions the more I use it. Right now, it will only work if you draw your quad (for example) like this:

// Set up modelview and projection matrices
.
.

// Draw polygon
glTranslatef(10, 10, 0);
glBegin(GL_QUADS);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd( );

i.e. the polygon has to start centered at (0,0,0) and translated via the modelview. If you don’t translate, but instead give vertex coords centered around (10.0, 10.0), it won’t rotate with the rest of the scene… I’ll have to think about this.

– Zeno

As I said, you have to do enough set-up on the host side (per billboard) that I can see no use to use a vertex program in this case.

I’m sure that makes me a nay-sayer, though; too bad :slight_smile:

“i.e. the polygon has to start centered at (0,0,0) and translated via the modelview. If you don’t translate, but instead give vertex coords centered around (10.0, 10.0), it won’t rotate with the rest of the scene… I’ll have to think about this.
– Zeno”

Isn’t that what you would do anyway - say if you wanted to billboard 10,000 trees ? You don’t want the hassle of 10,000 different sets of quad vertices ? Wouldn’t 10,000 glTranslates on the same quad be cleaner/faster ? Of to check now on GF3

Rob J. http://www.pocketmoon.com

fastest would be to create a pointer of 10000 vertices with this settings:

( x,y,z-coordinate of billboard, size of billboard ( in units… ) )

and then use this array, and draw it as GL_POINT_SPRITES_EXT points… would be very fast, if in hardware… and not much slower if in software directly in the driver i think… but in hw it would save much memory bandwith… no texcoords needed, automatically done… ok, a normal perhaps… but 1/4 times the data you have to send with any other ways… so i would prefer having new types of rendering-stuff in glBegin than a vertexprogram… GL_THETRAEDER_EXT would be nice, too… ( the simplest volumetric object in space… for volumetric effects… ) or GL_SHADOWED_LINE_EXT… and more… i would know many wich could save bandwith, and thats what currently is needed…

but anyways… vertexprograms are great… for example for setting up perpixellighing in tangentspace… saves softwareprocessing of every vertex… wich is usefull there… and for doing some fancy effects, too… but most of all i like it as “setupprogram” for the texture_shader/register_combiners or pixelshader… depends

If that’s what you do anyway, then this is the best possible solution, I think

Ideally, though, you’d like to just blast vertex positions to the card via VAR or vertex arrays, and have the gfx card billboard these polys for you. If you have to call glTranslatef() before each poly, you are sorta forced into immediate mode, which will be slower. It’s also slower cuz you force the driver to do a matrix multiply for each poly. However, you could use a display list if your polys are static…I don’t know how much display lists speed up calls to gltranslate().

Anyway, I think it would be ideal if your translations didn’t have to be done with glTranslatef(), but this may require sending the center of the poly to the vertex program in addition to the vertex you are rendering.

What we really need is opengl point sprites!

– Zeno

ok, this is an official call to ATI and NVIDIA ( and all the others wich create new drivers during the time… ):

PLEASE INCLUDE GL_POINT_SPRITES_EXT, PLEASE

i dont think it would be so hard to do, would it?

_glVertex4f( float x, float y, float z, float w )
{
if( mode == GL_POINT_SPRITES_EXT )
{
GLvec v( x, y, z );
v.Transform( GL_MODELVIEW_MATRIX );
GLvec v0,v1,v2,v3;
v0 = v + GLvec( w, w );
v0.Transform( GL_PROJECTION_MATRIX );
GPUBegin( GPU_QUAD );
v0.SendToGPU( );
v1 = v + GLvec( -w, w );
v1.Transform( GL_PROJECTION_MATRIX );
v1.SendToGPU( );
v2 = v + GLvec( -w, -w );
v2.Transform( GL_PROJECTION_MATRIX );
v2.SendToGPU( );
v3 = v + GLvec( w, -w );
v3.Transform( GL_PROJECTION_MATRIX );
v3.SendToGPU( );
GPUEnd( );
}
}

something like that ( not sure at all if it is that writing code here in the forum is not what i am good in )