I get the yuv data from camera , and send them to opengl, then I use fragment shader to convert the data to RGBA format and show it on the screen. Everything goes well but when I use glReadPixels to get the RGBA data from framebuffer to int array, I get wrong data.
// I use VBO to draw
glBindBuffer(GL_ARRAY_BUFFER, squareVerticesBufferID);
glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(gvPositionHandle);
glBindBuffer(GL_ARRAY_BUFFER, textureVerticesBuferID);
glVertexAttribPointer(gvTextureHandle, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(gvTextureHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, squareVerticesIndexBufferID);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
// Then I use glReadPixels to read the RGBA data
unsigned char *returnDataPointer = (unsigned char*) malloc(width * height * 4);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, returnDataPointer);
Unfortunately I get wrong data, the last thousands elements in the array are 0s,the same code works well on ios, did I miss something?
I work on Android 4.0.3 and use OpenGL ES 2 from the NDK.
Related
I am trying to start with some basic operations with OpenCV and GLES20 on Android using C++.
I use CameraGLSurfaceView and its callback onCameraTexture(...) which calls I pass into my native library.
Calls are flowing well, I can read frame buffer to vector and pass it to texture without changing and it works as expected.
But when I try to work with pixels I get image broken.
My C++ code:
cv::Mat in(w,h,CV_8UC4);
cv::Mat out(w,h,CV_8UC4);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, in.data);
// following operations break image >>
cv::cvtColor(in, out, CV_RGBA2BGRA);
cv::flip(out, in, 0);
cv::cvtColor(in, out, CV_BGRA2RGBA);
// << prev operations break image
glBindTexture(GL_TEXTURE_2D, (GLuint) tex2);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
w,
h,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
out.ptr());
glBindTexture(GL_TEXTURE_2D, 0);
in.release();
out.release();
Without signed operations picture goes to texture and is displayed well.
I understand that my mistake is in converting formats between OpenGL and OpenCV.
How to convert formats properly?
It's my mistake with sizes of Mat:
cv::Mat in(w,h,CV_8UC4) should be cv::Mat in(h,w,CV_8UC4)
Im having trouble with texturing a cube with different textures per face. I can draw the cube with one texture on all the faces, but when I try use multiple textures it fails. The way im trying to do it is like so:
//my indexing array located in a header file
#define NUM_IMAGE_OBJECT_INDEX 36
static const unsigned short cubeIndices[NUM_IMAGE_OBJECT_INDEX] =
{
0, 1, 2, 2, 3, 0, // front
4, 5, 6, 6, 7, 4, // right
8, 9,10, 10,11, 8, // top
12,13,14, 14,15,12, // left
16,17,18, 18,19,16, // bottom
20,21,22, 22,23,20 // back
};
now in my rendering function, this currently works for drawing the cube with a single texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, iconTextureID);
glDrawElements(GL_TRIANGLES, NUM_IMAGE_OBJECT_INDEX, GL_UNSIGNED_SHORT, 0);
this does not work
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, iconTextureID);
glDrawElements(GL_TRIANGLES, NUM_IMAGE_OBJECT_INDEX, GL_UNSIGNED_SHORT, (const GLvoid*)&cubeIndices[0]);
which should equate to the same thing, from looking at some other examples. Ultimately I would like to be doing this something like this:
for(int i = 0; i < 6; i++){
iconTextureID = textureID[i];
glBindTexture(GL_TEXTURE_2D, iconTextureID);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const GLvoid*)&cubeIndices[i*6]); //index 0-5 use texture 1, 6-11 use texture 2, etc
}
does anyone know what could be wrong with this indexing? ive basically copy pasted this code from an android project (which works), currently trying to do this on ios.
In OpenGL ES 2.0, index data can come from either buffer objects or pointers to client memory. Your code is obviously using a buffer object. Though you don't show the creation of this buffer object, where you upload your client array of pointers, or where you call glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) before rendering with it. It must be there or your code would have crashed. When a buffer is bound to GL_ELEMENT_ARRAY_BUFFER, OpenGL expects the "pointer" given to glDrawElements to be a byte offset into the buffer object, not a client-memory pointer.
This is why copy-and-paste coding is a bad idea. Where you copied from was probably using client memory; you are not.
If you want your looping code to work, you need to do the pointer arithmetic yourself:
for(int i = 0; i < 6; i++)
{
iconTextureID = textureID[i];
glBindTexture(GL_TEXTURE_2D, iconTextureID);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(i * 6 * sizeof(GLushort)));
}
I have implemented the Bullet Physics engine into my android program with the NDK (I am using Vuforia's imagetarget example for android), and it is set up and working correctly, however I would like to render/draw my collision boxes/planes to see my rigid bodies (btRigidBody)/collision shapes (btCollisionShape), I'm positive this is possible but I can't find any tutorials on how to do it!
I have taken the hello world Bullet physics tutorial on their wiki page and modified it to apply the transformations from the falling physics body to a 3d object I have in opengl es 2.0 to view the collision bodies, here is the code I am using to render to object:
void drawRigidBody(btRigidBody* body,QCAR::Matrix44F modelViewMatrix, unsigned int textureID)
{
btTransform trans;
body->getMotionState()->getWorldTransform(trans);
LOG("sphere pos: (x %f , y %f, z %f)",trans.getOrigin().getX(),trans.getOrigin().getY(),trans.getOrigin().getZ());
float physicsMatrix[16];
trans.getOpenGLMatrix(physicsMatrix);
SampleUtils::scalePoseMatrix(kObjectScale, kObjectScale, kObjectScale,
&modelViewMatrix.data[0]);
QCAR::Matrix44F modelViewProjection, objectMatrix;
SampleUtils::multiplyMatrix(&modelViewMatrix.data[0], physicsMatrix, &objectMatrix.data[0]);
SampleUtils::multiplyMatrix(&projectionMatrix.data[0], &objectMatrix.data[0], &modelViewProjection.data[0]);
glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &signVerts[0]);
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &signNormals[0]);
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &signTexCoords[0]);
glEnableVertexAttribArray(vertexHandle);
glEnableVertexAttribArray(normalHandle);
glEnableVertexAttribArray(textureCoordHandle);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE,
(GLfloat*)&modelViewProjection.data[0] );
glDrawArrays(GL_TRIANGLES, 0, signNumVerts);
}
EDIT: looking at the code for btBoxShape i noticed you can grab the box vertices and normals:
btVector3** vertices= wallShape->getVertices();
btVector3**normals = wallShape->getNormals();
but you can't grab a list of indices to draw the vertex points in a certain order!
If I recall correctly, this is not the proper way to draw debug shapes in Bullet. Did you read the user manual (PDF), page 16?
You are supposed to implement your own debug drawer class which implements btIDebugDraw, and in this class you implement the drawLine method.
You pass this debug drawer to bullet with setDebugDrawer, and then enable it with world->getDebugDrawer->setDebugMode(debugMode);
To draw the world, call world->debugDrawWorld();
This then calls drawLine on your custom function numerous times until a wireframe model of the physics world has been drawn.
I load obj models and try to render them with OpenGL ES using Android NDK:
class ObjModel{
public:
ObjModel();
~ObjModel();
int numVertex, numNormal,numTexCoord, numTriange;
float *vertexArray;
float *normalArray;
float *texCoordArray;
unsigned short *indexArray;
void loadModel(string fileName);
};
model->loadModel(filename);
glVertexPointer(3, GL_FLOAT, 0, &(model->vertexArray[0]));
glNormalPointer(GL_FLOAT, 0, &(model->normalArray[0]));
glDrawElements(GL_TRIANGLES, model->numTriange, GL_UNSIGNED_SHORT,
&(model->indexArray[0]));
Model is not rendered fully, I see only part of it.
I checked the data in arrays and they are parsed properly. I think that the only issue might be with passing arguments. Am I doing it right?
Hope this helps! I think you are just missing the number 3!
glDrawElements(GL_TRIANGLES, 3 * model->numTriange, GL_UNSIGNED_SHORT,
&(model->indexArray[0]));
Using OpenGL 1.1 and the Matrix Palette extension. The issue I'm having, is that not every model being loaded needs to be animated, so I don't think that I need to enable those client states nor provide weights or weight index arrays. For example, I'm trying something like this during my drawing code...
glMatrixMode(GL_MATRIX_PALETTE_OES);
glBindBuffer(GL_ARRAY_BUFFER, dataBuffers[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dataBuffers[1]);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_WEIGHT_ARRAY_OES);
glEnableClientState(GL_MATRIX_INDEX_ARRAY_OES);
//Code to modify the palettes... works fine...
for(i = 0; i < mech.boneCount; ++i){
glCurrentPaletteMatrixOES(i);
glLoadPaletteFromModelViewMatrixOES();
GenerateBoneMatrixPalette(bones, i);
}
glVertexPointer(3, GL_FLOAT, sizeof(VertexData), (char*)(NULL + 0));
glNormalPointer(GL_FLOAT, sizeof(VertexData), (char*)(NULL + 12));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexData), (char*)(NULL + 24));
glWeightPointerOES(1, GL_FLOAT, sizeof(VertexData), (char*)(NULL + 28));
glMatrixIndexPointerOES(1, GL_UNSIGNED_BYTE, sizeof(VertexData), (char*)(NULL + 32));
glDrawElements(GL_TRIANGLES, mech.indexsize, GL_UNSIGNED_SHORT, (char*)(NULL + 0));
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_WEIGHT_ARRAY_OES);
glDisableClientState(GL_MATRIX_INDEX_ARRAY_OES);
glBindBuffer(GL_ARRAY_BUFFER, dataBuffers[2]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dataBuffers[3]);
glMatrixMode(GL_MODELVIEW);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
//pardon the hard 28 value here, it's the correct offset for this test
glVertexPointer(3, GL_FLOAT, 28, (char*)(NULL + 0));
glNormalPointer(GL_FLOAT, 28, (char*)(NULL + 12));
glColorPointer(4, GL_UNSIGNED_BYTE, 28, (char*)(NULL + 24));
glDrawElements(GL_TRIANGLES, indexsize, GL_UNSIGNED_SHORT, (char*)(NULL + 0));
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
But it is not working. The first section displays correctly but the second does not display at all. If I add an, what feels to be, unnecessary weight and weight index element to the second section modifying the stride as needed and not setting the matrix to the modelview... then it displays what I expect.
The test that feels the strangest, is if I do not enable the Matrix Palette extension at all and only draw the second part, it works just fine. However, just enabling the Matrix Palette extension causes the second section to not work at all, making it seem that I can not draw simply while the mode is set to the ModelView Matrix... though this seems somewhat unusual as the ModelView still absolutely is affected by transformations.
So... is it possible to switch to and draw while the ModelView is the current matrix while using this extension? Or must I make use/reuse a single palette to make it work.
I haven't found an OES matrix palette extension in the extension registry, but an ARB extension and suppose it works similar. In this extension, you have to enable GL_MATRIX_PALETTE and or GL_VERTEX_BLEND (with glEnable) to use matrix palette skinning and disable it to not use it.
But the glMatrixMode does't have anything to do with enabling or disabling it. It just selects the matrix to which matrix modification functions apply (like glLoadIdentity, glTranslate, ...).
EDIT: After googling this extension (I have no ES experience) I found, that you definitely have to enable GL_MATRIX_PALETTE_OES to use it (via glEnable) and then disable it again for your second part to not use it. As I've written above, glMatrixMode doesn't do what you thought it to.