Vertex rendering information

I need to do some operations on update that rely on the vertices of a mesh. I need to know which vertices are currently inside the camera frustum i.e. being rendered.

So far I’ve come up with per vertex checking, by getting it’s WorldToScreen coordinates with the current camera and checking if it’s within the screen boundaries.

But there’s gotta be a better way!

Any thoughts?

did you see this?

is that what you were looking for?

Hi Jordi, that’s more or less what I’m doing. In that code planes are used to tell whether the vertices (points) are inside the frustum. Instead of using planes I’m checking if the vertices’ screen coordinates are within the screen. I don’t actually need to perform culling, but to tell if a vertex is visible.

I’ve seen that there [scene graphs][1] are used for this purpose.

But I as I don’t need culling, I wonder if I can get which vertices were rendered in the last frame, I don’t know if I can ask that to the GPU somehow as this is performed by the rendering pipeline. Or output it with a shader… ?

Anyways, I’m totally overthinking this… :blush:
[1]: http://en.wikipedia.org/wiki/Scene_graph

Hi @chuckleplant, I don’t have a direct solution to your problem. One zippier option would be to create a shader that accepts a list of coordinates and the current camera info … and does the testing for you. It’ll be a big performance boost compared to doing the calculations on the CPU. This has been on my mind for a little while now. I’ll try to set aside some time on the weekend, will definitely ping ya.

That sounds awesome, though I still need that info on cpu side, is there a way to get output from the shaders? Also there would need to be a way of identifying the vertices.

Anyways do tell me what you find out! :smiley:

@chuckleplant, ja, that’d be the idea. in a nutshell: send the coordinates as values in a floating point FBO texture and then have the shader write boolean values back to the FBO, which would then be processed by your software (on the CPU side). this shader would be purely for doing the calculations – you would never see or display its output on screen. this is slightly different from the way you might typically use a shader (to draw points or process pixels).

one quick note that this is relatively inefficient, since it’s doing some matrix math and matrix inversion per point you are projecting – inspecting it:

//----------------------------------------
ofVec3f ofCamera::screenToWorld(ofVec3f ScreenXYZ, ofRectangle viewport) const {

	//convert from screen to camera
	ofVec3f CameraXYZ;
	CameraXYZ.x = 2.0f * (ScreenXYZ.x - viewport.x) / viewport.width - 1.0f;
	CameraXYZ.y = 1.0f - 2.0f *(ScreenXYZ.y - viewport.y) / viewport.height;
	CameraXYZ.z = ScreenXYZ.z;

	//get inverse camera matrix
	ofMatrix4x4 inverseCamera;
	inverseCamera.makeInvertOf(getModelViewProjectionMatrix(viewport));

	//convert camera to world
	return CameraXYZ * inverseCamera;

}

getModelViewProjectionMatrix(viewport) = ofMatrix4x4 * ofMatrix4x4 operation and
makeInvertOf is a matrix inverse.

imagine you are doing that per point, it’s kinda heavy / not very efficient!

In the past, I’ve grabbed the interior of this function to get that inverseCamera matrix and just used it per point, which is pretty fast. If you want to see an example, I’m happy to post.

1 Like

That’s a good tip, Zach!

Hrm, moving this calculation into a shader is creating unexpected results!

Why would multiplying the position by the model view projection matrix on the CPU would be different from doing that calculation in a shader?

#version 120

uniform sampler2DRect pointsTexture;
uniform vec4 viewport;
uniform mat4 mvMatrix;

varying vec4 texCoord0;

void main(){
	
    vec4 pos = texture2DRect( pointsTexture, texCoord0.xy );
    
    pos = mvMatrix * vec4( pos.xyz, 1.0f );

    vec3 screenPos;
    screenPos.x = (( pos.x + 1.0f ) / 2.0f ) * 1024.0f; 
    screenPos.y = (( 1.0f - pos.y ) / 2.0f ) * 384.0f; 
    screenPos.z = pos.z;

I happened to notice that if I send a rotation matrix instead of the MVP matrix, the shader produces the same coordinates as the calculation on the CPU.

ofMatrix4x4 modelViewMat;
modelViewMat.makeRotationMatrix( 120, ofVec3f(0.5, 1, 0.3) );

And here’s the calculation I’m doing on the CPU, for comparison

ofRect viewport = ofGetCurrentViewport();
ofMatrix4x4 modelViewMat = cam.getModelViewProjectionMatrix( viewport );
ofPoint testPt = ofPoint( ofGetWidth()/2, ofGetHeight()/2, -100 );
testPt = testPt * modelViewMat;

Oh, must be the difference between how matrices are structured in OpenGL versus OF

ofMatrix4x4
[0] [1] [2] [3]
[4] [5] [6] [7]
[8] [9] [10] [11]
[12] [13] [14] [15]

openGL
[0] [4] [8] [12]
[1] [5] [9] [13]
[2] [6] [10] [14]
[3] [7] [11] [15]

but you solve that by changing the order of multiplication which you are already doing. what kind of texture are you using? it might be that you are loosing resolution when passing the points in the texture?

hi arturo. i’m pretty sure it’s something on the matrix math side of things. when i disable this line from the shader

pos = vec3(mvMatrix * vec4(pos, 1.0f));

and replace it with this (transposed) matrix multiplication math, it works.

float d = 1.0f / (mvMatrix[0][3] * pos.x + mvMatrix[1][3] * pos.y + mvMatrix[2][3] * pos.z + mvMatrix[3][3]) ;
	
pos = vec3( (mvMatrix[0][0]*pos.x + mvMatrix[1][0]*pos.y + mvMatrix[2][0]*pos.z + mvMatrix[3][0])*d,
	                 (mvMatrix[0][1]*pos.x + mvMatrix[1][1]*pos.y + mvMatrix[2][1]*pos.z + mvMatrix[3][1])*d,
	                 (mvMatrix[0][2]*pos.x + mvMatrix[1][2]*pos.y + mvMatrix[2][2]*pos.z + mvMatrix[3][2])*d ) ;

the FBO is of type GL_RGBA32F_ARB and I’m using ofFloatImage and ofFloatPixels throughout.

thanks!

@chuckleplant here’s a demo of using a shader for testing. i’m not sure if it’s worth all the effort, unless that is you have some more complicated testing to do (i’m planning to add some billboarding calculations down the road).

from my comparisons between CPU and GPU approaches, each frame saved a few ms, but in the end i couldn’t actually discern much of a difference in the overall frame rate.

anyway, enjoy!

1 Like

Thanks a lot @mantissa! That’s a really useful example. Good to know OF matrices are transposed with respect to GLSL matrices.

Could it be that retrieving the vertex info when coming back from the shader is still quite heavy to do on CPU side? I also get almost the same time results from both methods.

Please correct me if I’m wrong. The vertex shader receives all vertices in our scene, and only those inside the viewing frustum make it to the fragment shader. If so, if we could just identify the vertices in the fragment shader we would know which ones are on screen, is there a way to do this? (This wouldn’t be for culling, as the render would have already happenned, but to acquire the rendered vertices)

Maybe sending vertex identifyers, from cpu, so we can know which ones are inside the frustum when we come back.

Anyways thanks for the gist! Really cool stuff!

Ja, the example utilizes an 32 bit floating point RGBA FBO, so it’s reading 4x more info than really necessary. Plus reading pixels from an FBO is a slow process to begin with. The shader really only needs to send back a boolean value – draw or don’t draw (now it’s sending the screen pos and 1.0 if it’s on screen and 0.5 if it’s not). I tried to get the example to work with a single float FBO (tried using both luminance and alpha) but OpenGL kept spitting out errors at me. I imagine this might save a teeny bit more time.

The vertex shader doesn’t do anything really, all the calculations are done in the fragment shader. I think I get what you’re saying … just sending the IDs of the verts that fall into the viewport …that could be another good approach.