How to tell if a 3D point will be hidden

Started by
11 comments, last by BigEfromTheVillages 10 years, 3 months ago

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??

Thanks in advance

Advertisement

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.

Thanks for your reply

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?

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.

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,

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?

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?

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.

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);
}

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.

This topic is closed to new replies.

Advertisement