How to tell if a 3D point will be hidden

Recommended Posts

I want to number vertices of a model only if that vertex will be visible once the complete model is rendered. I need to turn off the depth buffer to insure that the number text will not be obscured by adjacent objects, so i need to know in advance if the position of the vertex is hidden.

My plan is to render the model, then go back over each vertex (could be thousands) to see if it is visible, if so, turn off the depth buffer and label the vertex using outlined fonts.

Any suggestions on how to accomplish this??

Share on other sites
JohnnyCode    1046

there is not trivial way to find out what parts of object are visible. The most viable solution, in case you do not need to know this information at the CPU, is to render the model with stencil operation ZPASS STENCILPASS and setting stencil refference. In this case, after the object is rendered, all pixels that passed z test will write the stencil reference value you picked to the stencil buffer. This will effectively create a mask of pixels that object was visible at.

In case you need this information at CPU. All I can think off is to detect at CPU the front facing triangles and examine their verticies toward depth buffer.

Share on other sites

The stencil buffer sounds like a plan if i understand it correctly. I could render each polygon with a different reference number, then when i want to check for numbering of that polygon, i would query the stencil buffer ( i assume using some kind of glRasterPos routine) at the position i want to place the number. If the reference number matches the reference number for that polygon, then that location is visible.

Is that correct?

Share on other sites
Samith    2460

EDIT: Did not realize this was the OpenGL forum... for anyone interested the OpenGL equivalent would be glBeginQuery with GL_SAMPLES_PASSED.

Sounds like you could use the Direct3D query interface with D3D11_QUERY_OCCLUSION for this. Render your object the first time, then for each vert in the model create an occlusion query object and render a point at that vert's position. If any samples of that tiny triangle pass the depth and stencil test, you'll hear about it in the query results, and you'll know that vert was visible. I've never tried doing thousands of occlusion queries, though, so this might not be a very practical solution.

Edited by Samith

Share on other sites
JohnnyCode    1046

yes, you could identify every triangle as unique and sample from stencil texture to check for its 3 verticies, even all on cpu side. But remember that stencil buffer can be at most 8 bits wide, so you would only have 256 identities available. Better approach, in case you are into the information at CPU, would be to render triangle identificator to 32 bit texture. The identificator would have to be a per vertex unique information though, for you to establish.

I have adviced you with stencil buffer in case you needed visibility definition informative for gpu, not cpu. in case of cpu, u'd rather use texture and sample triangles if so. But maybe a pure CPU solution would be more suficient, after the depth of scene is fully constructed,

Share on other sites

So if i understand this correctly, i should render the scene to a 32 bit texture of the same resolution as the screen. Then query the texture to see if a vertex passes. I assume the "identificator" would be the color i set for each vertex. What would be the best way to query a texture?

Share on other sites

I tried using the occlusions, but i seem to be missing something. I started with the " simple occlusion query demo" from gamedev. I draw a crude sphere with 20 vertices, then do a query.

#define NUM_VERT 20
GLuint oq_sphere,oq_verts[NUM_VERT];

glGenQueriesARB(NUM_VERT, oq_verts);

... drawing the sphere
glBegin(GL_TRIANGLES);
for (i = 0; i < 20; i++) {
glBeginQueryARB(GL_SAMPLES_PASSED_ARB, oq_verts[i]);
glVertex3fv(&vdata[tindices[i][0]][0]);
glVertex3fv(&vdata[tindices[i][1]][0]);
glVertex3fv(&vdata[tindices[i][2]][0]);
glEndQueryARB(GL_SAMPLES_PASSED_ARB);
}
glEnd();

... then getting results after second rendering of sphere
GLuint vert_samples[NUM_VERT];
for(int i=0; i<NUM_VERT; i++)
{
do {
glGetQueryObjectivARB(oq_verts[i], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
} while (!available);
glGetQueryObjectuivARB(oq_verts[i], GL_QUERY_RESULT_ARB, &vert_samples[i]);
}



The problem is, all queries come back with the number 4294967295. What gives?

Edited by BigEfromTheVillages

Share on other sites
richardurich    1352

4294967295 is -1 (32-bit).

Is your variable named available also -1? The only valid return values for that call are GL_TRUE (1) and GL_FALSE (0), so -1 means you're doing something causing undefined behavior.

Are you creating an OpenGL 3.3 or later context?

As a warning, I'm not sure using occlusion queries is going to scale to thousands of queries per frame anyways. You could theoretically render the scene using unique colors, then you can tell if a vertex is visible if the pixel is the right color. You might look at different picking techniques to see if you can use any others for what you're trying to do.

Share on other sites
Samith    2460

Oops, didn't realize this post was in the OpenGL forum!! I came from the "New Content" page. My bad. Looks like you managed to find the equivalent OpenGL interface, though.

I'm not 100% sure what's wrong with your code, being that it's OpenGL, but my guess would be that you're putting the glBeginQuery and glEndQuery calls inside the glBegin/glEnd. No draw call actually gets made when you call glVertex3fv, so the query doesn't have anything to query. Also, with what you've written it looks like you're trying to query the number of samples that got draw for each triangle in the sphere, which I don't think is what you originally wanted to do. I would try something more like this:

#define NUM_VERT 20
GLUint oq_verts[NUM_VERT];

glGenQueriesARB(NUM_VERT, oq_verts);

// render the sphere normally first, however you like
DrawSphere();

// now query each vertex by attempting to draw a single point at that
// vertex's location. if any samples pass, then that vert is visible
// note that any verts obscured by the object itself will have zero samples
// that pass. this may or may not be what you intended! also, if your depth
// compare function is "less" then you may have to scooch your verts closer to
// the camera a little bit
for (int i = 0; i < NUM_VERT; i++) {
glBeginQueryARB(GL_SAMPLES_PASSED_ARB, oq_verts[i]);
glBegin(GL_POINTS);
glVertex3fv(&vdata[i]);
glEnd();
glEndQueryARB(GL_SAMPLES_PASSED_ARB);
}


Share on other sites
JohnnyCode    1046

up to optimization point of what we have adviced you with:

queriing all vertcies transformed to screen space, than sampling the 32 bit texture at that position to see if the vertex id (color?) is the same as the sampled texture pixel, is much the same as simply querring depth buffer to see if transformed vertex z is less. the solution is no worse, but is no better while- it occupies the color output of the scene prepass, that might be used for something else.

You should also consider, that, if your mesh is convex- meaning a front facing triangle cannot be occluded by other front facing triangle, you could simply find out on CPU all front facing triangles and consder their verticies visible right away.

Share on other sites

So i want to try the occlusion method. My program uses OpenGL without the glut routines. So i added the headers and libraries from the game_dev example to my program. But when i try to generate the queries with a call to:  glGenQueriesARB() I get -

First-chance exception at 0x00000000 in ePost.exe: 0xC0000005: Access violation at location 0x0000000000000000.

Maybe i am not initiating the glut libraries and routines correctly.

The game-dev sample is below. The question is, which of these do i need to call before beginning the queries? Right now i am not calling any of them.

	glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB );
glutInitWindowSize(512, 512);
glutCreateWindow("ARB_occlusion_query example");

glut_helpers_initialize();

glutDisplayFunc(display);
glutMainLoop();
glh_init_extensions("GL_ARB_occlusion_query ")


Share on other sites
Samith    2460

which of these do i need to call before beginning the queries? Right now i am not calling any of them.

glh_init_extensions is probably what you need to be calling, so that your function pointers get set up properly. Otherwise your glGenQueriesARB is just a null pointer.

However, the query interface has been core since OpenGL 1.5, so you don't need to be using any extensions. You can use glGenQueries() et al. without the ARB and you'll avoid having to initialize any extensions.

Share on other sites

Thank yo to everyone for their help. As you can tell, this is not my area of expertise. I have OpenGL version 4.4, so i should have what i need, I don't keep up on opengl as much as i should, so i am sure i have some extraneous files included, so any advice would be appreciated. I am running on a 64 bit machine, and this is a 64 bit application.

Right now the include files i am using are:

#include <gl/glew.h>
#include <gl/gl.h>
#include <gl/glu.h>
#define GL_GLEXT_PROTOTYPES
#include <gl/glext.h>

And i am using the following libraries: (i'm sure i have more referenced than i need)

binlib.lib
libifcoremd.lib
libifportmd.lib
opengl32.lib
glu32.lib
htmlhelp.lib
winmm.lib
iphlpapi.lib
ws2_32.lib
glut32.lib
odbc32.lib
odbccp32.lib
glew32.lib
glew32s.lib

I get no unsatisfied externals and everything compiles fine,
However, when i try to call glGenQuieries
GLuint nodeQuiery[8],elemQuery[6];
void COpenGL::SetUpOcclusion()
{
glGenQueries(8, nodeQuiery);
glGenQueries(6, elemQuery);
}
i get:
First-chance exception at 0x00000000 in ePost.exe: 0xC0000005: Access violation at location 0x0000000000000000.

I apparently am missing something, but i don't know what.
Edited by BigEfromTheVillages