I'm trying to use the GL_TEXTURE1 texture unit to draw a simple shape. I know how to draw it using the standard GL_TEXTURE0, but when changing it something is not working.
I thought that from my code below, I just had to change the following:
glActiveTexture(GL_TEXTURE1);
glUniform1i(uTextureLocation, 1);
What I'm missing?
Code:
public class RendererClass implements Renderer {
Context context;
FloatBuffer verticesInBuffer;
int aPositionLocation;
int aTextureLocation;
int uTextureLocation;
int program;
public RendererClass(Context context){
this.context = context;
}
#Override
public void onSurfaceCreated(GL10 arg0, EGLConfig config) {
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
float[] vertices = {
-0.5f, 0.5f, 0.5f, 0.5f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, 0.0f, 0.0f, 0.0f
};
verticesInBuffer = ByteBuffer.allocateDirect(vertices.length*4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertices);
String vss = "attribute vec4 a_Position;" +
"attribute vec2 a_Texture;" +
"varying vec2 v_Texture;" +
"void main(){" +
" v_Texture = a_Texture;" +
" gl_Position = a_Position;" +
"}";
String fss = "precision mediump float;" +
"varying vec2 v_Texture;" +
"uniform sampler2D u_Texture;" +
"void main(){" +
" gl_FragColor = texture2D(u_Texture, v_Texture);" +
"}";
int vs = glCreateShader(GL_VERTEX_SHADER);
int fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vs, vss);
glShaderSource(fs, fss);
glCompileShader(vs);
glCompileShader(fs);
program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
aPositionLocation = glGetAttribLocation(program, "a_Position");
// ***** Texture stuff starts here </</</</
// Fase 1
glActiveTexture(GL_TEXTURE0);
int[] genTextures = new int[1];
glGenTextures(1, genTextures, 0);
glBindTexture(GL_TEXTURE_2D, genTextures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Fase 2
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bitmap1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.res_for_test_1, options);
// Fase 3
texImage2D(GL_TEXTURE_2D, 0, bitmap1, 0);
glGenerateMipmap(GL_TEXTURE_2D);
// Fase 4
aTextureLocation = glGetAttribLocation(program, "a_Texture");
uTextureLocation = glGetUniformLocation(program, "u_Texture");
glUniform1i(uTextureLocation, 0);
verticesInBuffer.position(2);
glEnableVertexAttribArray(aTextureLocation);
glVertexAttribPointer(aTextureLocation, 2, GL_FLOAT, false, 16, verticesInBuffer);
// ***** Texture stuff ends here </</</</
}
#Override
public void onSurfaceChanged(GL10 arg0, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onDrawFrame(GL10 glUnused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
glUseProgram(program);
verticesInBuffer.position(0);
glEnableVertexAttribArray(aPositionLocation);
glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, false, 16, verticesInBuffer);
glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
}
}
You need to specify active texture unit and assign a previously loaded texture to it.
For convenience, I've created a helper function which does all of this. It activates given texture unit, assigns texture with given ID to it and puts this value to sampler2D uniform of shader:
protected void setTexture2D(int textureUnit, int textureID, int uniformID) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + textureUnit);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
GLES20.glUniform1i(uniformID, textureUnit);
}
And then call it like this:
setTexture2D(0, textureID, uniformID);
Related
I am testing to draw a textured sprite with opengl es 2.0. on android.
Demo works fine when I set ortho projection from - scr_w/2 to +scr_w/2 and - scr_h/ to +scr_h/2 with origin in middle of screen.
However if I translate to what I expect : 480 width (scr_w) and 720 (scr_h) height coordinate system + origin on top left corner of screen.
then Texture rendering goes wrong.
Matrix.orthoM(mProjectionMatrix, 0, 0, scr_w,0, scr_h, -1, 1); //then texture rendering doesn't work ?
I have tried to set Matrix.setLookAtM differently to point from (240,360,5) to (240,360,0)
//Matrix.setLookAtM(mViewMatrix, 0, scr_w/2, scr_h/2, 5, scr_w/2, scr_h/2, 0f, 0f, 1.0f, 0.0f); // then texture rendering doesn't work ?
The Renderer class:
public class SimpleRenderer implements GLSurfaceView.Renderer{
private final Context ctx;
static int scr_w = 480;
static int scr_h = 720;
private final float[] mViewMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mMVPMatrix = new float[16];
private Sprite spt1;
SimpleRenderer(final Context context)
{
this.ctx = context;
}
public void onSurfaceCreated(GL10 unused, EGLConfig config)
{
//Set the background color
GLES20.glClearColor(0.0f, 0.0f, 2.0f, 1.0f);
//Disable depth test
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
// Set alpha blend on
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
spt1 = new Sprite(ctx);
}
public void onSurfaceChanged(GL10 unused, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
Matrix.orthoM(mProjectionMatrix, 0, -scr_w/2, scr_w/2,-scr_h/2, scr_h/2, -1, 1);
// Matrix.orthoM(mProjectionMatrix, 0, 0, scr_w,0, scr_h, -1, 1); // DOESNT WORK ?
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0, 0, 0f, 0f, 1.0f, 0.0f);
//Matrix.setLookAtM(mViewMatrix, 0, scr_w/2, scr_h/2, 5, scr_w/2, scr_h/2, 0f, 0f, 1.0f, 0.0f); // DOESN'T WORK
// Mix the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
public void onDrawFrame(GL10 unused)
{
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
spt1.Draw(mMVPMatrix);
}}
The Sprite Class maybe mess with shader or fragment in 2D coordinates?
public class Sprite
{
//Reference to Activity Context
private final Context mActivityContext;
//Added for Textures
private final FloatBuffer mCubeTextureCoordinates;
private int mTextureUniformHandle;
private int mTextureCoordinateHandle;
private final int mTextureCoordinateDataSize = 2;
private int mTextureDataHandle;
private final String vertexShaderCode =
"attribute vec2 a_TexCoordinate; \n" +
"varying vec2 v_TexCoordinate; \n" +
"uniform mat4 uMVPMatrix; \n" +
"attribute vec4 vPosition; \n" +
"void main() { \n" +
" gl_Position = vPosition * uMVPMatrix; \n" +
" v_TexCoordinate = a_TexCoordinate; \n" +
"} \n";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"uniform sampler2D u_Texture;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
"gl_FragColor = (vColor * texture2D(u_Texture, v_TexCoordinate));" +
"}";
private final int shaderProgram;
private final FloatBuffer vertexBuffer;
private final ShortBuffer drawListBuffer;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 2;
static float spriteCoords[] = {
-50f, 50f, // top left
-50f, -50f, // bottom left
50f, -50f, // bottom right
50f, 50f //top right
};
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; //Order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; //Bytes per vertex
float color[] = { 1f, 1f, 1f, 1.0f };
public Sprite(final Context activityContext)
{
mActivityContext = activityContext;
//Initialize Vertex Byte Buffer
ByteBuffer bb = ByteBuffer.allocateDirect(spriteCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(spriteCoords);
vertexBuffer.position(0);
final float[] TextureCoordinate =
{
1f, 0f,
1f, 1f,
0f, 1f,
0f, 0f
};
mCubeTextureCoordinates = ByteBuffer.allocateDirect(TextureCoordinate.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeTextureCoordinates.put(TextureCoordinate).position(0);
//Initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(spriteCoords.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);
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertexShader);
GLES20.glAttachShader(shaderProgram, fragmentShader);
//Texture Code
GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate");
GLES20.glLinkProgram(shaderProgram);
//Load the texture
mTextureDataHandle = loadTexture(mActivityContext, R.drawable.cathead);
}
public void Draw(float[] mvpMatrix)
{
//Add program to OpenGL ES Environment
GLES20.glUseProgram(shaderProgram);
//Get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
//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
mColorHandle = GLES20.glGetUniformLocation(shaderProgram, "vColor");
//Set the Color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
//Set Texture Handles and bind Texture
mTextureUniformHandle = GLES20.glGetAttribLocation(shaderProgram, "u_Texture");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "a_TexCoordinate");
//Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
//Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
//Pass in the texture coordinate information
mCubeTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
//Get Handle to Shape's Transformation Matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
//Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glEnable(GLES20.GL_BLEND_COLOR);
GLES20.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLES20.glDepthMask(false);
//Draw the triangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
//Disable Vertex Array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
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);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
public static int loadShader(int type, String shaderCode)
{
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
I've recently started looking into OpenGL on Android. After T tried WebGL, I tried to use that on Android and ran into a weird issue which I can't solve after hours of googling and trial'n'error.
My code is supposed to draw a cube. However, it seems to not properly use my element buffer and always draws a black/green triangle. Even if I remove some indices, it still draws the same black/green triangle which hints to me that OpenGL pulls the wrong data.
I've read the tutorial on google code, which writes the buffers before every draw call, but I really want to avoid that, due to the memory overhead.
This is the code for my renderer. I expect my error somewhere in here:
package test.slikey.opengl_test;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import static android.opengl.GLES20.*;
public class OpenGLRenderer implements GLSurfaceView.Renderer {
private final String vertexShaderCode = "" +
"precision mediump float;" +
"" +
"attribute vec3 aVertexPosition;" +
"attribute vec4 aVertexColor;" +
"" +
"uniform mat4 uMatWorld;" +
"uniform mat4 uMatView;" +
"uniform mat4 uMatProj;" +
"" +
"varying vec4 vFragColor;" +
"" +
"void main()" +
"{" +
" gl_Position = uMatProj * uMatView * uMatWorld * vec4(aVertexPosition, 1.0);" +
" vFragColor = aVertexColor;" +
"}";
private final String fragmentShaderCode = "" +
"precision mediump float;" +
"" +
"varying vec4 vFragColor;" +
"" +
"void main()" +
"{" +
" gl_FragColor = vFragColor;" +
"}";
private final float[] positions = new float[]{
-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 0.5f, 0.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 1.0f, 0.5f, 0.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f
};
private final byte[] indices = new byte[]{
0, 4, 5,
0, 5, 1,
1, 5, 6,
1, 6, 2,
2, 6, 7,
2, 7, 3,
3, 7, 4,
3, 4, 0,
4, 7, 6,
4, 6, 5,
3, 0, 1,
3, 1, 2
};
private int shaderProgram;
private int attribVertexPosition;
private int attribVertexColor;
private int uniformMatWorld;
private int uniformMatView;
private int uniformMatProj;
private float[] matrixWorld;
private float[] matrixView;
private float[] matrixProj;
private int vertexBufferPointer;
private int indexBufferPointer;
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
glClearColor(0.2f, 0.6f, 0.8f, 1.0f);
shaderProgram = initShaderProgram();
attribVertexPosition = glGetAttribLocation(shaderProgram, "aVertexPosition");
attribVertexColor = glGetAttribLocation(shaderProgram, "aVertexColor");
uniformMatWorld = glGetUniformLocation(shaderProgram, "uMatWorld");
uniformMatView = glGetUniformLocation(shaderProgram, "uMatView");
uniformMatProj = glGetUniformLocation(shaderProgram, "uMatProj");
matrixWorld = new float[16];
matrixView = new float[16];
matrixProj = new float[16];
initBuffers();
}
private int initShaderProgram() {
int vertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
int program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
int[] linkStatus = new int[1];
glGetProgramiv(program, GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GL_TRUE) {
glDeleteProgram(program);
throw new RuntimeException("Could not link program: "
+ glGetProgramInfoLog(program));
}
return program;
}
private int loadShader(int type, String shaderCode) {
int shader = glCreateShader(type);
glShaderSource(shader, shaderCode);
glCompileShader(shader);
int[] compiled = new int[1];
glGetShaderiv(shader, GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
glDeleteShader(shader);
throw new RuntimeException("Could not compile program: "
+ glGetShaderInfoLog(shader) + " | " + shaderCode);
}
return shader;
}
private void initBuffers() {
int[] buffers = new int[2];
glGenBuffers(2, buffers, 0);
vertexBufferPointer = buffers[0];
indexBufferPointer = buffers[1];
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferPointer);
glBufferData(GL_ARRAY_BUFFER, positions.length, ByteBuffer.allocateDirect(positions.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(positions).position(0), GL_STATIC_DRAW);
glVertexAttribPointer(attribVertexPosition, 3, GL_FLOAT, false, 7 * 4, 0);
glVertexAttribPointer(attribVertexColor, 4, GL_FLOAT, false, 7 * 4, 3 * 4);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferPointer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.length, ByteBuffer.allocateDirect(indices.length).order(ByteOrder.nativeOrder()).put(indices).position(0), GL_STATIC_DRAW);
glEnableVertexAttribArray(attribVertexPosition);
glEnableVertexAttribArray(attribVertexColor);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
glViewport(0, 0, width, height);
Matrix.perspectiveM(matrixProj, 0, 45, (float) width / height, 0.01f, 1000.0f);
}
#Override
public void onDrawFrame(GL10 gl) {
glUseProgram(shaderProgram);
Matrix.setIdentityM(matrixWorld, 0);
Matrix.setLookAtM(matrixView, 0,
0, 0, -8,
0, 0, 0,
0, 1, 0
);
glUniformMatrix4fv(uniformMatWorld, 1, false, matrixWorld, 0);
glUniformMatrix4fv(uniformMatView, 1, false, matrixView, 0);
glUniformMatrix4fv(uniformMatProj, 1, false, matrixProj, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_BYTE, 0);
}
}
I expect it to be something really minor, like a default instuction which I am missing which is specific to Android. A similiar code has worked for WebGL.
Hopefully someone has an idea.
Thank you!
I am having a problem when rendering a texture to the viewport.
The screen is being rendered but the texture (256*256) does not the same as the original jpg picture I uploaded.
Please find attached images and code for the render. One image is the original jpg and the other is screenshot that is the rendered texture on the android phone.
original
rendered image
This is my MainActivity code:
private void initialize() {
if (hasGLES20()) {
GLSurfaceView mGLView = new GLSurfaceView(this);
mGLView.setEGLContextClientVersion(2);
mGLView.setPreserveEGLContextOnPause(true);
mGLView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
mGLView.setEGLConfigChooser(true);
mGLView.setRenderer(this);
setContentView(mGLView);
}
}
#Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
GLES20.glClearColor(0.5f,0.3f,0.8f,1.0f);
String vertexShaderSource = "" +
"uniform mat4 u_projection;" +
"uniform mat4 u_model;" +
"uniform mat4 u_view;" +
"" +
"attribute vec4 a_position;" +
"attribute vec2 a_texCoord;" +
"" +
"varying vec2 v_texCoord;" +
"" +
"void main()" +
"{" +
" gl_Position = u_projection * u_view * u_model * a_position;" +
" v_texCoord = a_texCoord;" +
"}";
String fragmentShaderSource = "" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"" +
"void main() {" +
" vec4 texCol = texture2D(s_texture, v_texCoord );" +
" gl_FragColor = texCol;" +
"}";
texture = new Texture(this);
vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vertexShader, vertexShaderSource);
GLES20.glCompileShader(vertexShader);
String vertexShaderCompileLog = GLES20.glGetShaderInfoLog(vertexShader);
fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, fragmentShaderSource);
GLES20.glCompileShader(fragmentShader);
String fragmentShaderCompileLog = GLES20.glGetShaderInfoLog(fragmentShader);
programID = GLES20.glCreateProgram();
GLES20.glAttachShader(programID,vertexShader);
GLES20.glAttachShader(programID,fragmentShader);
GLES20.glBindAttribLocation(programID, 0, "a_position");
GLES20.glBindAttribLocation(programID, 1, "a_texCoord");
GLES20.glLinkProgram(programID);
String programLinkLog = GLES20.glGetProgramInfoLog(programID);
GLES20.glUseProgram(programID);
float[] modelMatrix = new float[16], viewMatrix = new float[16], projectionMatrix = new float[16];
ByteBuffer modelMatrixByteBuffer = ByteBuffer.allocateDirect(modelMatrix.length * 4);
modelMatrixByteBuffer.order(ByteOrder.nativeOrder());
FloatBuffer modelMatrixBuffer = modelMatrixByteBuffer.asFloatBuffer();
Matrix.setIdentityM(modelMatrix,0);
Matrix.translateM(modelMatrix, 0, modelMatrix,0,0,0,-2.0f);
modelMatrixBuffer.put(modelMatrix);
modelMatrixBuffer.rewind();
// translate model to 0,0,-2
Matrix.setLookAtM(viewMatrix,0,0,0,0,0,0,-10,0,1,0);
Matrix.perspectiveM(projectionMatrix,0,70,256/256,0.1f,100);
GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(programID,"u_projection"),1,false,projectionMatrix,0);
GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(programID,"u_view"),1,false,viewMatrix,0);
GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(programID,"u_model"),1,false,modelMatrixBuffer);
}
#Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES20.glViewport(0,0,256,256);
}
#Override
public void onDrawFrame(GL10 gl10){
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
float vertices[] =
{
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f
};
float textureCoord[] =
{
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
ByteBuffer verticesByteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
verticesByteBuffer.order(ByteOrder.nativeOrder());
FloatBuffer verticesBuffer = verticesByteBuffer.asFloatBuffer();
verticesBuffer.put(vertices);
verticesBuffer.rewind();
ByteBuffer textureCoordByteBuffer = ByteBuffer.allocateDirect(textureCoord.length * 4);
textureCoordByteBuffer.order(ByteOrder.nativeOrder());
FloatBuffer textureCoordBuffer = textureCoordByteBuffer.asFloatBuffer();
textureCoordBuffer.put(textureCoord);
textureCoordBuffer.rewind();
GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 3 * 4, verticesBuffer);
GLES20.glVertexAttribPointer(1, 2, GLES20.GL_FLOAT, false, 2 * 4, textureCoordBuffer);
GLES20.glEnableVertexAttribArray(0);
GLES20.glEnableVertexAttribArray(1);
texture.setTexture();
GLES20.glUniform1i(GLES20.glGetUniformLocation(programID,"s_texture"),0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
This is my load Texture Class
public class Texture
{
private int m_iTextureId;
public Texture(Context ctx)
{
m_iTextureId = loadTexture(ctx, R.drawable.index);
}
public void setTexture()
{
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, m_iTextureId);
}
public int loadTexture(Context ctx, int rsrcId)
{
int[] iTextureId = new int[1];
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glGenTextures(1, iTextureId, 0);
if(iTextureId[0] != 0)
{
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iTextureId[0]);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeResource(ctx.getResources(), rsrcId,
options);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
}
else
{
throw new RuntimeException("Error loading texture");
}
return iTextureId[0];
}
Any help?
Your texture coordinates are wrong. They contain the same coordinate twice:
float textureCoord[] =
{
0.0f, 1.0f, <--
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f <--
};
To solve this replace the last coordinate with [1, 0] instead of [0, 1].
I'm trying to draw a disc in OpenGL-ES 2.0. Based on the second answer to this question How to draw basic circle in OpenGL ES 2.0 Android by user2901066, I'm doing:
String VertexShaderCode ="uniform mat4 uMVPMatrix;\n" +
"attribute vec4 vPosition;\n" +
"void main() {\n" +
"gl_Position = uMVPMatrix * vPosition;\n" +
"}";
String FragmentShaderCode = "precision mediump float;\n" +
"void main() {\n" +
//The problem is here
//"if ((textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0)" +
"if (true)\n" +
"gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n" +
"else\n" +
"gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 0.0f);\n" +
"}";
int vertexShader = this.loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode);
int fragmentShader = this.loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode);
mGlProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mGlProgram, vertexShader);
GLES20.glAttachShader(mGlProgram, fragmentShader);
GLES20.glLinkProgram(mGlProgram);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
protected int PositionHandle;
protected int MVPMatrixHandle;
static final int COORDS_PER_VERTEX = 3;
private final int VertexStride = COORDS_PER_VERTEX * 4;
private float LineCoords[] = new float[4 * 3];
private FloatBuffer VertexBuffer;
private final int VertexCount = 4;
ByteBuffer bb = ByteBuffer.allocateDirect(LineCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
VertexBuffer = bb.asFloatBuffer();
VertexBuffer.put(LineCoords);
VertexBuffer.position(0);
float[] mvpMatrix = {1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f};
LineCoords[0] = -1.0f;
LineCoords[1] = 1.0f;
LineCoords[3] = -1.0f;
LineCoords[4] = -1.0f;
LineCoords[6] = 1.0f;
LineCoords[7] = -1.0f;
LineCoords[9] = 1.0f;
LineCoords[10] = 1.0f;
VertexBuffer.put(LineCoords);
VertexBuffer.position(0);
GLES20.glUseProgram(mGlProgram);
PositionHandle = GLES20.glGetAttribLocation(mGlProgram, "vPosition");
GLES20.glEnableVertexAttribArray(PositionHandle);
GLES20.glVertexAttribPointer(PositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, VertexStride, VertexBuffer);
MVPMatrixHandle = GLES20.glGetUniformLocation(mGlProgram, "uMVPMatrix");
GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, VertexCount);
GLES20.glDisableVertexAttribArray(PositionHandle);
My problem is to get the position in the fragment shader in order to apply the right color. How do I do that?
You need a varying variable declared on both shaders:
varying vec2 textureCoord;
then on the vertex shader, put some value to it such as:
textureCoord = gl_Position.xy;
this variable will then be sent to the fragment shader interpolated for each fragment so your fragment shader can use it:
if ((textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0)
{
gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
} else {
gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 0.0f);
}
I would like to rotate my triangles in Z axis, but I would to do it around the center of the triangle, not the center of the screen. I have researched a lot on that but didn't find any resolution.
Any idea of what could I try to solve it?
public class RendererClass implements Renderer {
FloatBuffer bufferObj1;
FloatBuffer bufferObj2;
int programObj1;
int programObj2;
int positionObj1;
int positionObj2;
int rotationMatrixLocationObj1;
int rotationMatrixLocationObj2;
int colorObj1;
int colorObj2;
float[] rotationMatrixObj1 = new float[16];
float[] rotationMatrixObj2 = new float[16];
#Override
public void onSurfaceCreated(GL10 arg0, EGLConfig config) {
GLES20.glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
float[] vertexObj1 = {
-0.8f, 0.8f,
-0.8f, 0.0f,
0.0f, 0.0f
};
float[] vertexObj2 = {
0.8f, 0.8f,
0.8f, 0.0f,
0.0f, 0.0f
};
bufferObj1 = ByteBuffer.allocateDirect(vertexObj1.length*4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexObj1);
bufferObj2 = ByteBuffer.allocateDirect(vertexObj2.length*4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexObj2);
String vssObj1 = "attribute vec4 positionObj1;" +
"uniform mat4 rotationMatrixObj1;" +
"void main(){" +
"gl_Position = rotationMatrixObj1 * positionObj1;" +
"}";
String vssObj2 = "attribute vec4 positionObj2;" +
"uniform mat4 rotationMatrixObj2;" +
"void main(){" +
"gl_Position = rotationMatrixObj2 * positionObj2;" +
"}";
String fssObj1 = "precision mediump float;" +
"uniform vec4 colorObj1;" +
"void main(){" +
"gl_FragColor = colorObj1;" +
"}";
String fssObj2 = "precision mediump float;" +
"uniform vec4 colorObj2;" +
"void main(){" +
"gl_FragColor = colorObj2;" +
"}";
int vsObj1 = glCreateShader(GL_VERTEX_SHADER);
int vsObj2 = glCreateShader(GL_VERTEX_SHADER);
int fsObj1 = glCreateShader(GL_FRAGMENT_SHADER);
int fsObj2 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vsObj1, vssObj1);
glShaderSource(vsObj2, vssObj2);
glShaderSource(fsObj1, fssObj1);
glShaderSource(fsObj2, fssObj2);
glCompileShader(vsObj1);
glCompileShader(vsObj2);
glCompileShader(fsObj1);
glCompileShader(fsObj2);
programObj1 = glCreateProgram();
programObj2 = glCreateProgram();
glAttachShader(programObj1, vsObj1);
glAttachShader(programObj2, vsObj2);
glAttachShader(programObj1, fsObj1);
glAttachShader(programObj2, fsObj2);
glLinkProgram(programObj1);
glLinkProgram(programObj2);
positionObj1 = glGetAttribLocation(programObj1, "positionObj1");
positionObj2 = glGetAttribLocation(programObj2, "positionObj2");
rotationMatrixLocationObj1 = glGetUniformLocation(programObj1, "rotationMatrixObj1");
rotationMatrixLocationObj2 = glGetUniformLocation(programObj2, "rotationMatrixObj2");
colorObj1 = glGetUniformLocation(programObj1, "colorObj1");
colorObj2 = glGetUniformLocation(programObj2, "colorObj2");
}
#Override
public void onSurfaceChanged(GL10 arg0, int width, int height) {
Matrix.setIdentityM(rotationMatrixObj1, 0);
Matrix.rotateM(rotationMatrixObj1, 0, MainActivity.angle, 0, 0, 1);
Matrix.setIdentityM(rotationMatrixObj2, 0);
Matrix.rotateM(rotationMatrixObj2, 0, MainActivity.angle, 0, 0, -1);
}
GL10 gl;
#Override
public void onDrawFrame(GL10 glUnused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
onSurfaceChanged(gl, 0, 0);
glUseProgram(programObj1);
bufferObj1.position(0);
glVertexAttribPointer(positionObj1, 2, GL_FLOAT, false, 0, bufferObj1);
glEnableVertexAttribArray(positionObj1);
glUniform4f(colorObj1, 0.0f, 0.0f, 1.0f, 1.0f);
glUniformMatrix4fv(rotationMatrixLocationObj1, 1, false, rotationMatrixObj1, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glUseProgram(programObj2);
bufferObj2.position(0);
glVertexAttribPointer(positionObj2, 2, GL_FLOAT, false, 0, bufferObj2);
glEnableVertexAttribArray(positionObj2);
glUniform4f(colorObj2, 1.0f, 0.0f, 0.0f, 1.0f);
glUniformMatrix4fv(rotationMatrixLocationObj2, 1, false, rotationMatrixObj2, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
}
You use glDrawArrays so you can alter your triangles in your code any way you want. Use simple trigonometry to rotate your vertices independently.
Rotation matrix rotates vertices around center of coordinate system.
If you want to rotate scene around some other point (x0, y0, z0) you have to do this in 3 simple steps:
translate scene in such way that your point will be in center of coord system (by -x0, -y0, -z0)
rotate
translate back (by x0, y0, z0)
Of course 3 steps of transformation are not needed, matrix multiplication can do this work for us.