Hi, Oliver

Quick and somewhat dirty how-to example attached. File contains custom 
osg::Drawable::DrawCallback with some utility stuff and comments on what is 
going on and how to use it.

shaders to test against view frustum is:
vertex:
[code]
#version 150 core

in vec3 InstancePosition;

uniform mat4 MVP;

out vec4 OrigPosition;
flat out int objectVisible;


void main(void) {

        OrigPosition = vec4(InstancePosition,1.0);

        vec4 SSpos = MVP * OrigPosition;
        bvec4 outside;

        outside.w = SSpos.w<0.0;
        SSpos = abs(SSpos);
        outside.xyz = greaterThan(SSpos.xyz,vec3(SSpos.w,SSpos.w,SSpos.w));
        objectVisible = int(!any(outside));

}
[/code]

geometry:
[code]
#version 150 core

layout(points) in;
layout(points, max_vertices = 1) out;

in vec4 OrigPosition[1];
flat in int objectVisible[1];

out vec4 CulledPosition;

void main() {

   /* only emit primitive if the object is visible */
   if ( objectVisible[0] == 1 )
   {
      CulledPosition = OrigPosition[0];
      EmitVertex();
      EndPrimitive();
   }
}
[/code]

You will need to add test against depth map to vertex shader and setup depth 
texture in code.

Cheers,
Sergey

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=35864#35864



#include <GL/gl.h>

#include <osg/Camera>
#include <osg/GL>
#include <osg/GLExtensions>
#include <osg/Drawable>

#include <osg/io_utils>

#include <iostream>
#define GL_TEXTURE_BUFFER_ARB             0x8C2A
#define GL_GEOMETRY_SHADER                0x8DD9


void checkLinkError(GLuint prog, osg::GL2Extensions& gl2_ext)
{
	GLint status;
	gl2_ext.glGetProgramiv(prog, GL_LINK_STATUS, &status);
	if (status != GL_TRUE) {
		std::cerr << "Failed to link shaders: " << std::endl;
		GLchar log[10000];
		gl2_ext.glGetProgramInfoLog(prog, 10000, NULL, log);
		std::cerr << log << std::endl;
	}
}

GLuint loadShaderFromFile(const char* filename, GLenum shaderType, osg::GL2Extensions& gl2_ext) {

	std::ifstream file(filename);
	if (!file) {
		std::cerr << "Unable to open file: " << filename << std::endl;
		return 0;
	}

	char line[256];
	std::string source;

	while (file) {
		file.getline(line, 256);
		source += line;
		source += '\n';
	}

    if (!file.eof()) {
    	std::cerr << "Error reading the file: " << filename << std::endl;
    	return 0;
    }

    GLuint shader = gl2_ext.glCreateShader(shaderType);
	gl2_ext.glShaderSource(shader, 1, (const GLchar**)&source, NULL);
	gl2_ext.glCompileShader(shader);

	GLint status;
	gl2_ext.glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
	if (status != GL_TRUE) {
		std::cerr << "Failed to compile shader: " << filename << std::endl;
		GLchar log[10000];
		gl2_ext.glGetShaderInfoLog(shader, 10000, NULL, log);
		std::cerr << log << std::endl;
		exit(1);
	}

	return shader;
}


class MyExtensions: public osg::Referenced
{
public:
		MyExtensions(unsigned int contextID)
		{
		    if (!osg::setGLExtensionFuncPtr(_glGenBuffers,  "glGenBuffers" ))
				if (!osg::setGLExtensionFuncPtr(_glGenBuffers,  "glGenBuffersARB" )) {std::cerr<<"glGenBuffers(ARB) not supported"<<std::endl;exit(0);}

		    if (!osg::setGLExtensionFuncPtr(_glBindBuffer,  "glBindBuffer" )) {std::cerr<<"glBindBuffer not supported"<<std::endl;exit(0);}

		    osg::setGLExtensionFuncPtr(_glBufferData,  "glBufferData" );

		    osg::setGLExtensionFuncPtr(_glMapBufferRange,  "glMapBufferRange" );

		    osg::setGLExtensionFuncPtr(_glUnmapBuffer,  "glUnmapBuffer" );

		    osg::setGLExtensionFuncPtr(_glGenVertexArrays,  "glGenVertexArrays" );

		    osg::setGLExtensionFuncPtr(_glBindVertexArray,  "glBindVertexArray" );

		    osg::setGLExtensionFuncPtr(_glEnableVertexAttribArray,  "glEnableVertexAttribArray" );

		    osg::setGLExtensionFuncPtr(_glVertexAttribPointer,  "glVertexAttribPointer" );

		    if (!osg::setGLExtensionFuncPtr(_glTexBuffer,  "glTexBuffer" ))
				osg::setGLExtensionFuncPtr(_glTexBuffer,  "glTexBufferARB" );

		    if (!osg::setGLExtensionFuncPtr(_glGenTextures,  "glGenTextures" ))
				osg::setGLExtensionFuncPtr(_glGenTextures,  "glGenTexturesEXT" );

		    if (!osg::setGLExtensionFuncPtr(_glBindTexture,  "glBindTexture" ))
				osg::setGLExtensionFuncPtr(_glBindTexture,  "glBindTextureEXT" );

		    if (!osg::setGLExtensionFuncPtr(_glGenQueries,  "glGenQueries" ))
				osg::setGLExtensionFuncPtr(_glGenQueries,  "glGenQueriesEXT" );

		    if (!osg::setGLExtensionFuncPtr(_glBindBufferBase,  "glBindBufferBase" ))
				osg::setGLExtensionFuncPtr(_glBindBufferBase,  "glBindBufferBaseEXT" );

		    if (!osg::setGLExtensionFuncPtr(_glBeginTransformFeedback,  "glBeginTransformFeedback" ))
				if (!osg::setGLExtensionFuncPtr(_glBeginTransformFeedback,  "glBeginTransformFeedbackEXT" )) {std::cerr<<"glBeginTransformFeedback(EXT) not supported"<<std::endl;exit(0);}

		    if (!osg::setGLExtensionFuncPtr(_glEndTransformFeedback,  "glEndTransformFeedback" ))
				if(!osg::setGLExtensionFuncPtr(_glEndTransformFeedback,  "glEndTransformFeedbackEXT" )) {std::cerr<<"glEndTransformFeedback(EXT) not supported"<<std::endl;exit(0);}

		    if (!osg::setGLExtensionFuncPtr(_glDrawArrays,  "glDrawArrays" ))
				osg::setGLExtensionFuncPtr(_glDrawArrays,  "glDrawArraysEXT" );

		    if (!osg::setGLExtensionFuncPtr(_glDrawArrays,  "glDrawArrays" ))
				osg::setGLExtensionFuncPtr(_glDrawArrays,  "glDrawArraysEXT" );

		    if (!osg::setGLExtensionFuncPtr(_glBeginQuery,  "glBeginQuery" ))
				if (!osg::setGLExtensionFuncPtr(_glBeginQuery,  "glBeginQueryARB" )) {std::cerr<<"glBeginQuery(ARB) not supported"<<std::endl;exit(0);}

		    if (!osg::setGLExtensionFuncPtr(_glEndQuery,  "glEndQuery" ))
				if (!osg::setGLExtensionFuncPtr(_glEndQuery,  "glEndQueryARB" )) {std::cerr<<"glEndQuery(ARB) not supported"<<std::endl;exit(0);}

		    osg::setGLExtensionFuncPtr(_glUseProgram,  "glUseProgram" );

		    if (!osg::setGLExtensionFuncPtr(_glGetQueryObjectiv,  "glGetQueryObjectiv" ))
				if (!osg::setGLExtensionFuncPtr(_glGetQueryObjectiv,  "glGetQueryObjectivARB" )) {std::cerr<<"glGetQueryObjectiv(ARB) not supported"<<std::endl;exit(0);}

		    if (!osg::setGLExtensionFuncPtr(_glUniform3f,  "glUniform3f" ))
				osg::setGLExtensionFuncPtr(_glUniform3f,  "glUniform3fARB" );

		    if (!osg::setGLExtensionFuncPtr(_glGetUniformLocation,  "glGetUniformLocation" ))
				osg::setGLExtensionFuncPtr(_glGetUniformLocation,  "glGetUniformLocationARB" );

		    if (!osg::setGLExtensionFuncPtr(_glTransformFeedbackVaryings,  "glTransformFeedbackVaryings" ))
				osg::setGLExtensionFuncPtr(_glTransformFeedbackVaryings,  "glTransformFeedbackVaryingsEXT" );

		    if (!osg::setGLExtensionFuncPtr(_glActiveTexture,  "glActiveTexture" ))
				osg::setGLExtensionFuncPtr(_glActiveTexture,  "glActiveTextureARB" );

		}
		void glGenBuffers(GLsizei n, GLuint *buffers){_glGenBuffers(n,buffers);};
		void glBindBuffer(GLenum a1, GLuint a2){_glBindBuffer(a1,a2);};
		void glBufferData(GLenum a1, GLsizeiptr a2, const GLvoid * a3, GLenum a4){_glBufferData(a1,a2,a3,a4);};
		GLvoid* glMapBufferRange(GLenum a1, GLintptr a2, GLsizeiptr a3, GLbitfield a4){return _glMapBufferRange(a1,a2,a3,a4);};
		GLboolean glUnmapBuffer(GLenum a1){return _glUnmapBuffer(a1);};
		void glGenVertexArrays(GLsizei a1, GLuint * a2){_glGenVertexArrays(a1,a2);};
		void glBindVertexArray(GLuint a1){_glBindVertexArray(a1);};
		void glEnableVertexAttribArray(GLuint a1){_glEnableVertexAttribArray(a1);};
		void glVertexAttribPointer(GLuint a1, GLint a2, GLenum a3, GLboolean a4, GLsizei a5, const GLvoid * a6){_glVertexAttribPointer(a1,a2,a3,a4,a5,a6);};
		void glTexBuffer(GLenum a1, GLenum a2, GLuint a3){_glTexBuffer(a1,a2,a3);};
		void glGenTextures(GLsizei a1, GLuint * a2){_glGenTextures(a1,a2);};
		void glBindTexture(GLenum a1, GLuint a2){_glBindTexture(a1,a2);};
		void glGenQueries(GLsizei a1, GLuint * a2){_glGenQueries(a1,a2);};
		void glBindBufferBase(GLenum a1, GLuint a2, GLuint a3){_glBindBufferBase(a1,a2,a3);};
		void glBeginTransformFeedback(GLenum a1){_glBeginTransformFeedback(a1);};
		void glEndTransformFeedback(){_glEndTransformFeedback();};
		void glDrawArrays(GLenum a1, GLint a2, GLsizei a3){_glDrawArrays(a1,a2,a3);};
		void glEndQuery(GLenum a1){_glEndQuery(a1);};
		void glBeginQuery(GLenum a1, GLuint a2){_glBeginQuery(a1, a2);};
		void glUseProgram(GLuint a1){_glUseProgram(a1);};
		void glGetQueryObjectiv(GLuint a1, GLenum a2, GLint * a3){_glGetQueryObjectiv(a1,a2,a3);};
		void glUniform3f(GLint a1, GLfloat a2, GLfloat a3, GLfloat a4){_glUniform3f(a1,a2,a3,a4);};
		GLint glGetUniformLocation(GLuint a1, const GLchar * a2){return _glGetUniformLocation(a1,a2);};
		void glTransformFeedbackVaryings(GLuint a1, GLsizei a2, const GLchar ** a3, GLenum a4){_glTransformFeedbackVaryings(a1,a2,a3,a4);};
		void glActiveTexture(GLenum a1){_glActiveTexture(a1);};



protected:

        typedef void (APIENTRY * GenBuffers)(GLsizei n, GLuint *buffers);
        typedef void (APIENTRY * BindBuffer)(GLenum, GLuint);
        typedef void (APIENTRY * BufferData)(GLenum, GLsizeiptr, const GLvoid *, GLenum);
        typedef GLvoid* (APIENTRY * MapBufferRange)(GLenum, GLintptr, GLsizeiptr, GLbitfield);
        typedef GLboolean (APIENTRY * UnmapBuffer)(GLenum);
        typedef void (APIENTRY * GenVertexArrays)(GLsizei, GLuint *);
        typedef void (APIENTRY * BindVertexArray)(GLuint);
        typedef void (APIENTRY * EnableVertexAttribArray)(GLuint);
        typedef void (APIENTRY * VertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
        typedef void (APIENTRY * TexBuffer)(GLenum, GLenum, GLuint);
        typedef void (APIENTRY * GenTextures)(GLsizei, GLuint *);
        typedef void (APIENTRY * BindTexture)(GLenum, GLuint);
        typedef void (APIENTRY * GenQueries)(GLsizei, GLuint *);
        typedef void (APIENTRY * BindBufferBase)(GLenum, GLuint, GLuint);
        typedef void (APIENTRY * BeginTransformFeedback)(GLenum);
        typedef void (APIENTRY * EndTransformFeedback)();
        typedef void (APIENTRY * DrawArrays)(GLenum, GLint, GLsizei);
        typedef void (APIENTRY * EndQuery)(GLenum);
        typedef void (APIENTRY * BeginQuery)(GLenum, GLuint);
        typedef void (APIENTRY * UseProgram)(GLuint);
        typedef void (APIENTRY * GetQueryObjectiv)(GLuint, GLenum, GLint *);
        typedef void (APIENTRY * Uniform3f)(GLint, GLfloat, GLfloat, GLfloat);
        typedef GLint (APIENTRY * GetUniformLocation)(GLuint, const GLchar *);
        typedef void (APIENTRY * TransformFeedbackVaryings)(GLuint, GLsizei, const GLchar **, GLenum);
	typedef void (APIENTRY * ActiveTexture)(GLenum);


        GenBuffers _glGenBuffers;
        BindBuffer _glBindBuffer;
        BufferData _glBufferData;
	MapBufferRange _glMapBufferRange;
	UnmapBuffer _glUnmapBuffer;
	GenVertexArrays _glGenVertexArrays;
	BindVertexArray _glBindVertexArray;
	EnableVertexAttribArray _glEnableVertexAttribArray;
	VertexAttribPointer _glVertexAttribPointer;
	TexBuffer _glTexBuffer;
	GenTextures _glGenTextures;
	BindTexture _glBindTexture;
	GenQueries _glGenQueries;
	BindBufferBase _glBindBufferBase;
	BeginTransformFeedback _glBeginTransformFeedback;
	EndTransformFeedback _glEndTransformFeedback;
	DrawArrays _glDrawArrays;
	EndQuery _glEndQuery;
	BeginQuery _glBeginQuery;
	UseProgram _glUseProgram;
	GetQueryObjectiv _glGetQueryObjectiv;
	Uniform3f _glUniform3f;
	GetUniformLocation _glGetUniformLocation;
	TransformFeedbackVaryings _glTransformFeedbackVaryings;
	ActiveTexture _glActiveTexture;
};

class TransformFeedbackDrawableCallback: public osg::Drawable::DrawCallback
{
public:
// vertex_pointer is assumed to be pointer to array of floats with 3 float per vertex : x,y,z
// count is number of vertices in vertex_pointer
	TransformFeedbackDrawableCallback(int _count, float* _vertex_pointer, std::string data_dir):count(_count), vertex_pointer(_vertex_pointer), initialized(false), dataDir(data_dir)
	{
	}

	void drawImplementation (osg::RenderInfo &renderinfo, const osg::Drawable *drawable) const
	{
		if (renderinfo.getContextID() != m_contextID)
		{
			ext = 0;
			gl2_ext = 0;
			initialized = false;
		}
		if (!ext) ext = new MyExtensions(renderinfo.getContextID());
		if (!gl2_ext) gl2_ext = new osg::GL2Extensions(renderinfo.getContextID());

		if (!initialized)
		{
			m_contextID = renderinfo.getContextID();
			initialized = true;
			cullVS = loadShaderFromFile(std::string(dataDir + "/shaders/cull.vs").c_str(), GL_VERTEX_SHADER,*gl2_ext.get());
			cullGS = loadShaderFromFile(std::string(dataDir + "/shaders/cull.gs").c_str(), GL_GEOMETRY_SHADER,*gl2_ext.get());

			cullPO = gl2_ext->glCreateProgram();
			gl2_ext->glAttachShader(cullPO, cullVS);
			gl2_ext->glAttachShader(cullPO, cullGS);
			// bind output varyings
			const char *vars[] = { "CulledPosition" };
			ext->glTransformFeedbackVaryings(cullPO, 1 /*0*/, vars, GL_INTERLEAVED_ATTRIBS);
			// bind vertex attributes
			gl2_ext->glBindAttribLocation(cullPO, 0, "InstancePosition");
			// link program
			gl2_ext->glLinkProgram(cullPO);
			checkLinkError(cullPO, *gl2_ext.get());

			ext->glGenBuffers(1, &tbo);//input tbo
			ext->glBindBuffer(GL_TEXTURE_BUFFER_ARB, tbo);
			ext->glBufferData(GL_TEXTURE_BUFFER_ARB, 3*count*sizeof(float), NULL, GL_STATIC_DRAW);

			//feed data
			float* instance = reinterpret_cast<float*>(ext->glMapBufferRange(GL_TEXTURE_BUFFER_ARB, 0, count*3*sizeof(float), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT /*| GL_MAP_UNSYNCHRONIZED_BIT*/));
			int size = count*3;
			for (int i=0; i<size; i++)
			{
				instance[i] = *vertex_pointer;
				vertex_pointer+=1;
			}
			ext->glUnmapBuffer(GL_TEXTURE_BUFFER_ARB);

			// create the vertex array for culling
			ext->glGenVertexArrays(1, &vertexArray);
			ext->glBindVertexArray(vertexArray);
			ext->glBindBuffer(GL_ARRAY_BUFFER, tbo);
			ext->glEnableVertexAttribArray(0);
			ext->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, (void*)0);

			// create the buffer texture for culled instance data
			ext->glGenBuffers(1, &result_tbo);
			ext->glBindBuffer(GL_TEXTURE_BUFFER_ARB, result_tbo);
			ext->glBufferData(GL_TEXTURE_BUFFER_ARB, sizeof(float)*4*count, NULL, GL_DYNAMIC_COPY);
			ext->glGenTextures(1, &tex);
			ext->glBindTexture(GL_TEXTURE_BUFFER_ARB, tex);
			ext->glTexBuffer(GL_TEXTURE_BUFFER_ARB, GL_RGBA32F, result_tbo);

// 			//create query object to retrieve culled primitive count
 			ext->glGenQueries(1, &query);
// 			ext->glGenQueries(1, &query_written);


		}

//		GLenum glError;

		// start culling phase by bounding the GPU program
		ext->glUseProgram(cullPO);
		// disable rasterization as we don't need it
		glEnable(GL_RASTERIZER_DISCARD); // you can move it to osg::StateSet on this drawable

		renderinfo.getState()->haveAppliedAttribute(osg::StateAttribute::PROGRAM);

		osg::Matrixf view,proj,MVP;
		view = renderinfo.getState()->getModelViewMatrix();
		proj = renderinfo.getState()->getProjectionMatrix();

		MVP = view * proj;
		gl2_ext->glUniformMatrix4fv(ext->glGetUniformLocation(cullPO, "MVP"), 1, GL_FALSE, MVP.ptr());

		ext->glBindVertexArray(vertexArray);
		ext->glEnableVertexAttribArray(0);
		// bind the texture buffer used as input later as the target for the transform feedback
		ext->glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, result_tbo);
		// bind the vertex array that contains the instance data array

		// start transform feedback
		ext->glBeginTransformFeedback(GL_POINTS);
		// query for generated primitive count

		ext->glBeginQuery(GL_PRIMITIVES_GENERATED, query);
//		ext->glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT, query_written);

		// draw the instance data as points
		ext->glDrawArrays(GL_POINTS, 0, count);
		ext->glEndQuery(GL_PRIMITIVES_GENERATED);
//		ext->glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT);

		ext->glEndTransformFeedback();

		glDisable(GL_RASTERIZER_DISCARD); // if you use osg::StateSet to set GL_RASTERIZER_DISCARD comment this line
		ext->glBindVertexArray(0);
//		ext->glUseProgram(0);


	};

	// next three methods MUST be called from thread that have valid opengl context (same context that this callback is initialized with)
	// f.e. you can modify callback to use them in next frame to get previous frame results writed to some storage
	// or have another drawcallback that uses them or texture generated by first one in same frame as they generated or whatever
	// make sure to have proper draw order so callback that do transform feedback called before one's that uses results
	// this functions returns stuff that represents results obtained from last draw call in this callback, previous results is lost.

	GLint getPrimivesCount(bool waitForQueryResult) // return -1 when query result not available yet
	{
		int ready = 0;
		if (waitForQueryResult)
		{
			while(true)// waiting for query result
			{
				ext->glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &ready);
				if (!ready) usleep(1);
				else break;
			}
		}
		else
		{
			ext->glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &ready);
			if (!ready) return -1;
		}
		GLint visibleCount = 0;
		ext->glGetQueryObjectiv(query, GL_QUERY_RESULT, visibleCount); //get number of primitives generated by geometry shader
		return visibleCount;
	}
	
	float* getResultArrayPointer() // pointer to array of floats returned, vertex represented as 4 continuous float values in order x,y,z,w..
	{
		ext->glBindBuffer(GL_TEXTURE_BUFFER_ARB, result_tbo);
		return reinterpret_cast<float*>(ext->glMapBuffer(GL_TEXTURE_BUFFER_ARB, GL_READ_ONLY));
	}
	void unmapBuffer() //call after you are done with using pointer obtained through getResultArrayPointer()
	{
		ext->glBindBuffer(GL_TEXTURE_BUFFER_ARB, result_tbo);
		ext->glUnmapBuffer(GL_TEXTURE_BUFFER_ARB);
	}


	GLuint cullVS;					// vertex shader for culling
	GLuint cullGS;					// geometry shader for culling
	GLuint cullPO;					// program object for culling

	mutable GLuint tbo;
	mutable GLuint result_tbo;
	mutable GLuint query;
	mutable GLuint query_written;

	mutable GLuint vertexArray;
	mutable GLuint tex;
	int count;
	mutable float* vertex_pointer;
	mutable bool initialized;

private:
	mutable osg::ref_ptr<MyExtensions> ext;
	mutable osg::ref_ptr<osg::GL2Extensions> gl2_ext;
	std::string dataDir;

};

// just some example of usage of results generated by previous callback (in this case it is number if vertices generated, and texture buffer object data):

class TransformFeedbackDrawResultDrawableCallback: public osg::Drawable::DrawCallback
{
public:
	TransformFeedbackDrawResultDrawableCallback(TransformFeedbackDrawableCallback* cb): m_cb(cb)
	{}
	void drawImplementation (osg::RenderInfo &renderinfo, const osg::Drawable *drawable) const
	{
		if (!m_cb->initialized)
			{std::cerr<<"transform feedback culling callback not initialized yet!!"<<std::endl;return;}
		if (!ext)
			ext = new MyExtensions(renderinfo.getContextID());

		int count = m_cb->getPrimivesCount(true);

		if (count)
		{
			ext->glActiveTexture(GL_TEXTURE4);
			ext->glBindTexture(GL_TEXTURE_BUFFER_ARB, m_cb->tex);
			ext->glActiveTexture(GL_TEXTURE0);
			// texture buffer object bound to texture unit 4 and used in shader attached to stateset of this drawable
			// number of vertices generated used to set number of instances of drawable
 			for (unsigned int j=0;j<drawable->asGeometry()->getNumPrimitiveSets();j++)
 				const_cast<osg::Drawable*>(drawable)->asGeometry()->getPrimitiveSet(j)->setNumInstances(m_cb->visibleCount);
			drawable->drawImplementation(renderinfo);
		}

	}
private:
	mutable osg::ref_ptr<MyExtensions> ext;
	TransformFeedbackDrawableCallback* m_cb;
};






_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to