PDA

View Full Version : How can I know which polygons have been rasterized



lordmule
03-21-2009, 08:07 AM
Hi everyone,
I am trying to work out which geometry actually makes the contribution to the final rendered image...for every frame. To be specific, I want to know from all the quads/triangles sent to OpenGL, which ones have actually made a pixel contribution.

I proposed to number (glPushName) every primitive and use selection/feedback, but that would be rather horrid. Performing ray to scene intersection tests seems like the next best thing. Knowing full well that I can't get access to the internals of the rasterisation stage (I believe DirectX 11 allows you to), how could I go about the task in the most effective way?


btw I am using:
OpenGL version string: 2.0 ATI-1.5.36 on OSX (ATI 1600x mobility).

ZbuffeR
03-21-2009, 09:04 AM
What about occlusion queries ?

Ysaneya
03-21-2009, 04:47 PM
Occ queries will give you the amount of visible pixels, but not the IDs of the triangles.

I'd approach the problem by assigning a unique color to each triangle from its ID (possibly in a separate buffer with ARB_draw_buffers in FBOs) and reading this buffer back (if you need the results on the cpu) with_ARB_pixel_buffer_object for best performance, but even this may be too slow depending on what you're trying to do.

Y.

zed
03-21-2009, 09:47 PM
occlusion querys give the amount of pixels rendered (which is usually a lot higher than visible pixels)
the color method will work

though u prolly dont want to know how many triangles drawn but how many pixels rendered
one way to do this is with the stencil buffer
eg
set it to incriment with each pixel passing the test
at the end of the scene draw a fullscreen primitive with a shader that sets the color depending on the value in the stencil buffer

lordmule
03-23-2009, 01:13 AM
assigning a unique color to each triangle from its ID

Yes! I cannot believe its been 4 years since I used that trick.
Speed of readback is not a great issue.

On the note of performance, I looked into ARB_pixel_buffer_object.

Asynchronous glReadPixels: If an application needs to read back a
number of images and process them with the CPU
is it be safe to assume that any singular and sequentially dependent render and readback operations, bear no performance gain over glReadPixels().


though u prolly dont want to know how many triangles drawn but how many pixels rendered

i want to know which triangles drawn, even if they contribute one pixel to the final image. I think the pixel count for primitives will become an issue later, when the number of pixels for primitive are lower than 6. Right now, I want to know if the pixel count per primitive is > 0. Good suggestion with the stencil otherwise.

Thanks for the help everyone. I'll see how it goes.

lordmule
03-30-2009, 12:31 AM
A pointer for those who follow this. I am not sure why, but reading back GL_FLOAT with glReadPixels does not give the correct value.

I rendered a 0.5 red triangle and the value returned in the pixel space is 0.501961

If you use R = 1.0f then you get 1.0f, for other values it doesn't seem to work. From the glReadPixels man page, there should be no conversion process when using float. nevertheless something goes wrong.

I disabled lighting, color material, smooth shading (using FLAT), normals, cleared color,depth buffers, using a 0,0,0,0 clearcolor.




unsigned char colors[3*(facets+1)] = {0};

// distribute over 3 colours as one number
int pi = 255*255*255 / (facets+1);
int cval;
for (i = 0; i < facets; i++)
{
cval = pi * (i+1);
// shift 8 bits
cval = cval << 8;
memcpy(colors + 3*i, &amp;cval, 3);
}


// disable any lights, smoothness, materials etc
glClearColor(0,0,0,0);

// render here using:
glColorubv(colors + 3*current_facet);

// swapbuffers

glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glReadPixels(0,0,width,height, GL_RGB, GL_UNSIGNED_BYTE, pixels);

int visible[facets] = {0};

for ( y ... )
for (x ...)
if (pixel is black) continue;

for each color used C
if (visible[C]) break;
if pixel color is one of those used
{
visible[C] = 1;
break;
}




well this pseudo-C should be enough, it works wonderfully. The point is GL_FLOAT pixmaps beware!

OSX 10.5 Leopard, Xcode 3.1.2
OpenGL vendor string: ATI Technologies Inc.
OpenGL renderer string: ATI Radeon X1600 OpenGL Engine
OpenGL version string: 2.0 ATI-1.5.36

Dan Bartlett
03-30-2009, 01:43 AM
0.501961 is approximately 128/255, this is because the values you can represent with an unsigned byte lie between 0 and 255, therefore 0 is mapped to 0.0, and 255 is mapped to 1.0 (not 256 because cannot fit into 1 byte).

see section 2.1.5 of OpenGL 3.1 spec (Fixed point data conversions).

lordmule
03-30-2009, 02:57 AM
Thanks for that, an informative read.

I completely forgot that I specified a the pixel attributes to be 8 bits wide per channel to begin with. Of course there will be a downsampling, it was silly of me to think I can get more accuracy using floats. Bah! binary is good enough, even if I can only get 255^3 unique IDs out of it :P

Ilian Dinev
03-30-2009, 07:57 PM
That would be 2^32 unique IDs :). Alpha is also written (though I don't know what fixed-func writes there, I'm staying in shader-land).

lordmule
04-01-2009, 09:57 PM
changed the assignment of colours to triangles starting from white and changing a decent amount between adjacent polygons. Black is the clearcolor indicating no hit.

As is for future reference:


unsigned int cval = 256*256*256;

for each polygon:
cval -= 100; // MAX encodable 256^3/100
r = (cval & 16711680) >> 16;
g = (cval & 65280) >> 8;
b = (cval & 255);
glColor3ub(r,g,b);

// normal, vertex etc..



for looking up after readback of rendered frame:



unsigned int tfs = 256*256*256-1;
int polygon_visible [ num_polygons ] = {0};
char polygon_is_visible [ num_polygons ] = {0};

for each pixel:
pf = pixel color (unsigned byte)
unsigned int col = (pf[0] << 16) + (pf[1] << 8) + pf[2];
int polygonid = (tfs - col)/100;

if ( polygon_is_visible[ polygonid ] )
continue;

polygon_visible[ polygonid ] += 1;

if ( polygon_visible[ polygonid ] > MIN_PIXEL_FOR_VISIBLE )
polygon_is_visible[ polygonid ] = 1;




I found that having one pixel visible was not so good, so a threshold makes it better for performance (if you are post-processing this info).

Dj3hut1
04-05-2009, 12:57 AM
Hello,

why don't you use an occlusion query for each individual triangle?
For example :

for each triangle
{
glBeginQuery( GL_SAMPLES_PASSED, qids[triagle] );
glBegin( GL_TRIANGLE );
triangle vertices
glEnd();
glEndQuery( GL_SAMPLES_PASSED );
}

for each triangle
{
samples = 0;
glGetQueryObjectuiv( qids[triangle], GL_QUERY_RESULT, &amp;samples );

if ( samples > 0 )
-> triangle is visible
}


P.S. of course the triangles should be rendered into the depth buffer in the first pass, and in the second pass you should do the occlusion queries