Sign in to follow this  
spek

VBO with tangent data

Recommended Posts

Hi, I want to use VBO's for my objects, but I can't find space for putting the tangent data in it as well. My vertex-data contains this: - Vertices(3f) - Texcoords(2f) - Normals(3f) - Tangents(3f) - BiTangents(3f) Its a while ago since I used VBO's, so correct me if I'm wrong. Normally I would use the "glInterleavedArrays" function to tell what the data format is. For example, I can choose for "GL_C4UB_V3F" format, which means it the vertex-data contains 4 unsigned bytes for the color, and a vertices with 3 components. But what format to use for the stuff I want? Normally I put my tangents/biTangents inside texture coordinates on channel 1 and 2. But I can't find a format for that. greetings, Rick

Share this post


Link to post
Share on other sites
It is, perhaps, time to switch to defining your own layouts. I never even bothered trying those pre-packaged configurations. Modern 3D cards, and most certainly VBO processing, are designed for vertex-structures that contain some multiple of 32-bytes (32-bytes, 64-bytes, etc).

I have two vertex structures in my engine, one with 32-bytes that contains:
    position: x,y,z
    tcoords: u,v
    color: r,g,b,a
    normal: nx,ny,[nz]
and another with 64-bytes that contains:
    position: x,y,z
    tcoords: u,v
    color: r,g,b,a
    normal: nx,ny,nz
    tangent: tx,ty,tz
    bitangent: bx,by,bz

You are being pushed in this direction now, and this is where you should go. Once you have it working, you will never look back! However, you will probably want/need to consider making some of your components with integers. For example, to make my vertex-structures and VBO arrangement "work out", I store my colors and texture-coordinates as u16 values (unsigned 16-bit integers). This required me to NOT put the z component of the normal vector into the VBO, to make room for the four u16 RGBA color values in one-half of the vertex. But that is no problem since the shader can compute nz from nx,ny! :-)

Share this post


Link to post
Share on other sites
64 bytes should be sufficient. But... how to render it in that case? I didn't know this was possible as well. Is there a constant to tell OpenGL 64 bytes is coming? And ifso, how to set the data up?

Before I made an array with floats, something like this:

// format = GL_T2F_C4UB_V3F
data[n][0] = texcoord.x
data[n][1] = texcoord.y
data[n][2] = <packed rgba in 1 float>
data[n][3] = vertex.x
data[n][4] = vertex.y
data[n][5] = vertex.z


But what to do now? Is there an example somewhere?

greetings,
Rick

Share this post


Link to post
Share on other sites
Don't use GL's built in glInterleavedArrays, setup the arrays yourself.

Make a struct and put the vertex attributes in it you need. Than allocate the memory you need and fill the data and upload the data to the VBO as a whole unit if you want or map it. Then you use offsets in bytes of the size of the data you want to access. e.g.


struct Vertex
{
float vx,vy,vz;
float nx,ny,nz;
float tx,ty,tz;
//others
};

//then you get the size of the data
unsigned int normalsOffset = sizeof(float) * 3;
unsigned int tangentOffset = sizeof(float) * 6;




then you use the offsets in the array pointer functions with the Bufferoffset macro from the extension doc.

hope that helps

Share this post


Link to post
Share on other sites
Uhm... I understand how to make the data array. But with which function to pass it? So far I always use "glDrawElements". Its a while ago I used VBO's. Possibly I also have an older version of the OpenGL function library.

greetings and thanks for helping,
Rick

Share this post


Link to post
Share on other sites
Well, this is a somewhat involved process that you need to grind through once to get right. For me, it took reading the OpenGL information carefully about thirty-seven million, nine-hundred and fifty-six thousand, eight-hundred and twenty-six times. I think I looked in "OpenGL SuperBible" and the "OpenGL Programmer Manual" a few times too. Oh, and after I got it working I got "OpenGL Distilled" and it would have saved me a couple years I think.

All the above just means "it ain't trivial".

Here is some code to read to get hints from. This code WORKS, so I know it is correct, but many of the variables are specific to my engine, and therefore make no sense to you (though they are pretty descriptive names). However, all the OpenGL function calls are what you need to understand, and this code shows you what order they come in. The first function is where the shaders are created and initialized and all the vertex-element positions are registered with OpenGL and double-checked by the code (to make sure it happened correctly).

This code is called once to set up the shaders and its variables (which are specific to processing the vertex structure I outlined previously).

The second chunk of code is a function the first function/code-chunk calls.

The third chunk of code is code that sets up OpenGL before every draw call (and you can see the draw call down at the bottom).

If all this code isn't enough to drive you crazy, then you will end up very happy and never return to fixed predefined vertex arrangements - which are hopelessly ancient and inflexible and inefficient in new video cards.

Sorry, but you will need to do some reading and learning to understand this. But you'll probably find lots of VBO experts to explain this a hundred times better than I ever could. I only know how to slog until it works! And since I have the worst memory on earth, I cannot remember all the hows and whys. :-(




cpu ig_shader_create (cpu vertex, cpu pixel) { // function entry

buffer = memory_buffer_create (maxbytes);

file_load (L"igtan003.vs", &vsource, &vbytes); // vertex shader
file_load (L"igtan003.ps", &psource, &pbytes); // pixel shader
//
// create vertex shader and pixel shader
//
vshader = glCreateShader (GL_VERTEX_SHADER); // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
pshader = glCreateShader (GL_FRAGMENT_SHADER); // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
//
// specify vertex shader and pixel shader source-code text
//
const GLchar** vstext = (const GLchar**)&vsource; // vstext is an array of pointers to strings that contain vertex-shader-programs-or-functions (source code)
const GLchar** pstext = (const GLchar**)&psource; // pstext is an array of pointers to strings that contain pixel-shader-programs-or-functions (source code)
glShaderSource (vshader, vlines, vstext, &vbytes); //
glShaderSource (pshader, plines, pstext, &pbytes); //
//
// compile vertex shader
//
glCompileShader (vshader); // compile vertex shader
glGetShaderiv (vshader, GL_COMPILE_STATUS, &success); // success or failure ???
if (success == 0) {
glGetShaderiv (vshader, GL_INFO_LOG_LENGTH, &ebytes);
log = memory_buffer_create (ebytes + 1);
if (log == 0) { return (CORE_ERROR_MEMORY_ALLOCATION); }
glGetShaderInfoLog (vshader, ebytes, NULL, (GLchar*)log);
error = file_log_c08 (log);
memory_buffer_destroy (log);
memory_buffer_destroy (buffer);
memory_buffer_destroy (vsource);
memory_buffer_destroy (psource);
return (CORE_ERROR_INTERNAL);
}
//
// compile pixel shader and test for error message
//
glCompileShader (pshader); // compile pixel shader
glGetShaderiv (pshader, GL_COMPILE_STATUS, &success); // success or failure ???
if (success == 0) {
glGetShaderiv (pshader, GL_INFO_LOG_LENGTH, &ebytes);
log = memory_buffer_create (ebytes + 1);
if (log == 0) { return (CORE_ERROR_MEMORY_ALLOCATION); }
glGetShaderInfoLog (pshader, ebytes, NULL, (GLchar*)log);
error = file_log_c08 (log);
memory_buffer_destroy (log);
memory_buffer_destroy (buffer);
memory_buffer_destroy (vsource);
memory_buffer_destroy (psource);
return (CORE_ERROR_INTERNAL);
}
//
// create empty "program object"
//
program = glCreateProgram (); // create "program object"
//
// attach vertex-shader and pixel-shader to this "program object"
//
glAttachShader (program, vshader); // attach vertex shader to program
glAttachShader (program, pshader); // attach pixel shader to program
//
// establish:
// - vertex structure component types and offsets
// - generic vertex attribute variables
// - uniform variables [and others?]
// - other shader stuff
//
error = ig_shader_setup (program, vshader, pshader, 0);
if (error < 0) { return (error); }
//
// link vertex-shader and pixel-shader in this "program object"
//
char* logc = (char*)log;
glLinkProgram (program); // link program object
glGetProgramiv (program, GL_LINK_STATUS, &success); // success or failure ???
if (success == 0) {
glGetProgramiv (program, GL_INFO_LOG_LENGTH, &ebytes);
log = memory_buffer_create (ebytes + 1);
if (log == 0) { return (CORE_ERROR_MEMORY_ALLOCATION); }
glGetProgramInfoLog (program, ebytes, NULL, (GLchar*)log);
logc = (char*)log;
error = file_log_c08 (log);
memory_buffer_destroy (log);
memory_buffer_destroy (buffer);
memory_buffer_destroy (vsource);
memory_buffer_destroy (psource);
return (CORE_ERROR_INTERNAL);
}
//
// attempt to validate this program-object (try to validate vertex-shader and pixel-shader in this program-object)
//
glValidateProgram (program);
glGetProgramiv (program, GL_VALIDATE_STATUS, &success);
if (success == 0) {
glGetProgramiv (program, GL_INFO_LOG_LENGTH, &ebytes);
log = memory_buffer_create (ebytes + 1);
if (log == 0) { return (CORE_ERROR_MEMORY_ALLOCATION); }
glGetProgramInfoLog (program, ebytes, NULL, (GLchar*)log);
error = file_log_c08 (log);
memory_buffer_destroy (log);
memory_buffer_destroy (buffer);
memory_buffer_destroy (vsource);
memory_buffer_destroy (psource);
return (CORE_ERROR_INTERNAL);
}
//
// tell GPU to activate our program-object (our vertex-shader and pixel-shader)
//
glstate.active_vshader = vshader;
glstate.active_pshader = pshader;
glstate.active_program = program;
igstate.active_shaders = program;
igstate.shaderprogram = program;
//
// make program active (GPU executes shader rather than current shaders --- or default fixed pipeline)
//
glUseProgram (program);

glGetShaderiv (vshader, GL_INFO_LOG_LENGTH, &vsbytes);
glGetShaderiv (pshader, GL_INFO_LOG_LENGTH, &psbytes);
glGetProgramiv (program, GL_INFO_LOG_LENGTH, &prbytes);

glGetShaderInfoLog (vshader, maxbytes, &readbytes, (GLchar*)buffer);
glGetShaderInfoLog (pshader, maxbytes, &readbytes, (GLchar*)buffer);
glGetProgramInfoLog (program, maxbytes, &readbytes, (GLchar*)buffer);
//
// load and install any textures required for this shader
//
// [special-purpose texture-map/normal-map loading code snipped]
//
//
GLuint texid;
glGenTextures (1, &texid);
glstate.texid_texturemap = texid; // remember OpenGL texture-object ID #
//
// set-up the necessary textures for texture/height/normal/relief/parallax/distance/occlusion/displacement mapping (normal-tweaking tricks in tangent-space)
//
// first a simple texture map to apply to surface
//
glActiveTexture (GL_TEXTURE0); // set active texture unit # = 0
glBindTexture (GL_TEXTURE_2D, glstate.texid_texturemap); // attach the "texturemap" texture to texture-unit #0
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, twidth, theight, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmap);
//
// second a height-map in the A channel and a normal-map in the RGB channels
//
glGenTextures (1, &texid);
glstate.texid_surfacemap = texid; // remember OpenGL texture-object ID #

glActiveTexture (GL_TEXTURE1); // set active texture unit # = 1
glBindTexture (GL_TEXTURE_2D, glstate.texid_surfacemap); // attach the "surfacemap" texture to texture-unit #1
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, swidth, sheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, smap);

glActiveTexture (GL_TEXTURE0); // set active texture unit # = 0 == default-location
//
// see if we can verify our attributes
//
glstate.index_position = glGetAttribLocation (program, "ig_position"); // position
glstate.index_tcoord = glGetAttribLocation (program, "ig_tcoord"); // tcoord
glstate.index_up = glGetAttribLocation (program, "ig_up"); // up-vector AKA zenith-vector AKA normal-vector
glstate.index_color = glGetAttribLocation (program, "ig_color"); // color == RGBA
glstate.index_east = glGetAttribLocation (program, "ig_east"); // east-vector AKA tangent-vector
glstate.index_north = glGetAttribLocation (program, "ig_north"); // north-vector AKA bitangent-vector
glstate.index_select = glGetAttribLocation (program, "ig_select"); // select behavior in vertex-shader and pixel-shader

glstate.index_pcamera = glGetUniformLocation (program, "ig_pcamera"); // uniform variable == camera position
glstate.index_plight0 = glGetUniformLocation (program, "ig_plight0"); // uniform variable == light0 position
glstate.index_plight1 = glGetUniformLocation (program, "ig_plight1"); // uniform variable == light1 position
glstate.index_plight2 = glGetUniformLocation (program, "ig_plight2"); // uniform variable == light2 position
glstate.index_texturemap = glGetUniformLocation (program, "ig_texturemap"); // texture-map #0 == texture-unit #0
glstate.index_surfacemap = glGetUniformLocation (program, "ig_surfacemap"); // texture-map #1 == texture-unit #1
//
// NOTE: We do not assign values to pcamera, plight0, plight1, plight2 here,
// because they must be set every frame (since they can be moved every frame).
// However, we do assign values to texturemap, surfacemap, [foldingmap], [steppermap],
// because they remain fixed [probably] as long as these shaders remain installed.
//
glUniform1i (glstate.index_texturemap, 0); // specify texture unit # that contains "texturemap"
glUniform1i (glstate.index_surfacemap, 1); // specify texture unit # that contains "surfacemap"
//
// If we execute the rest of this function (below),
// we cannot switch back to default-pipeline processing
// and THEN back to this program (cuz it has been trashed)!
//
// Therefore, we really should not detach and delete these resource,
// we should do that when the program is done executing (to clean up).
//
if (1) {
glDetachShader (program, vshader);
glDetachShader (program, pshader);

glDeleteShader (vshader);
glDeleteShader (pshader);
glDeleteProgram (program);
}

memory_buffer_destroy (log);
memory_buffer_destroy (buffer);
memory_buffer_destroy (vsource);
memory_buffer_destroy (psource);
}






//
// the following is the guts of function ig_shader_setup() --- called from the other code
//
cpu ig_shader_setup (cpu program, cpu vshader, cpu pshader, cpu options) {

//
// [snip internal setup code]
//
// get offset to each element in ig_vertex32 structure (vertex structure we put into VBO)
//
u08* base = (u08*)&vertex;
u08* offsetp = (u08*)((u08*)&vertex.position - (u08*)base); // 0x0000 to 0x000B ::: 3 * f32 position.xyz
u08* offsett = (u08*)((u08*)&vertex.tcoords - (u08*)base); // 0x000C to 0x000F ::: 2 * u16 tcoord.st
u08* offsetu = (u08*)((u08*)&vertex.up - (u08*)base); // 0x0010 to 0x0018 ::: 2 * f32 up.xy
u08* offsetc = (u08*)((u08*)&vertex.coloru16[0] - (u08*)base); // 0x0018 to 0x001F ::: 4 * u16 color.rgba
u08* offsete = (u08*)((u08*)&vertex.east - (u08*)base); // 0x0020 to 0x002F ::: 4 * f32 east.xyz + up.z
u08* offsetn = (u08*)((u08*)&vertex.north - (u08*)base); // 0x0030 to 0x003B ::: 3 * f32 north.xyz
u08* offsets = (u08*)((u08*)&vertex.selectu08[0] - (u08*)base); // 0x003C to 0x003F ::: 4 * u08 select.xyzw
//
// define vertex attributes --- each corresponds to one component of the vertex structure we put into the VBO
//
glVertexAttribPointer (1, 2, GL_UNSIGNED_SHORT, 1, vbytes, offsett); // 2 * u16 == tcoord.st
glVertexAttribPointer (2, 2, GL_FLOAT, 0, vbytes, offsetu); // 2 * f32 == up.xy
glVertexAttribPointer (3, 4, GL_UNSIGNED_SHORT, 1, vbytes, offsetc); // 4 * u16 == color
glVertexAttribPointer (4, 4, GL_FLOAT, 0, vbytes, offsete); // 4 * f32 == east.xyz + up.z
glVertexAttribPointer (5, 3, GL_FLOAT, 0, vbytes, offsetn); // 3 * f32 == north.xyz
glVertexAttribPointer (6, 4, GL_UNSIGNED_BYTE, 1, vbytes, offsets); // 4 * u08 == select.xyzw
glVertexAttribPointer (0, 3, GL_FLOAT, 0, vbytes, offsetp); // 3 * f32 == position (must be executed LAST)
//
// enable every vertex attribute --- evidentally not needed (!!!!! until we implement long AND short (halfsize) vertices !!!!!)
//
glEnableVertexAttribArray (0); // enable vertex position
glEnableVertexAttribArray (1); // enable vertex tcoords
glEnableVertexAttribArray (2); // enable vertex up-vector
glEnableVertexAttribArray (3); // enable vertex color
glEnableVertexAttribArray (4); // enable vertex east-vector
glEnableVertexAttribArray (5); // enable vertex north-vector
glEnableVertexAttribArray (6); // enable vertex select-behavior
// glEnableVertexAttribArray (0); // enable vertex position
//
// just curious whether the following function exist and function
//
void* attr00 = 0;
void* attr01 = 0;
void* attr02 = 0;
void* attr03 = 0;
void* attr04 = 0;
void* attr05 = 0;
void* attr06 = 0;
glGetVertexAttribPointerv (0, GL_VERTEX_ATTRIB_ARRAY_POINTER, (GLvoid**)&attr00);
glGetVertexAttribPointerv (1, GL_VERTEX_ATTRIB_ARRAY_POINTER, (GLvoid**)&attr01);
glGetVertexAttribPointerv (2, GL_VERTEX_ATTRIB_ARRAY_POINTER, (GLvoid**)&attr02);
glGetVertexAttribPointerv (3, GL_VERTEX_ATTRIB_ARRAY_POINTER, (GLvoid**)&attr03);
glGetVertexAttribPointerv (4, GL_VERTEX_ATTRIB_ARRAY_POINTER, (GLvoid**)&attr04);
glGetVertexAttribPointerv (5, GL_VERTEX_ATTRIB_ARRAY_POINTER, (GLvoid**)&attr05);
glGetVertexAttribPointerv (6, GL_VERTEX_ATTRIB_ARRAY_POINTER, (GLvoid**)&attr06);
error = glGetError ();
//
// assocatiates attribute variable names in vertex shader with vertex structure components
//
glBindAttribLocation (program, 0, "ig_position"); // 0 == position
glBindAttribLocation (program, 1, "ig_tcoord"); // 1 == tcoord
glBindAttribLocation (program, 2, "ig_up"); // 2 == up-vector
glBindAttribLocation (program, 3, "ig_color"); // 3 == color
glBindAttribLocation (program, 4, "ig_east"); // 4 == east-vector
glBindAttribLocation (program, 5, "ig_north"); // 5 == north-vector
glBindAttribLocation (program, 6, "ig_select"); // 6 == select

return (0);
}







cpu ig_batch_draw (cpu batchid, cpu mode) {

//
// #######################################
// THE FOLLOWING CODE SHOULD NOT BE NEEDED
// #######################################
//
// get offset to each element in ig_vertex32 structure (vertex structure we put into VBO)
//
ig_vertex32 vertex;
cpu vbytes = sizeof(ig_vertex32);

u08* base = (u08*)&vertex;
u08* offsetp = (u08*)((u08*)&vertex.position - (u08*)base); // 0x0000 to 0x000B ::: 3 * f32 position.xyz
u08* offsett = (u08*)((u08*)&vertex.tcoords - (u08*)base); // 0x000C to 0x000F ::: 2 * u16 tcoord.st
u08* offsetu = (u08*)((u08*)&vertex.up - (u08*)base); // 0x0010 to 0x0018 ::: 2 * f32 up.xy
u08* offsetc = (u08*)((u08*)&vertex.coloru16[0] - (u08*)base); // 0x0018 to 0x001F ::: 4 * u16 color.rgba
u08* offsete = (u08*)((u08*)&vertex.east - (u08*)base); // 0x0020 to 0x002F ::: 4 * f32 east.xyz + up.z
u08* offsetn = (u08*)((u08*)&vertex.north - (u08*)base); // 0x0030 to 0x003B ::: 3 * f32 north.xyz
u08* offsets = (u08*)((u08*)&vertex.selectu08[0] - (u08*)base); // 0x003C to 0x003F ::: 4 * u08 select.xyzw
//
// define vertex attributes --- each corresponds to one component of the vertex structure we put into the VBO
//
// glVertexAttribPointer (0, 3, GL_FLOAT, 0, vbytes, offsetp); // 3 * f32 == position.xyz (must be executed LAST)
glVertexAttribPointer (1, 2, GL_UNSIGNED_SHORT, 1, vbytes, offsett); // 2 * u16 == tcoord.st
glVertexAttribPointer (2, 2, GL_FLOAT, 0, vbytes, offsetu); // 2 * f32 == up.xy
glVertexAttribPointer (3, 4, GL_UNSIGNED_SHORT, 1, vbytes, offsetc); // 4 * u16 == color
glVertexAttribPointer (4, 4, GL_FLOAT, 0, vbytes, offsete); // 4 * f32 == east.xyz + up.z
glVertexAttribPointer (5, 3, GL_FLOAT, 0, vbytes, offsetn); // 3 * f32 == north.xyz
glVertexAttribPointer (6, 4, GL_UNSIGNED_BYTE, 1, vbytes, offsets); // 4 * u08 == select.xyzw
glVertexAttribPointer (0, 3, GL_FLOAT, 0, vbytes, offsetp); // 3 * f32 == position (must be executed LAST)
error = glGetError ();
//
// enable every vertex attribute --- evidentally not needed (until we implement long AND short vertices)
//
if (0) {
glEnableVertexAttribArray (0); // enable vertex position
glEnableVertexAttribArray (1); // enable vertex tcoords
glEnableVertexAttribArray (2); // enable vertex up-vector
glEnableVertexAttribArray (3); // enable vertex color
glEnableVertexAttribArray (4); // enable vertex east-vector
glEnableVertexAttribArray (5); // enable vertex north-vector
glEnableVertexAttribArray (6); // enable vertex select-behavior
// glEnableVertexAttribArray (0); // enable vertex position
error = glGetError ();
}
//
//
// OpenGL draw modes - IG support ::: IG primitive
//
// GL_POINTS - IG supports == IG_PRIMITIVE_POINT
// GL_LINES - IG supports == IG_PRIMITIVE_LINE
// GL_TRIANGLES - IG supports == IG_PRIMITIVE_TRIANGLE == IG_PRIMITIVE_SURFACE
//
// GL_LINE_STRIP - no -------- but IG supports line strips with GL_LINES
// GL_LINE_LOOP - no -------- but IG supports line loops with GL_LINES
//
// GL_TRIANGLE_STRIP - no
// GL_TRIANGLE_FAN - no
// GL_QUAD - no
// GL_QUAD_STRIP - no
// GL_POLYGON - no
//
// trying to disable our shaders for points and lines --- disables our shaders COMPLETELY and PERMANENTLY --- FIX THIS
//
u32 activeshaders = igstate.active_shaders;
u32 shaderprogram = igstate.shaderprogram;

error = GL_TRIANGLES;
error = GL_LINES;
error = GL_POINTS;

switch (ptype) {
case IG_PRIMITIVE_TRIANGLE:
gmode = GL_TRIANGLES;
break;
case IG_PRIMITIVE_LINE:
gmode = GL_LINES;
break;
case IG_PRIMITIVE_POINT:
gmode = GL_POINTS;
break;
default:
gmode = GL_TRIANGLES;
break;
}
//
// draw IBO/VBO pair == draw batch
// - separate batches for points versus lines versus triangles/surfaces
//
if (icount) {
glDrawElements (gmode, icount, GL_UNSIGNED_SHORT, 0);
error = glGetError();
}

return (0);
}


Share this post


Link to post
Share on other sites
One of you other VBO experts will have to tell him how many things he does NOT need to do if he has no shaders (just lets the fixed function run). I have never run OpenGL without IBOs and VBOs or without vertex and pixel shaders, so I have no idea whatsoever how to advise about those situations! :-(

Share this post


Link to post
Share on other sites
Wow, thanks for the code :) I'm studying it now. That probably takes a while, I never used some of the OpenGL calls.

I'm using (cg) shaders as well, so I have one more question about that, how to get the data in the shader? I guess the positions, texcoords and normals come in the "usual" way. But where to get other data, the tangents for example? Are they inside another texture coordinate channel?

-edit-
I see you are sending the data to parameters inside the shaders ("ig_position", "ig_tcoord", and so on). Are these uniform array parameters in your shader program? Could you show how you get these values back in your shader? Normally I use the "vertex", "normal" and "texcoord(s)" in my Cg shader, but I guess its a little different now.

greetings,
Rick

[Edited by - spek on April 7, 2007 1:20:49 PM]

Share this post


Link to post
Share on other sites
If you look in the code, you will see references to "up", "east", "north". These are my way of saying "normal", "tangent", "bitangent" (or "binormal"). The names I choose are easy to visualize which direction they point relative to each other, that's all.

So when you look at the code, you will find the "east" (tangent) vector and "north" (bitangent/binormal) vector are in the vertex-structure, just like the "up" (normal) vector.

At the top of the "shader_setup" function you will see code that shows exactly what each of the vertex-structure elements is, how big it is, what type it is, and how the information about it is told to OpenGL (the glVertexAttribPointer functions and the code-section just above that finds the offsets of each of those vertex elements in the vertex-structure (which goes in the VBO) so OpenGL knows where each vertex element is in each vertex-structure.

You can mix "conventional" vertex component (position, normal, color, etc) with extra application-defined "vertex attributes", but I find that confusing. So I made *every* vertex component an application-defined "vertex attribute" - so everything is defined the same way. The vertex and pixel shaders the code refers to "igtan003.vs" and "igtan003.ps" also access two textures, one of which contains pixel-colors (as usual), while the other contains a normal-map with nx,ny,nz,h components. I removed the code that loads these two maps from memory because it is totally irrelevant code that you don't need to copy.

PS: My shaders are GLSL shaders, and I know nothing about Cg shaders. Therefore your questions that might have different answers for Cg shaders are totally outta my knowledge. Some of the code refers to the variable names in my shader code, but I'm not sure that is part of your question. I will send you the corresponding shader code by PM in case that helps you understand.

Share this post


Link to post
Share on other sites
Now I understand your code, thanks! Only problem is that Cg doesn't have the "attribute" like you can use in GLSL. In Cg you have to pass the arrays via the vertex array, normals or a texture coordinate channel. So, I don't know where/how to get the data back that was given with "glVertexAttribPointer( )". But that is indeed a specific Cg question.

But won't it be possible the data array's another way? For example, I always used texture channel 2 for my tangents, so I passed the tangents like this:

glClientActiveTextureARB( GL_TEXTURE2_ARB );
glTexCoordPointer( 3, GL_FLOAT, SizeOf(vector3f), tangentData );
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

But I can't use the offset here though, so I have to use seperated arrays... But I can only attach 1 array to a VBO right (with "glBufferDataARB").

Maybe its possible to tell that the array from "glEnableVertexAttribArray(x)" is a texture coordinates array on channel[x]?

greetings,
Rick

Share this post


Link to post
Share on other sites
Quote:
Original post by spek
Now I understand your code, thanks! Only problem is that Cg doesn't have the "attribute" like you can use in GLSL. In Cg you have to pass the arrays via the vertex array, normals or a texture coordinate channel. So, I don't know where/how to get the data back that was given with "glVertexAttribPointer( )". But that is indeed a specific Cg question.

But won't it be possible the data array's another way? For example, I always used texture channel 2 for my tangents, so I passed the tangents like this:

glClientActiveTextureARB( GL_TEXTURE2_ARB );
glTexCoordPointer( 3, GL_FLOAT, SizeOf(vector3f), tangentData );
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

But I can't use the offset here though, so I have to use seperated arrays... But I can only attach 1 array to a VBO right (with "glBufferDataARB").

Maybe its possible to tell that the array from "glEnableVertexAttribArray(x)" is a texture coordinates array on channel[x]?

greetings,
Rick


Does it appear that my program has separate arrays for the various components of each vertex? If so, this is a mistaken impression! All the components of each vertex (position, color, tcoord, normal, tangent, bitangent) is inside one totally conventional C structure. In other words, all the code you see is FOR interleaved vertex components!

In theory, you might be able to do things the way (I think) you describe above, namely "describe all non-conventional vertex components as extra texture-coord components to OpenGL". I cannot remember why I did not do that, except surely one of the reason is my dislike for code that appears to do one thing, but is actually doing something else! I hate that! But I vaguely recall I had some other more fundamental reasons too. I find it extremely difficult to believe that Cg cannot do the equivalent of everything (fundamental) that GLSL does, and this issue is certainly fundamental! Somebody who knows GLSL and Cg and OpenGL and VBOs should insert themselves into this conversation --- NOW !!!

Share this post


Link to post
Share on other sites
I understand that all your data is inside one buffer. And if I'm right, therefore you tell OpenGL what the format is inside that buffer by giving offsets.

I wonder if I can do the same on those "default" array's. I think the code for rendering would then look something like this:

// Activate VBO
glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBO_Handle );

// Set the format inside the VBO vertexData array:
// - f32 00..02 = vertex position (xyz)
// - f32 03..04 = texcoord (st)
// - f32 05..07 = normal (xyz)
// - f32 08..10 = tangent (xyz)
// - f32 11..13 = biTangent (xyz)
glVertexPointer( 3, GL_FLOAT, <stride?>, vert <with offset?> );
glNormalPointer( GL_FLOAT, <stride?>, nrm< with offset?> );
glTexCoordPointer( 2, GL_FLOAT, <stride>>, tex<offset?> );
... and also for tex channel 1 and 2 ...

// Render geometry
glDrawArrays( GL_TRIANGLES, 0, vertexCount );


Instead of the "interleaved" stuff, I now have to apply offsets on the vertex/normal and texcoord arrays. But how? I read something about that "Buffer_Offset" macro MArs_999 mentioned. I guess I can pass an array with an offset in the "pointer" functions. I think this website
http://www.g-truc.net/article/vbo-en.pdf // page 6/7
is actually doing that. But I'm using Delphi... I'm don't exactly know how to make make that offset macro.


Or am I doing something wrong now? It would also be nice if Cg has an equivalent of the GLSL attribute indeed, but I haven't seen it so far.

Thanks for helping!
Rick

Share this post


Link to post
Share on other sites
Look at the first 25 lines in the middle window of code that I posted several messages ago. Here it is again, cut and pasted from above.


u08* base = (u08*)&vertex;
u08* offsetp = (u08*)((u08*)&vertex.position - (u08*)base); // 0x0000 to 0x000B ::: 3 * f32 position.xyz
u08* offsett = (u08*)((u08*)&vertex.tcoords - (u08*)base); // 0x000C to 0x000F ::: 2 * u16 tcoord.st
u08* offsetu = (u08*)((u08*)&vertex.up - (u08*)base); // 0x0010 to 0x0018 ::: 2 * f32 up.xy
u08* offsetc = (u08*)((u08*)&vertex.coloru16[0] - (u08*)base); // 0x0018 to 0x001F ::: 4 * u16 color.rgba
u08* offsete = (u08*)((u08*)&vertex.east - (u08*)base); // 0x0020 to 0x002F ::: 4 * f32 east.xyz + up.z
u08* offsetn = (u08*)((u08*)&vertex.north - (u08*)base); // 0x0030 to 0x003B ::: 3 * f32 north.xyz
u08* offsets = (u08*)((u08*)&vertex.selectu08[0] - (u08*)base); // 0x003C to 0x003F ::: 4 * u08 select.xyzw
//
// define vertex attributes --- each corresponds to one component of the vertex structure we put into the VBO
//
glVertexAttribPointer (1, 2, GL_UNSIGNED_SHORT, 1, vbytes, offsett); // 2 * u16 == tcoord.st
glVertexAttribPointer (2, 2, GL_FLOAT, 0, vbytes, offsetu); // 2 * f32 == up.xy
glVertexAttribPointer (3, 4, GL_UNSIGNED_SHORT, 1, vbytes, offsetc); // 4 * u16 == color
glVertexAttribPointer (4, 4, GL_FLOAT, 0, vbytes, offsete); // 4 * f32 == east.xyz + up.z
glVertexAttribPointer (5, 3, GL_FLOAT, 0, vbytes, offsetn); // 3 * f32 == north.xyz
glVertexAttribPointer (6, 4, GL_UNSIGNED_BYTE, 1, vbytes, offsets); // 4 * u08 == select.xyzw
glVertexAttribPointer (0, 3, GL_FLOAT, 0, vbytes, offsetp); // 3 * f32 == position (must be executed LAST)




You see, it takes the address of the vertex structure and assignes that address to variable "base". Then the code following takes the addresses of the various components inside that vertex structure and subtracts "base" from them to get the offsets of each component from the base of each vertex structure. Then the second group of lines tells OpenGL this information with a series of glVertexAttribPointer() function calls. Is not that what you need to do? Perhaps I misunderstand your question - I'm good at that!

PS: I'm not sure GLSL "understands" anything about attributes either.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this