Alexander Miroch
Alexander Miroch

Reputation: 101

Background image move OpenGL ES2

I'm trying to get my 2D-background image moving. In the fututre it will be implemented as automatic movement (looks like camera follow some object). A typical example - angry birds game. Camera follows the bird during attack.

Currently, I just change the values in setLookAtM(). Here is the code:

public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);

    GLES20.glDisable(GLES20.GL_DEPTH_TEST); 
    GLES20.glEnable(GLES20.GL_BLEND);
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA,GLES20.GL_ONE_MINUS_SRC_ALPHA);

    // background
   bg = new BackGround(mActivityContext);

}

public void onDrawFrame(GL10 unused) {
    // Redraw background color
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    Matrix.setLookAtM(mVMatrix, 0, -1f, 0f, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    Matrix.setIdentityM(mTrMatrix, 0);

    bg.draw(mMVPMatrix);
}

public void onSurfaceChanged(GL10 unused, int width, int height) {
    GLES20.glViewport(0, 0, width , height );

    float ratio = (float) width / height;
    Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}


class BackGround {

    private FloatBuffer vertexBuffer;
    private ShortBuffer drawListBuffer;

    static final int COORDS_PER_VERTEX = 3;
    static float squareCoords[] = { -15.5f,  15.5f, 0.0f,   // top left
    -15.5f, -15.5f, 0.0f,   // bottom left
    15.5f, -15.5f, 0.0f,   // bottom right
    15.5f,  15.5f, 0.0f }; // top right

    int mProgram;
    int mPositionHandle;

    private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
    private final String vertexShaderCode = "attribute vec2 a_TexCoordinate;" +
    "varying vec2 v_TexCoordinate;" +
    "uniform mat4 uMVPMatrix;" +
    "attribute vec4 vPosition;" +
    "void main() {" +
    "  gl_Position = uMVPMatrix * vPosition;" +
    "v_TexCoordinate = a_TexCoordinate;" +
    "}";

    private final String fragmentShaderCode =
    "precision mediump float;" +
    "uniform vec4 vColor;" +
    "uniform sampler2D u_Texture;" +
    "varying vec2 v_TexCoordinate;" +
    "void main() {" +
    "gl_FragColor = ( texture2D(u_Texture, v_TexCoordinate));" +
    "}";

    public BackGround(final Context context) {
        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(squareCoords);
        vertexBuffer.position(0);

        mActivityContext = context;

        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        final float[] cubeTextureCoordinateData = {
            -15.5f,  15.5f,
            -15.5f, -15.5f,
            15.5f, -15.5f,
            15.5f,  15.5f
        };

        mCubeTextureCoordinates =   
        ByteBuffer.allocateDirect(cubeTextureCoordinateData.length *  
        4).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);

        mProgram = GLES20.glCreateProgram();             
        GLES20.glAttachShader(mProgram, vertexShader);   
        GLES20.glAttachShader(mProgram, fragmentShader); 
        GLES20.glBindAttribLocation(mProgram, 0, "a_TexCoordinate");
        GLES20.glLinkProgram(mProgram);   

        // load background bitmap 256x256px              
        mTextureDataHandle = loadTexture(mActivityContext, R.drawable.mud);
    }

    public void draw(float[] mvpMatrix) {

        GLES20.glUseProgram(mProgram);
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
        GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);

        mTextureUniformHandle = GLES20.glGetAttribLocation(mProgram, "u_Texture");
        mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
        GLES20.glUniform1i(mTextureUniformHandle, 0);

        mCubeTextureCoordinates.position(0);
        GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize,
        GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
        GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);

        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
        GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}

The problem is that I don't know how to spread my background (256x256) over big area (not limited by screen size). currenty, texture is repeated in the screen edges only. And when im trying to move it (using SetLookAtm()) it moves ok, but leaves empty stripe behind:

Initial background image (bmp-reversed):

ab
cd

Background image at the screen:

--------
|ababab|
|cdcdcd|
|ababab|
|cdcdcd|
|ababab|
|cdcdcd|
--------

Background image after move (right ->)

--------
|  abab|
|  cdcd|
|  abab|
|  cdcd| 
|  abab|
|  cdcd|
--------

Direction (left, right, up, down) doesnt matter. It only has effect on which side stripe appears

Upvotes: 2

Views: 1464

Answers (1)

Rahul Banerjee
Rahul Banerjee

Reputation: 2363

Either:

A) Define your background rectangle so that it extends beyond the ends of the screen (and "scroll" the background by animating its position)

--------
|ababab|ababab
|cdcdcd|cdcdcd
|ababab|ababab
|cdcdcd|cdcdcd
|ababab|ababab
|cdcdcd|cdcdcd
--------

or:

B) Define the bg rectangle filling up the screen as before, but animate the texture coordinates to make it scroll. Eg: If your texcoords form a rectangle (0.00,0.00)->(1.00,1.00), then scroll the bg left by changing texcoords to be (0.05,0.00)->(1.05,1.00). Make sure you've set glTexParameteri as follows:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

Upvotes: 1

Related Questions