I'm currently developing a software that involves drawing 3d scene with OpenGL (ES) 2.0. I want users to be able to pick objects from the scene by clicking (or touching) on the screen. My current approach is to render the scene to an off-screen buffer and deduce the clicked object by reading color values from that buffer. While this worked on PC with regular OpenGL, it fails on N900. Most times glReadPixels segfaults when reading a single pixel, and when it doesn't, it returns invalid values. And if I read the whole buffer, I get strange, striped results, where each row of pixels is accompanied with three empty rows.
If anyone has any idea why the above is happening, or has suggestions how to implement better picking, then any help would be appreciated. I have attached an example code to this email which demonstrates my problem. The example code uses Qt and QGLFramebufferObject, but I had similar results with 'handmade' FBO too. The code is also available from <http://zokier.net/stuff/fail.cpp> Also image of erroneous FBO is available at <http://zokier.net/stuff/fbo.png>, it should have a pinkish square in the middle, but it doesn't. /Torste Aikio ps. I am not very experienced with mailing lists, I hope this is the correct place to discuss this.
#ifdef USE_GLEW #include <GL/glew.h> #endif #include <QtOpenGL> #include <QDebug> #define FBO_SIZE_X 512 #define FBO_SIZE_Y 512 #define BUFFER_OFFSET(i) ((char *)NULL + (i)) #pragma pack(push, 1) struct Vertex { GLfloat x,y,z; }; #pragma pack(pop) class OGLWidget : public QGLWidget { public: OGLWidget(QWidget *parent = 0); ~OGLWidget(); void mouseDoubleClickEvent(QMouseEvent *); void initializeGL(); void paintGL(); private: void loadVBO(); void loadShaders(); void render(); QGLFramebufferObject *m_fbo; GLuint m_vertexCount; GLuint m_vertices; GLuint m_indices; GLuint m_shaderProg; GLuint m_shaderAr; }; OGLWidget::OGLWidget(QWidget *parent) : QGLWidget(parent) , m_fbo(NULL) { } OGLWidget::~OGLWidget() { delete m_fbo; glDeleteBuffers(1, &m_vertices); glDeleteBuffers(1, &m_indices); glDeleteProgram(m_shaderProg); } void OGLWidget::mouseDoubleClickEvent(QMouseEvent *event) { m_fbo->toImage().save("fbo.png", "PNG"); int fbox = (event->x() / (double)width()) * FBO_SIZE_X; int fboy = (event->y() / (double)height()) * FBO_SIZE_Y; qDebug() << "fbo coords:" << fbox << fboy; qDebug() << "screen coords:" << event->x() << event->y(); m_fbo->bind(); unsigned char color[4] = {0, 0, 0, 0}; //SEGFAULT happens here glReadPixels(fbox, fboy, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color); m_fbo->release(); qDebug() << "color (rgba):" << color[0] << color[1] << color[2] << color[3]; } void OGLWidget::initializeGL() { #ifdef USE_GLEW glewInit(); #endif m_fbo = new QGLFramebufferObject(FBO_SIZE_X, FBO_SIZE_Y); loadShaders(); loadVBO(); } void OGLWidget::loadVBO() { m_vertexCount = 6; Vertex vertices[] = { {-0.5, 0.5, 0.0}, { 0.5, 0.5, 0.0}, {-0.5, -0.5, 0.0}, { 0.5, -0.5, 0.0}}; GLushort indices[] = {2, 0, 1, 2, 1, 3}; glGenBuffers(1, &m_vertices); glBindBuffer(GL_ARRAY_BUFFER, m_vertices); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glGenBuffers(1, &m_indices); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STREAM_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } void OGLWidget::loadShaders() { const char *fragmentShSrc = "#version 100\n" "\n" "void main (void)\n" "{\n" " gl_FragColor = vec4(0.8, 0.2, 0.4, 1.0);\n" "}\n"; const char *vertexShSrc = "#version 100\n" "\n" "attribute vec3 position;\n" "uniform float ar;\n" "\n" "mat4 v_frustum(float angle_of_view,\n" " float aspect_ratio,\n" " float z_near,\n" " float z_far)\n" "{\n" " return mat4(\n" " vec4(1.0/tan(angle_of_view), 0.0, 0.0, 0.0),\n" " vec4(0.0, aspect_ratio/tan(angle_of_view), 0.0, 0.0),\n" " vec4(0.0, 0.0, (z_far+z_near)/(z_far-z_near), 1.0),\n" " vec4(0.0, 0.0, -2.0*z_far*z_near/(z_far-z_near), 0.0));\n" "}\n" "\n" "void main(void)\n" "{\n" " vec4 d = mat4(vec4(1, 0, 0, 0),\n" " vec4(0, 1, 0, 0),\n" " vec4(0, 0, 1, 0),\n" " vec4(0, 0, 2, 1)) * vec4(position, 1.0);\n" " gl_Position = v_frustum(radians(30.0), ar, 0.1, 15.0) * d;\n" "}\n"; GLuint vertexSh = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexSh, 1, &vertexShSrc, NULL); glCompileShader(vertexSh); GLuint fragmentSh = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentSh, 1, &fragmentShSrc, NULL); glCompileShader(fragmentSh); m_shaderProg = glCreateProgram(); glAttachShader(m_shaderProg, vertexSh); glAttachShader(m_shaderProg, fragmentSh); glLinkProgram(m_shaderProg); glDeleteShader(vertexSh); glDeleteShader(fragmentSh); m_shaderAr = glGetUniformLocation(m_shaderProg, "ar"); } void OGLWidget::render() { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLuint position = glGetAttribLocation(m_shaderProg, "position"); glBindBuffer(GL_ARRAY_BUFFER, m_vertices); glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0)); glEnableVertexAttribArray(position); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices); glDrawElements(GL_TRIANGLES, m_vertexCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); glDisableVertexAttribArray(position); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } void OGLWidget::paintGL() { glUseProgram(m_shaderProg); glUniform1f(m_shaderAr, width()/(double)height()); m_fbo->bind(); glViewport(0, 0, FBO_SIZE_X, FBO_SIZE_Y); render(); m_fbo->release(); glViewport(0, 0, width(), height()); render(); } int main(int argc, char** argv) { QApplication app(argc, argv); OGLWidget w; w.show(); return app.exec(); }
_______________________________________________ maemo-developers mailing list maemo-developers@maemo.org https://lists.maemo.org/mailman/listinfo/maemo-developers