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