Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

125 Neutral

About tau_neutrino

  • Rank

Personal Information

  • Interests
  1. Hello my fellow gamedevers,   I now feel much better about my "engine" (its my first `serious` work in OpenGl, but it is still a newbie stuff of course). So after I have successfully implemented VBO packed with vertices and colors and IBO, now I want to make it more robust and scalable.  I have a class called GlRenderBuffer which contains two buffers:  FloatBuffer for vertex data ShortBuffer for indices I do also have objects I call primitives. What I actually do is drawing a floor plan. So my primitives are walls, doors, etc. Each primitive can write itself into vertices and indices buffers.  So the design is pretty much straightforward: Load the scene from file, deserialize primitives, put them into buffers and render.  The problem: when I use single GlRenderBuffer everything works (all primitives are drawn), but if I use several such buffers only the first one is drawn.    GlRenderBuffer class public class GlRenderBuffer { public static final int SIZE_OF_FLOAT = Float.SIZE/Byte.SIZE; public static final int SIZE_OF_SHORT = Short.SIZE/Byte.SIZE; public static final int COORDS_PER_VERTEX = 3; public static final int COLORS_PER_VERTEX = 4; // RGB + A public static final int INDICES_BUFFER_SIZE_FACTOR = 4; // we allocate indices buffer 4 private static final int BUFFERS_COUNT = 1; private static final int STRIDE = (COORDS_PER_VERTEX + COLORS_PER_VERTEX) * SIZE_OF_FLOAT; private final FloatBuffer mVerticesBuffer; private final ShortBuffer mIndicesBuffer; private final int[] mVerticesBufferId = new int[BUFFERS_COUNT]; private final int[] mIndicesBufferId = new int[BUFFERS_COUNT]; public GlRenderBuffer(int verticesNum) { // device hardware's native byte order mVerticesBuffer = ByteBuffer.allocateDirect(verticesNum * (COORDS_PER_VERTEX + COLORS_PER_VERTEX)* SIZE_OF_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); mIndicesBuffer = ByteBuffer.allocateDirect(verticesNum * INDICES_BUFFER_SIZE_FACTOR * SIZE_OF_SHORT).order(ByteOrder.nativeOrder()).asShortBuffer(); allocateGpuBuffers(); } public boolean put(IFloorPlanPrimitive primitive) { int neededVertexDataSize = primitive.getVerticesDataSize(); // in bytes int neededIndexDataSize = primitive.getIndicesDataSize(); // this too // Ensure there is enough space for new primitive final boolean verticesBufferHasEnoughSpace = mVerticesBuffer.remaining() >= neededVertexDataSize / SIZE_OF_FLOAT; final boolean indicesBufferHasEnoughSpace = mIndicesBuffer.remaining() >= neededIndexDataSize / SIZE_OF_SHORT; if (!verticesBufferHasEnoughSpace || !indicesBufferHasEnoughSpace) { return false; } primitive.putVertices(mVerticesBuffer); primitive.putIndices(mIndicesBuffer); primitive.setContainingBuffer(this); return true; } public void copyToGpu(FloatBuffer vertices) { GLES20.glGenBuffers(BUFFERS_COUNT, mVerticesBufferId, 0); // Copy vertices data into GPU memory GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesBufferId[0]); // TODO: Should be vertices.limit() instead of vertices.capacity() GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertices.capacity() * SIZE_OF_FLOAT, vertices, GLES20.GL_DYNAMIC_DRAW); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); } public void copyToGpu(ShortBuffer indices) { GLES20.glGenBuffers(BUFFERS_COUNT, mIndicesBufferId, 0); // Copy vertices data into GPU memory GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]); // TODO: Should be vertices.limit() instead of vertices.capacity() GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indices.capacity() * SIZE_OF_SHORT, indices, GLES20.GL_STATIC_DRAW); GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); } public void updateSingleObject(IFloorPlanPrimitive primitive) { primitive.updateBuffer(mVerticesBuffer); // offset in bytes int primitiveBufferOffset = primitive.getVertexBufferPosition(); int vertexOffset = primitiveBufferOffset * SIZE_OF_FLOAT; int previousBufferPosition = mVerticesBuffer.position(); mVerticesBuffer.position(primitiveBufferOffset); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesBufferId[0]); GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexOffset, primitive.getVerticesDataSize(), mVerticesBuffer); mVerticesBuffer.position(previousBufferPosition); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); } public void render(float[] mvpMatrix) { GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesBufferId[0]); int positionAttributeHandle = GLES20.glGetAttribLocation(AppSettings.oglProgram, ShaderHelper.POSITION_ATTRIBUTE); GLES20.glVertexAttribPointer(positionAttributeHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, STRIDE, 0); GLES20.glEnableVertexAttribArray(positionAttributeHandle); int colorAttributeHandle = GLES20.glGetAttribLocation(AppSettings.oglProgram, ShaderHelper.COLOR_ATTRIBUTE); GLES20.glVertexAttribPointer(colorAttributeHandle, COLORS_PER_VERTEX, GLES20.GL_FLOAT, false, STRIDE, COORDS_PER_VERTEX * SIZE_OF_FLOAT); GLES20.glEnableVertexAttribArray(colorAttributeHandle); GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]); // get handle to shape's transformation matrix int mvpMatrixHandle = GLES20.glGetUniformLocation(AppSettings.oglProgram, ShaderHelper.MVP_MATRIX); // Pass the projection and view transformation to the shader GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0); GLES20.glDrawElements( GLES20.GL_TRIANGLES, mIndicesBuffer.position(), GLES20.GL_UNSIGNED_SHORT, 0); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); } public void allocateGpuBuffers() { int vertexPos = mVerticesBuffer.position(); int indexPos = mIndicesBuffer.position(); // Reset positions of buffers for consuming in GL mVerticesBuffer.position(0); mIndicesBuffer.position(0); mVerticesBuffer.limit(mVerticesBuffer.capacity()); mIndicesBuffer.limit(mIndicesBuffer.capacity()); copyToGpu(mVerticesBuffer); copyToGpu(mIndicesBuffer); mVerticesBuffer.position(vertexPos); mIndicesBuffer.position(indexPos); } public void deallocateGpuBuffers() { if (mVerticesBufferId[0] > 0) { GLES20.glDeleteBuffers(mVerticesBufferId.length, mVerticesBufferId, 0); mVerticesBufferId[0] = 0; } if (mIndicesBufferId[0] > 0) { GLES20.glDeleteBuffers(mIndicesBufferId.length, mIndicesBufferId, 0); mIndicesBufferId[0] = 0; } } public void refreshGpuBuffers() { deallocateGpuBuffers(); allocateGpuBuffers(); } @Override public void finalize() { deallocateGpuBuffers(); } public void clear() { mVerticesBuffer.clear(); mIndicesBuffer.clear(); // TODO: more actions to come } } This code is used in Renderer class of GlSurfaceView. Since when single buffer is used this works, I suppose GlRenderBuffer class I wrote is incorrect. If Renderer's code is also desired please let me know and I'll add it.   Thank you in advance,   Greg
  2. tau_neutrino

    Android, OpenGl ES, panning + zooming

    Found the bug. I should remove the scale factor from calculation of dx/dy because in world coordinates it is already been taken into account. Strange it is not introduced in the code here. I git-stashed the panning - related code and when pop it back it merged incorrectly.   So far so good.   Thanks for your help! I'll put the code of windowToWorld just for the record. Maybe it's buggy too. public void windowToWorld(int x, int y, PointF worldPoint) { final float WINDOW_Z_NEAR = 0.0f; final float WINDOW_Z_FAR = 1.0f; float rayStartPos[] = new float[4]; float rayEndPos[] = new float[4]; float modelView[] = new float[16]; int viewport[] = {0, 0, mViewPortWidth, mViewPortHeight}; // Model matrix is scale + rotation + translation Matrix.multiplyMM(modelView, 0, mViewMatrix, 0, mModelMatrix, 0); int windowX = x; int windowY = mViewPortHeight - y; int result = GLU.gluUnProject(windowX, windowY, WINDOW_Z_NEAR, modelView, 0, mProjectionMatrix, 0, viewport, 0, rayStartPos, 0); if (result == GL10.GL_TRUE) { rayStartPos[0] /= rayStartPos[3]; rayStartPos[1] /= rayStartPos[3]; rayStartPos[2] /= rayStartPos[3]; System.arraycopy(rayStartPos, 0, mRay, 0, 3); } result = GLU.gluUnProject(windowX, windowY, WINDOW_Z_FAR, modelView, 0, mProjectionMatrix, 0, viewport, 0, rayEndPos, 0); if (result == GL10.GL_TRUE) { rayEndPos[0] /= rayEndPos[3]; rayEndPos[1] /= rayEndPos[3]; rayEndPos[2] /= rayEndPos[3]; System.arraycopy(rayEndPos, 0, mRay, 3, 3); } worldPoint.x = mRay[0]; worldPoint.y = mRay[1]; } Although now I use only 2D, I'm planning to switch to 3D in the next release. That's why I use ray calculation.
  3. tau_neutrino

    Android, OpenGl ES, panning + zooming

    Hi,   Well scaling is pretty much straight-forward: private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); // Don't let the object get too small or too large. mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); Log.d("SCALE", Float.toString(mScaleFactor)); // Update scale mRenderer.setScale(mScaleFactor); requestRender(); return true; } } Renderer side of things: public void setScale(float scale) { mScale = scale; updateModelMatrix(); } And updateModelMatrix is the same as in first post.   If I neutralize the panning, scaling works perfectly. So the issue is still in panning I suppose.  If I try to pan with one finger (no scaling is activated) after scaled to factor of 2 or more, shaking starts again.
  4. tau_neutrino

    Android, OpenGl ES, panning + zooming

    Now to achieve zooming and panning at the same time I have removed the condition of: if (!mScaleDetector.isInProgress()) {   This basically works, but until scale factor of 2. Further scaling up will cause same effect of 'shaking' I described in 2). Maybe I'm doing it wrong way?
  5. tau_neutrino

    Android, OpenGl ES, panning + zooming

    Oh. Two things: 0) I cannot express the happiness and my gratitude. I invested 3 full days in debugging this and I'm now amazed... 1) ... amazed how dumb I am!    I'm sorry no other words. Thank you so much!!!   On a side note, do you have that zooming+panning code to learn from? Looks like I'm still amateur in this field.   Regards, Greg.
  6. Good day my fellow developers,   I'm a new here and this is my first post on GD. My background is 10 years of programming in different platforms and languages including C#, Java, Linux Kernel Dev, Java Card, ... Android is something new to me (4 months so far). Some month ago I started to use OpenGl ES.   So what I'm trying to write is OpenGl ES app which shows map. The map is rotated using magnetometer (map rotates in opposite direction of the device's rotation). For zooming I'm using ScaleGestureDetector and passing scale factor to Matrix.scaleM. My current problem is panning.    GlSurfaceView side: private void handlePanAndZoom(MotionEvent event) { int action = MotionEventCompat.getActionMasked(event); // Get the index of the pointer associated with the action. int index = MotionEventCompat.getActionIndex(event); int xPos = (int) MotionEventCompat.getX(event, index); int yPos = (int) MotionEventCompat.getY(event, index); mScaleDetector.onTouchEvent(event); switch (action) { case MotionEvent.ACTION_DOWN: mRenderer.handleStartPan(xPos, yPos); break; case MotionEvent.ACTION_MOVE: if (!mScaleDetector.isInProgress()) { mRenderer.handlePan(xPos, yPos); } break; } } Renderer side: private static final PointF mPanStart = new PointF(); public void handleStartPan(final int x, final int y) { runOnGlThread(new Runnable() { @Override public void run() { windowToWorld(x, y, mPanStart); } }); } private static final PointF mCurrentPan = new PointF(); public void handlePan(final int x, final int y) { runOnGlThread(new Runnable() { @Override public void run() { windowToWorld(x, y, mCurrentPan); float dx = mCurrentPan.x - mPanStart.x; float dy = mCurrentPan.y - mPanStart.y; mOffsetX += dx; mOffsetY += dy; updateModelMatrix(); mPanStart.set(mCurrentPan); } }); } windowToWorld function uses gluUnProject and I know it works because I'm using it for other tasks. updateModelMatrix() func: private void updateModelMatrix() { Matrix.setIdentityM(mScaleMatrix,0); Matrix.scaleM(mScaleMatrix, 0, mScale, mScale, mScale); Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, 1.0f); Matrix.setIdentityM(mTranslationMatrix,0); Matrix.translateM(mTranslationMatrix, 0, mOffsetX, mOffsetY, 0); // Model = Scale * Rotate * Translate Matrix.multiplyMM(mIntermediateMatrix, 0, mScaleMatrix, 0, mRotationMatrix, 0); Matrix.multiplyMM(mModelMatrix, 0, mIntermediateMatrix, 0, mTranslationMatrix, 0); } Same mModelMatrix is used in gluUnproject of windowToWorld function for point translation. So my problem two-fold: The panning occurs twice slower than the movement of finger on the device's screen At some point when panning continuously for a few seconds (making circles on screen, for example) the map starts to 'shake'. The amplitude of this shaking is getting bigger and bigger. Looks like some value adds up in handlePan iterations and causes this effect. Any idea why these happen? Thank you in advance, Greg. P.S> I didn't want to overwhelm the post with code, so I tried to put only relevant functions. Please let me know if there is anything missing to understand the question.
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!