Kenneth Gorking said:
I dont know about the new render to vertex array from ATI with DX9,
so I describe the two actual render to vertex array methods for
NVidia cards I know as a kind of Tutorial.
Mihail121 said:
The example-source below is working (I just finished my own implementation)
and since there are many traps and things that should be known before
implementing render to vertex array, I hope this little howto can help others.
Comments for improvements and other issues are of course welcome.
Overview:
Method 1: Texture read in the Vertex Shader.
Advantages:
- no copy to VBO necessary
- flexible texture lookup
- consumes less memory
Disadvantages:
- only supported by NVidia cards
- just very few special float textures supported (GL_RGBA_FLOAT32_ATI)
- doesnt run on older GFX hardware
- slow ( 30M vertices/s on a GF6600GT just by reading the texture. if the
texture should be additionally rendered by the frame buffer object (FBO)
its even slower )
Method 2: Copy to Pixel Buffer Object (PBO)
Advantages:
- Multiple formats should be available for the PBO (not just float RGBA)
- Faster ( about 58M vertices/s
for render FBO+copy FBO to PBO+render VBO
on a GF6600GT. If copy wouldnt be required,
the speed would be 86Mverts/s)
Disadvantages:
- Higher memory consumption
- Extra copy necessary
- Multiple FBO render targets must have same format
(like for rendering to a float rgb buffer for positions and
a byte rgb buffer for normals/binormals is not possible in
one rendering pass)
:excl: Older GFX-cards dont have multiple rendertargets!
Implementation:
Method 1. Texture read in the Vertex Shader.
Step 1: Create FBO
Create an FBO and attach the texture that will hold the vertex data.
( see further down the text how to create )
Step 2: Create VBO
Create a vertex buffer object (VBO) holding texture coordinates for
referencing the FBO texture (e.g. a position VBO with
2 float-coordinates per vertex)
( see further down the text how to create )
Step 3: Render the FBO
( see further down for details )
Step 4: Render the VBO
Here the vertex coordinates from the VBO are
used to lookup the FBO texture containing the coordinates
Here an example for the vertex program code:
// vertex.position is our
// index to the real vertex array
!!ARBvp1.0\n
OPTION NV_vertex_program3;
PARAM mvp[4] = { state.matrix.mvp };
TEMP real_position;
TEX real_position, vertex.position, texture[0], 2D;
DP4 result.position.x, mvp[0], real_position;
DP4 result.position.y, mvp[1], real_position;
DP4 result.position.z, mvp[2], real_position;
DP4 result.position.w, mvp[3], real_position;
END\n;
Allowed texture formats for using a texture in the
vertex shader:
Nvidia Documentation said:
GLuint vertex_texture;
glGenTextures(1, &vertex_texture);
glBindTexture(GL_TEXTURE_2D, vertex_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_FLOAT32_ATI, width, height, 0,GL_LUMINANCE, GL_FLOAT, data);
Method 2. Copy to Pixel Buffer Object (PBO).
Step 1: Create a VBO as pixel buffer object:
Here a sample:
GLuint vbo_points_handle; glGenBuffersARB(1, &vbo_vertices_handle); glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, vbo_vertices_handle); glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, vbo_points.size()*4*sizeof(float),NULL, GL_DYNAMIC_DRAW_ARB );
Step 2: Create a FBO.
Multiple render targets can be helpful for writing
vertex/normal/binormal at the same time.
Here an example to create an FBO:
GLuint fb_handle; glGenFramebuffersEXT(1,&fb_handle); fbo_tex_vertices = NewFloatTex(tex_width,tex_height,0); fbo_tex_normals = NewFloatTex(tex_width,tex_height,0);
Here an example to create a float texture:
GLuint NewFloatTex(int width,int height,char* buffer,bool alpha=true)
{
GLuint type = GL_TEXTURE_2D; // alternative: GL_TEXTURE_RECTANGLE_ARB;
GLuint tex_handle;
glGenTextures (1, &tex_handle);
glBindTexture(type,tex_handle);
// set texture parameters
glTexParameteri(type, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(type, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// define texture with floating point format
GLuint format0 = GL_RGB_FLOAT32_ATI;
GLuint format1 = GL_FLOAT_RGB32_NV;
GLuint format2 = GL_RGB32F_ARB;
GLuint iformat = GL_RGB;
if (alpha)
{
format0 = GL_RGBA_FLOAT32_ATI;
format1 = GL_FLOAT_RGBA32_NV;
format2 = GL_RGBA32F_ARB;
iformat = GL_RGBA;
}
glTexImage2D(type,0,format0,width,height,0,iformat,GL_FLOAT,buffer);
// ATI format supported ?
if (glGetError() != GL_NO_ERROR)
{
glTexImage2D(type,0,format1,width,height,0,iformat,GL_FLOAT,buffer);
// NVidia format supported ?
if (glGetError() != GL_NO_ERROR)
glTexImage2D(type,0,format2,width,height,0,iformat,GL_FLOAT,buffer);
}
glBindTexture(type,0);
return tex_handle;
}
:excl: Rect textures can be used for GPGPU but not
for copying FBO -> PBO !! Only GL_TEXTURE_2D
:excl: Even if an RGB texture is created, it may be RGBA internally
=> slow glReadPixels if RGB is the destination format due to format conversion
Step 3: Render FBO
The input textures contain the necessary data
(vertex position etc) to compute the outputs.
Example to bind the buffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fbo_handle);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_tex_vertices, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, fbo_tex_normals, 0);
GLenum dbuffers[] =
{GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
glDrawBuffers(2, dbuffers);
Example to render the buffer using a quad
glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glDisable(GL_CULL_FACE); glActiveTextureARB( GL_TEXTURE0_ARB ); glBindTexture(GL_TEXTURE_2D,tex_vertices); glActiveTextureARB( GL_TEXTURE1_ARB ); glBindTexture(GL_TEXTURE_2D,tex_normals); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0.0,tex_width,0.0,tex_height); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); glViewport(0,0,tex_width,tex_height); glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE); glBegin(GL_QUADS); glColor3f(1,1,1); glMultiTexCoord2f( GL_TEXTURE0, 0.0, 0.0); glVertex2f(0, 0); glMultiTexCoord2f( GL_TEXTURE0, 1.0, 0.0); glVertex2f(tex_width,0); glMultiTexCoord2f( GL_TEXTURE0, 1.0, 1.0); glVertex2f(tex_width, tex_height); glMultiTexCoord2f( GL_TEXTURE0, 0.0, 1.0); glVertex2f(0, tex_height); glEnd(); // ---> Insert Code to copy FBO to PBO here <--- // glViewport(viewport[0],viewport[1],viewport[2],viewport[3]); glDrawBuffer(GL_BACK); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glEnable(GL_CULL_FACE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW);
:excl: gluOrtho2D is necessary ! If missing, glReadPixels wont work
:excl: glClampColorARB is only necessary in case of drawing other
than by gl_FragData[0..n] in the shader, to allow unclamped color values
To write to multiple targets, here an
example Fragment Shader (GLSL):
//uniform sampler2DRect texPoints; example for a rect-texture
//uniform sampler2D texColors; example for a normal texture
//varying vec2 textureCoord;
void main(void)
{
// vec4 vertex = texture2DRect(texPoints,textureCoord) ;
// vec4 color = texture2D(texPoints,textureCoord) ;
gl_FragData[0] = vec4 (0.0 , 1.0 , 0.0 , 1.0) ;
gl_FragData[1] = vec4 (1.0 , 1.0 , 0.0 , 1.0) ;
}
Step 4: Copy from FBO to PBO
Example:
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, vbo_vertices_handle); glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_FLOAT, 0); glReadBuffer(GL_COLOR_ATTACHMENT1_EXT); glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, vbo_normals_handle); glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_FLOAT, 0); glReadBuffer(GL_NONE); glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0 );
( of course vbo_vertices.size() == tex_width * tex_height )
:excl:
If glReadPixels is too slow, different formats
(like RGBA->RGB) might be a problem, since
simple copy doesnt work!
Step 5: Render VBO as usual:
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo_vertices_handle); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer ( 4, GL_FLOAT,4*sizeof(float), (char *) 0); glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo_normals_handle); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, 4*sizeof(float), (char *) 0 ); glDrawArrays( GL_TRIANGLES, 0,vbo_vertices.size() ); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
References
http://oss.sgi.com/p...ffer_object.txt
http://developer.nvi...x_textures.html
http://wiki.delphigl...p/GLSL_Partikel (german)
http://www.mathemati...al.html#arrays3
http://download.deve...es/samples.html


This topic is locked









