I have this code that should move my circle( square):
float[] scratch = new float[16];
float[] move = new float[16];
Matrix.setIdentityM(move, 0);
Matrix.translateM(move, 0, 100, 100, 0);
Matrix.multiplyMM(scratch, 0, projectionMatrix, 0, move, 0);
mCircle.draw(scratch);
projectionMatrix is the camera:
Matrix.orthoM(projectionMatrix, 0, 0, width, height, 0, -1f, 1f);
But when I execute the code I get this:
Image
I followed the code from Android Developer.
precision highp float;
uniform float uRadius;
vec2 center = vec2(uRadius, uRadius);
vec2 coord = vec2(gl_FragCoord.x, 1080. - gl_FragCoord.y);
vec2 position = coord - center;
uniform vec4 uColor;
void main()
{
if (length(position) > uRadius) {
discard;
}
gl_FragColor = uColor;
}
--------------------------------
uniform mat4 uMatrix;
attribute vec4 aPosition;
void main()
{
gl_Position = uMatrix * aPosition;
}
My main loop:
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
float[] scratch = new float[16];
float[] move = new float[16];
Matrix.setIdentityM(move, 0);
Matrix.translateM(move, 0, 50, 50, 0);
Matrix.multiplyMM(scratch, 0, projectionMatrix, 0, move, 0);
mCircle.draw(scratch);
}
And circle draw functions is:
public void draw(float[] projectionMatrix) {
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
int mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
int mColorHandle = GLES20.glGetUniformLocation(mProgram, "uColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, mColor, 0);
int radiusHandle = GLES20.glGetUniformLocation(mProgram, "uRadius");
MyGLRenderer.checkGlError("glGetUniformLocation");
GLES20.glUniform1f(radiusHandle, mRadius);
// get handle to shape's transformation matrix
int mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, projectionMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
// Draw the square
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
After some hours I finally found the logical error in the fragment shader: the center of the circle was remaining the same, now I added 2 more uniforms for the offsets/position and it's working.
Related
I'm practicing in basic things in OpenGL ES2.0 using this 2d tutorial:
http://androidblog.reindustries.com/a-real-opengl-es-2-0-2d-tutorial-part-2/
Basically it just draws a rect with a texture.
Now I would like to draw multiple rects in one glDrawElements() call on different positions but with the same texture. So I add more items to the vertices and indices arrays. However texture coords (uvs array) are the same for every rect and there's no sense to stretch it by copying the same values. Can I somehow reuse it or perhaps set it as a constant somewhere inside the shader code?
Vertex shader:
uniform mat4 uMVPMatrix;
attribute vec4 vPosition;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() {
gl_Position = uMVPMatrix * vPosition;
v_texCoord = a_texCoord;
}
Fragment shader:
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D s_texture;
void main() {
gl_FragColor = texture2D( s_texture, v_texCoord );
}
Arrays (used in buffers):
vertices = new float[]
{ 10.0f, 200f, 0.0f,
10.0f, 100f, 0.0f,
100f, 100f, 0.0f,
100f, 200f, 0.0f,
};
indices = new short[] {0, 1, 2, 0, 2, 3};
uvs = new float[] {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
Render code:
private void Render() {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
int mPositionHandle = GLES20.glGetAttribLocation(program, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
int mTexCoordLoc = GLES20.glGetAttribLocation(program, "a_texCoord" );
GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, uvBuffer);
int mtrxhandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
int mSamplerLoc = GLES20.glGetUniformLocation (program, "s_texture" );
GLES20.glUniform1i ( mSamplerLoc, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
}
I am new to opengl es on android and learning opengl by doing some examples. I am using two program to draw 3 objects. The following code loads the texture and draws a square. But it is appearing as a black square instead of applying the texture to the body.
my fragment-shader code
precision mediump float;
uniform sampler2D u_Texture;
varying vec2 v_TexCoordinate;
void main() {
gl_FragColor = texture2D(u_Texture, v_TexCoordinate);
}
my vertex-shader code
attribute vec2 a_TexCoordinate;
varying vec2 v_TexCoordinate;
attribute vec4 a_Position;
uniform mat4 u_Matrix;
void main() {
gl_Position = u_Matrix * a_Position;
v_TexCoordinate = a_TexCoordinate;
}
my object vertex buffer
float [] vBufferFloat = new float[] {
-0.2f, -0.2f, 1f,
0.2f, -0.2f, 1f,
0.2f, 0.2f, 1f,
-0.2f, 0.2f, 1f,
-0.2f, -0.2f, 1f,
};
my texture buffer
float [] texCoordinate = new float[] {
-0.2f, -0.2f,
0.2f, -0.2f,
0.2f, 0.2f,
-0.2f, 0.2f,
-0.2f, -0.2f,
};
my onSurfaceCreated && onDrawFrame code
public void onSurfaceCreated() {
cloudRendereProgram = ShaderHelper.createProgram(mContext, R.raw.sky_texture_vertex_shader, R.raw.sky_texture_fragment_shader);
cloudTextureId = Utils.loadTexture(mContext, com.elpis.gamecontroller.R.drawable.cloud);
aTextureLocation = GLES20.glGetAttribLocation(cloudRendereProgram, "a_TexCoordinate");
uMatrixLocation = GLES20.glGetUniformLocation(cloudRendereProgram, "u_Matrix");
aPositionLocation = GLES20.glGetAttribLocation(cloudRendereProgram, "a_Position");
uTextureLocation = GLES20.glGetUniformLocation(cloudRendereProgram, "u_Texture");
}
public void onDrawFrame() {
float [] mVMatrix = new float[16];
GLES20.glUseProgram(cloudRendereProgram);
GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 0, vBuff.buffer);
GLES20.glEnableVertexAttribArray(aPositionLocation);
Matrix.multiplyMM(mVMatrix, 0, modelMatrix, 0, projectionMatrix, 0);
GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, mVMatrix, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.cloudTextureId);
GLES20.glUniform1i(uTextureLocation, 0);
GLES20.glVertexAttribPointer(aTextureLocation, 2, GLES20.GL_FLOAT, false, 0, texBuff.buffer);
GLES20.glEnableVertexAttribArray(aTextureLocation);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 5);
}
and my texture loader helper code
public static int loadTexture(Context ctx, int resId) {
final int [] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] == 0)
return 0;
final BitmapFactory.Options options = new Options();
options.inScaled = false;
final Bitmap imgTexture = BitmapFactory.decodeResource(ctx.getResources(), resId);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, imgTexture, 0);
imgTexture.recycle();
return textureHandle[0];
}
When I run the android application all I see is a black square instead of seeing a texture of cloud. So, I would appreciate if anyone point me in the right direction.
Two quick questions; Is it valid to create multiple opengl program objects with different shaders and run them concurrently?
[UPDATE]
The problem was on the onDrawFrame(). I had to use vBuff.buffer.position(0) and texBuff.buffer.position(0) to be able to draw the texture correctly.
public void onDrawFrame() {
float [] mVMatrix = new float[16];
GLES20.glUseProgram(cloudRendereProgram);
// FIX
vBuff.buffer.position(0);
texBuff.buffer.position(0);
// END FIX
GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 0, vBuff.buffer);
GLES20.glEnableVertexAttribArray(aPositionLocation);
Matrix.multiplyMM(mVMatrix, 0, modelMatrix, 0, projectionMatrix, 0);
GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, mVMatrix, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.cloudTextureId);
GLES20.glUniform1i(uTextureLocation, 0);
GLES20.glVertexAttribPointer(aTextureLocation, 2, GLES20.GL_FLOAT, false, 0, texBuff.buffer);
GLES20.glEnableVertexAttribArray(aTextureLocation);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 5);
}
You're not calling glEnableVertexAttribArray for your texture coords. Add this line to your onDrawFrame():
GLES20.glEnableVertexAttribArray(aTextureLocation);
Call glGenerateMipmap after you upload the texture texImage2D() in your loadTexture() function, to make sure all mip-map levels are valid:
glGenerateMipmap(GLES20.GL_TEXTURE_2D);
Also, move these calls from your surfaceCreated() function to the start of drawFrame():
aTextureLocation = GLES20.glGetAttribLocation(cloudRendereProgram, "a_TexCoordinate");
uMatrixLocation = GLES20.glGetUniformLocation(cloudRendereProgram, "u_Matrix");
aPositionLocation = GLES20.glGetAttribLocation(cloudRendereProgram, "a_Position");
uTextureLocation = GLES20.glGetUniformLocation(cloudRendereProgram, "u_Texture");
(it could be that these variables are not bound properly or the GL context is not yet properly set up in surfaceCreated())
A debugging tip for OpenGLES. Add this function to your code (it's from the Android OpenGLES samples):
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
you can call it after each OpenGLES call, and pass in a String that can be whatever debugging message you want. If anything goes wrong then you'll get an exception instead of just silent failure which will leave you scratching your head trying to figure out what went wrong. Make sure to remove it from your final build to avoid force closes.
I'm trying to apply projection and camera views, but I am not getting the wanted result. The drawn triangle still gets deformed when I rotate my device from portrait to landscape mode. This is the draw() method from my Triangle class:
public void draw(float[] mvpMatrix) {
int vertexCount = 3;
int vertexStride = 3 * COORDS_PER_VERTEX;
int mMVPMatrixHandle;
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// Pass the projection and view transformation to the shader
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
I don't know why it doesn't work, there is also my onDrawFrame() and onSurfaceChanged() methods from the Renderer class:
private float[] mProjectionMatrix = new float[16]
private float[] mViewMatrix = new float[16];
private float[] mMVPMatrix = new float[16];
public void onDrawFrame(GL10 unused) {
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// Draw shape
mTriangle.draw(mMVPMatrix);
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// this projection matrix is applied to object coordinates
// in the onDrawFrame() method
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
Some code is missing, here is what should be added :
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition * uMVPMatrix;" +
"}";
Edit Code added, please see below
Edit 2 - Screenshots from device included at bottom along with explanation
Edit 3 - New code added
I have 2 classes, a rendered and a custom 'quad' class.
I have these declared at class level in my renderer class:
final float[] mMVPMatrix = new float[16];
final float[] mProjMatrix = new float[16];
final float[] mVMatrix = new float[16];
And in my onSurfaceChanged method I have:
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
and....
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
myBitmap = BitmapFactory.decodeResource(curView.getResources(), R.drawable.box);
//Create new Dot objects
dot1 = new Quad();
dot1.setTexture(curView, myBitmap);
dot1.setSize(300,187); //These numbers are the size but are redundant/not used at the moment.
myBitmap.recycle();
//Set colour to black
GLES20.glClearColor(0, 0, 0, 1);
}
And finally from this class, onDrawFrame:
#Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
//Paint the screen the colour defined in onSurfaceCreated
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Set the camera position (View matrix) so looking from the front
Matrix.setLookAtM(mVMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Combine
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
dot1.rotateQuad(0,0,45, mMVPMatrix); //x,y,angle and matrix passed in
}
Then, in my quad class:
This declared at class level:
private float[] mRotationMatrix = new float[16];
private final float[] mMVPMatrix = new float[16];
private final float[] mProjMatrix = new float[16];
private final float[] mVMatrix = new float[16];
private int mMVPMatrixHandle;
private int mPositionHandle;
private int mRotationHandle;
//Create our vertex shader
String strVShader =
"uniform mat4 uMVPMatrix;" +
"uniform mat4 uRotate;" +
"attribute vec4 a_position;\n"+
"attribute vec2 a_texCoords;" +
"varying vec2 v_texCoords;" +
"void main()\n" +
"{\n" +
// "gl_Position = a_position * uRotate;\n"+
// "gl_Position = uRotate * a_position;\n"+
"gl_Position = a_position * uMVPMatrix;\n"+
// "gl_Position = uMVPMatrix * a_position;\n"+
"v_texCoords = a_texCoords;" +
"}";
//Fragment shader
String strFShader =
"precision mediump float;" +
"varying vec2 v_texCoords;" +
"uniform sampler2D u_baseMap;" +
"void main()" +
"{" +
"gl_FragColor = texture2D(u_baseMap, v_texCoords);" +
"}";
Then method for setting texture (don't think this is relevant to this problem though!!)
public void setTexture(GLSurfaceView view, Bitmap imgTexture){
this.imgTexture=imgTexture;
iProgId = Utils.LoadProgram(strVShader, strFShader);
iBaseMap = GLES20.glGetUniformLocation(iProgId, "u_baseMap");
iPosition = GLES20.glGetAttribLocation(iProgId, "a_position");
iTexCoords = GLES20.glGetAttribLocation(iProgId, "a_texCoords");
texID = Utils.LoadTexture(view, imgTexture);
}
And finally, my 'rotateQuad' method (which currently is supposed to draw and rotate the quad).
public void rotateQuad(float x, float y, int angle, float[] mvpMatrix){
Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, 0.1f);
// Matrix.translateM(mRotationMatrix, 0, 0, 0, 0); //Removed temporarily
// Combine the rotation matrix with the projection and camera view
Matrix.multiplyMM(mvpMatrix, 0, mRotationMatrix, 0, mvpMatrix, 0);
float[] vertices = {
-.5f,.5f,0, 0,0,
.5f,.5f,0, 1,0,
-.5f,-.5f,0, 0,1,
.5f,-.5f,0, 1,1
};
vertexBuf = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexBuf.put(vertices).position(0);
//Bind the correct texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texID);
//Use program
GLES20.glUseProgram(iProgId);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(iProgId, "uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
// get handle to shape's rotation matrix
mRotationHandle = GLES20.glGetUniformLocation(iProgId, "uRotate");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mRotationHandle, 1, false, mRotationMatrix, 0);
//Set starting position for vertices
vertexBuf.position(0);
//Specify attributes for vertex
GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 5 * 4, vertexBuf);
//Enable attribute for position
GLES20.glEnableVertexAttribArray(iPosition);
//Set starting position for texture
vertexBuf.position(3);
//Specify attributes for vertex
GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 5 * 4, vertexBuf);
//Enable attribute for texture
GLES20.glEnableVertexAttribArray(iTexCoords);
//Draw it
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
for Edit 2.
This is my quad as drawn in the center of the screen. No rotation.
This is the same quad rotated at +45 Degrees with the code "gl_Position = a_position * uMVPMatrix;" + in my vertex shader (it's from a different project now so the shader variable is a_position and not vPosition), it's looks correct!
However, this is the same quad rotated at +45 Degrees with the 2 shader variables switched (so they read "gl_Position = uMVPMatrix * a_position;" - as you can see, it's not quite right.
Also just a side note, you can't see it here as the quare is symetrical, but each method also rotates in the opposite direction to the other....
Any help appreciated.
It's really impossible to tell because we don't know what you are passing to these two variables.
OpenGL is column-major format, so if vPosition is in fact a vector, and uMVPMatrix is a matrix, then the first option is correct, if this is in your shader.
If this is not in your shader but in your program code, then there is not enough information.
If you are using the first option but getting unexpected results, you are likely not computing your matrix properly or not passing the correct vertices.
Normally in the vertex shader you should multiple the positions by the MVP, that is
gl_Position = uMVPMatrix *vPosition;
When you change the order this should work...
Thanks to all for the help.
I managed to track down the problem (For the most part). I will show what I did.
It was the following line:
Matrix.multiplyMM(mvpMatrix, 0, mvpMatrix, 0, mRotationMatrix, 0);
As you can see I was multiplying the matrices and storing them back into one that I was using in the multiplication.
So I created a new matrix called mvpMatrix2 and stored the results in that. Then passed that to my vertex shader.
//Multiply matrices
Matrix.multiplyMM(mvpMatrix2, 0, mvpMatrix, 0, mRotationMatrix, 0);
//get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(iProgId, "uMVPMatrix");
//Give to vertex shader variable
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix2, 0);
After applying this, there is no distortion (And also, with regards to my other question here Using Matrix. Rotate in OpenGL ES 2.0 I am able to translate the centre of the quad). I say 'for the most part' because however, when I rotate it, it rotates backwards (so if I say rotate +45 degrees, (Clockwise), it actually rotates the quad by -45 degrees (Anit-clockwise).
But hopefully, this will help anyone who has a similar problem in the future.
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
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);