more than one vertex color, possible?

I often need to store lots of data in my vertices (in an EGG file). The only way to do this seems to be adding more UV coordinates, and even then it is necessary to add fakey textures using those UVs to ensure they make it to the shader.
Is there a better solution?

The egg format doesn’t currently have a way to define custom vertex columns, but I’d certainly have no objection to someone adding that feature if you’re interesting in doing that work. :slight_smile:

Other than that, you could probably write a custom loader that read it in from some external file and paired it with the existing vertices, though this gets sticky since the egg loader might reorder (or even replicate) vertices.

Or, you could continue to use UV’s, and then rename the vertex columns in code, after loading the file (thus avoiding the need to use fakey textures).


Well I am interested in adding such a thing, and it seems like something I could handle.
Do you think allowing named vertex colours, like how the UVs are, would be a good interface for the extra RGBA entries?

That still seems like a bit of a hack, especially since colors imply a host of other things (like scaling to the range 0…1, an implicit value of 1, the overriding of polygon color, or even a contents type of C_color) that might not necessarily be true in the case of arbitrary custom data.

Why not add a new kind of attribute, like for instance name { x y z w }, to allow auxiliary data? The column name can then be exactly “name”, which gives the egg file creator the most flexibility in constructing the vertex data.


Out of curiosity, how would I rename and access the renamed data from an extra UV in a custom shader?

From List of Possible Cg Shader Inputs:


I don’t suppose there is a similar way to get it in a GLSL shader?
Also I am not seeing how to rename the vertex column.
I got as far as getting the proper column, but it seems I can only remove columns from the format, not add or rename them:

gvdata = nodepath.node().modifyGeom(0).modifyVertexData()
format = gvdata.getFormat()
col = format.getTexcoord(1)

Do I need to make a whole new geom?

Ah, you’re right, renaming the column is a bit tricky, but it can be done. You’ll have to create a new GeomVertexFormat that is exactly the same as the original format, but with the new column name(s). Then you’ll have to create a new GeomVertexData with the same data and the new format.

You can’t just use vdata->set_format(new_format), because that will try to adjust the data to match the new format by matching up the columns by names, but instead you’ll have to use vdata_array->get_data() and vdata_array->set_data() to copy the data as a block.

I’m not as familiar with the GLSL implementation, but I think it is also possible to get the column names. rdb?


I’ve added a new data type called Aux to the vertex as you suggested. I am having a bit of trouble with the parser file though.
In egg/parser.yxx I’ve added an include:

#include "eggVertexAux.h"

A token:


The bit that should pick up the new token:

        | vertex_body AUX required_name '{'
  EggVertex *vertex = DCAST(EggVertex, egg_stack.back());
  EggVertexAux *aux = new EggVertexAux($3, LVecBase4d::zero());
  if (vertex->has_aux($3)) {
    eggyywarning("Ignoring repeated Aux name " + $3);
  } else {
         vertex_aux_body '}'

And finally the bit that should read the values:

 * vertex_aux_body
 * enter: TOS is EggVertex.
 * exit: vertex Aux value has been filled.
        | real real real real
  DCAST(EggVertexAux, egg_stack.back())->set_aux(LVecBase4d($1, $2, $3, $4));

But it is still giving me a parse error:

Error in /c/work/sp1/assets/models/dummy.egg at line 27, column 13:
        <Aux> testdata { 1 0 0 1 }
parse error

Any idea what I’ve done wrong?

You don’t want a leading vertical bar in the vertex_aux_body definition. The vertical bar is used to separate alternate definitions; it shouldn’t precede the first (or only) definition.

Remember you also have to add your new token to lexer.lxx.

Were there any error messages from bison or flex when you compiled this? I think it’s actually a bit strange that it would have compiled.


It seemed to compile just fine.
I used the UV definition as reference.
After adding the token to lexer.lxx it appears to be reading the values from the EGG.

Unfortunately I’ve messed up the part where I add the new columns so I’ll have to figure out what’s wrong with that now.

So far I’ve added to make_vertex_data in eggLoader.cxx:

    EggVertex::const_aux_iterator auxi;
    for (auxi = vertex->aux_begin(); auxi != vertex->aux_end(); ++auxi) {
      EggVertexAux *egg_aux = (*auxi);
      LVecBase4d aux = egg_aux->get_aux();

      string name = egg_aux->get_name();
      PT(InternalName) iname = InternalName::make(name);


But seems like set_column is returning false, so probably I need to create that column somewhere earlier on?

Updated: Ah I see it, the add_column calls. :slight_smile:

OK I’ve got not one, not two, but three patches!

First off is for the topic at hand, the patch to add the Aux data in the EGG format. This allows storing arbitrary base4 data on the vertices which can be read by a CG shader (maybe GLSL too?).

Second is some additional fixes to make BufferViewer, OnScreenText, and the direct entry coordinate-system agnostic.

And the third one is a patch to add array inputs to GLSL shaders that I found on the forum and have been keeping up to date.

All those combined would bring my own repository in line with Panda’s and make me very happy. :slight_smile:

All three patches integrated, with my thanks!


Hi David,
I’ve got a small patch related to the Aux data. It allows CG shaders in DX9 to use a TEXCOORD semantic to read vertex data with 4 elements. This matches the functionality of OpenGL. Without it there is no good semantic to use for reading the Aux data in DX9.

Committed, thanks!


Can you post an example of array inputs to GLSL in Python? I tried

np.setShaderInput('fs', [10.0, 40.0])


fs = pModules.PTAFloat().emptyArray(2)
np.setShaderInput('fs', fs)

and in shader

uniform float fs[2];
a = fs[0];
b = fs[1];

and I always get error:

AssertionError: Shader input fs[0] is not present.

This is a tricky one that depends on what the graphics driver expects. According to the GL docs both “name” and “name[0]” are valid for a driver to use. Until a few months ago NVIDIA used to use “name” but switched to “name[0]” in recent drivers. ATI/AMD use the same convention. Note that it is always [0] regardless of the size of the array.
To be safe (and future proof) just do both. For example:

fs = PTA_LVecBase4f()
fs.pushBack(Vec4(1, 0, 0, 1))
fs.pushBack(Vec4(0, 1, 0, 1))
np.setShaderInput('fs', fs)
np.setShaderInput('fs[0]', fs)

I’m sure with some tinkering to the engine code it could be made to work for both with only one setShaderInput call, but it is easy enough to work around.

Thanks :slight_smile:
now it’s working.
Just for the record, vectors are working, but floats are not. It isn’t very important though, I can use vectors instead of arrays in this case.