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].
Related
If i change the background of GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f) and then try to draw a texture, colors of this last changes unexpectedly. This is the png file:
The result of the application when i try simply to display it is this one:
Im using this code:
public class GLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "MyGLRenderer";
private float[] vertices = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f
};
private float[] textureVertices = {
0f, 1f,
1f, 1f,
0f, 0f,
1f, 0f
};
private final String vertexShaderCode =
"attribute vec4 aPosition;" +
"attribute vec2 aTexPosition;" +
"varying vec2 vTexPosition;" +
"void main() {" +
" gl_Position = aPosition;" +
" vTexPosition = aTexPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D uTexture;" +
"varying vec2 vTexPosition;" +
"void main() {\n" +
"vec4 color = texture2D(uTexture, vTexPosition);\n"+
//"if(color.r == 0.0 && color.g == 0.0 && color.b == 0.0)\n"+
// "color = vec4(1.0,0.5,0.5,1.0);"+
// "discard;"+
" gl_FragColor = color;" +
"}";
private FloatBuffer verticesBuffer;
private FloatBuffer textureBuffer;
private int vertexShader;
private int fragmentShader;
private int program;
private Bitmap bmp;
private int textures[] = new int[2];
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
public GLRenderer() {
bmp=Bitmap.createBitmap(513,912, Bitmap.Config.ARGB_8888);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
checkGlError("glClearColor");
setup();
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
#Override
public void onDrawFrame(GL10 gl) {
Log.d("Drawing_Frame","Working");
float[] scratch = new float[16];
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.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 Bitmap
drawBinaryImage(bmp,textures[0]);
Matrix.setRotateM(mRotationMatrix, 0, 0, 0, 0, 1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
}
private void setup(){
GLES20.glGenTextures(2, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
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);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
//GLES20.glBindTexture(GL);
initializeBuffers();
initializeProgram();
}
private void initializeBuffers() {
ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4);
buff.order(ByteOrder.nativeOrder());
verticesBuffer = buff.asFloatBuffer();
verticesBuffer.put(vertices);
verticesBuffer.position(0);
buff = ByteBuffer.allocateDirect(textureVertices.length * 4);
buff.order(ByteOrder.nativeOrder());
textureBuffer = buff.asFloatBuffer();
textureBuffer.put(textureVertices);
textureBuffer.position(0);
}
private void initializeProgram() {
vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glGetShaderInfoLog(vertexShader);
checkGlError("glCreateShader");
GLES20.glShaderSource(vertexShader, vertexShaderCode);
GLES20.glCompileShader(vertexShader);
fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
GLES20.glCompileShader(fragmentShader);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
checkGlError("glLinkProgram");
}
public void updateTexture(Bitmap bmp){
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
}
private void drawBinaryImage(Bitmap bmp,int texture){
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glUseProgram(program);
//Changes Here original Line GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
int positionHandle = GLES20.glGetAttribLocation(program, "aPosition");
int textureHandle = GLES20.glGetUniformLocation(program, "uTexture");
int texturePositionHandle = GLES20.glGetAttribLocation(program, "aTexPosition");
//Log.d("GL_SETUP",positionHandle+" , "+textureHandle);
GLES20.glVertexAttribPointer(texturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
GLES20.glEnableVertexAttribArray(texturePositionHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
Log.d("FILTER_APPLY","Applying");
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
GLES20.glUniform1i(textureHandle, 0);
GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, verticesBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
checkGlError("glDrawArrays");
}
public void setBitmap(Bitmap bitmap){
updateTexture(bitmap);
this.bmp = bitmap;
}
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);
}
}
}
The framebuffer is cleared by GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f);.
RGBA(1, 1, 0, 1) is yellow. This causes that before rendering the texture, the entire framebuffer is filled in yellow.
The texture contains a blue color RGBA(0, 0, 1, 1) and a black color RGBA(0, 0, 0, 1).
When the quad with the texture is drawn, then blending is enabled with the following function:
(see Blending and glBlendFunc)
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
At blending the current color of the framebuffer is mixed by the actually drawn color. With the above setup this done by the following function:
destinationColor = sourceColor * 1 + destinationColor * 1
In the regions where the texture is blue, the final color becomes white:
(1, 1, 0) * 1 + (0, 0, 1) * 1 = (1, 1, 1)
In the regions where the texture is black, the color in the framebuffer stays yellow:
(1, 1, 0) * 1 + (0, 0, 0) * 1 = (1, 1, 0)
I need to draw a shape in OpenGL from a binary image. For example, I have this image binary
and I need to draw this shape in OpenGL. The fact is that I need to do this "dynamically" so I will have for example a different binary image every second and I need to draw the shapes from every one of those images. Shapes will not be the only triangles like in the example image. I will use this in Android Studio.
Convert this image to Bitmap object and draw it on the GLSurfaceView. you can check condition in shader code like this.
vec4 color = texture2D(uTexture, vTexPosition);
if(color.r == 0.0 && color.g == 0.0 && color.b == 0.0)
color = vec4(1.0,0.5,0.5,1.0);
gl_FragColor = color;
This is the full GLRenderer
public class GLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "MyGLRenderer";
private float[] vertices = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f
};
private float[] textureVertices = {
0f, 1f,
1f, 1f,
0f, 0f,
1f, 0f
};
private final String vertexShaderCode =
"attribute vec4 aPosition;" +
"attribute vec2 aTexPosition;" +
"varying vec2 vTexPosition;" +
"void main() {" +
" gl_Position = aPosition;" +
" vTexPosition = aTexPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D uTexture;" +
"varying vec2 vTexPosition;" +
"void main() {\n" +
"vec4 color = texture2D(uTexture, vTexPosition);\n"+
"if(color.r == 0.0 && color.g == 0.0 && color.b == 0.0)\n"+
"color = vec4(1.0,0.5,0.5,1.0);"+
" gl_FragColor = color;" +
"}";
private FloatBuffer verticesBuffer;
private FloatBuffer textureBuffer;
private int vertexShader;
private int fragmentShader;
private int program;
private Bitmap bmp;
private int textures[] = new int[2];
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
public GLRenderer() {
bmp=Bitmap.createBitmap(513,912, Bitmap.Config.ARGB_8888);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
checkGlError("glClearColor");
setup();
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
#Override
public void onDrawFrame(GL10 gl) {
Log.d("Drawing_Frame","Working");
float[] scratch = new float[16];
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.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 Bitmap
drawBinaryImage(bmp,textures[0]);
Matrix.setRotateM(mRotationMatrix, 0, 0, 0, 0, 1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
}
private void setup(){
GLES20.glGenTextures(2, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
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);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
//GLES20.glBindTexture(GL);
initializeBuffers();
initializeProgram();
}
private void initializeBuffers() {
ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4);
buff.order(ByteOrder.nativeOrder());
verticesBuffer = buff.asFloatBuffer();
verticesBuffer.put(vertices);
verticesBuffer.position(0);
buff = ByteBuffer.allocateDirect(textureVertices.length * 4);
buff.order(ByteOrder.nativeOrder());
textureBuffer = buff.asFloatBuffer();
textureBuffer.put(textureVertices);
textureBuffer.position(0);
}
private void initializeProgram() {
vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glGetShaderInfoLog(vertexShader);
checkGlError("glCreateShader");
GLES20.glShaderSource(vertexShader, vertexShaderCode);
GLES20.glCompileShader(vertexShader);
fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
GLES20.glCompileShader(fragmentShader);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
checkGlError("glLinkProgram");
}
public void updateTexture(Bitmap bmp){
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
}
private void drawBinaryImage(Bitmap bmp,int texture){
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glUseProgram(program);
//Changes Here original Line GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
int positionHandle = GLES20.glGetAttribLocation(program, "aPosition");
int textureHandle = GLES20.glGetUniformLocation(program, "uTexture");
int texturePositionHandle = GLES20.glGetAttribLocation(program, "aTexPosition");
//Log.d("GL_SETUP",positionHandle+" , "+textureHandle);
GLES20.glVertexAttribPointer(texturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
GLES20.glEnableVertexAttribArray(texturePositionHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
Log.d("FILTER_APPLY","Applying");
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
GLES20.glUniform1i(textureHandle, 0);
GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, verticesBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
checkGlError("glDrawArrays");
}
public void setBitmap(Bitmap bitmap){
updateTexture(bitmap);
this.bmp = bitmap;
}
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);
}
}
}
Use this renderer with GlSurfaceView
Here is main Activity class
public class MainActivity extends AppCompatActivity {
FrameLayout glView;
private GLRenderer renderer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
glView = findViewById(R.id.glview);
setupGL();
}
private void setupGL(){
renderer = new GLRenderer();
//MyGlSurfaceView glSurfaceView = new MyGlSurfaceView(this,renderer);
GLSurfaceView glSurfaceView = new GLSurfaceView(this);
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setRenderer(renderer);
glView.addView(glSurfaceView);
produceFrame();
}
private void produceFrame(){
Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.sample);
renderer.setBitmap(bmp);
}
You can check this for complete project.
I want to make customized watermark renderer on Android.
I am going to add watermark at bottom right corner above current camera preview screen.
Here is the source code what I made. this code does not work.
Please help me. Thank you.
Function call sequence is :
-setWatermarkTexture
-createBuffers
-configureOpenGL
-draw
public class WatermarkRenderer implements Renderer {
private int[] textureHandles = new int[1];
float vertices[] = {
-1, 0.5f,
-0.5f, -0.5f,
-1, 1,
-0.5f, 1,
};
float texCoords[] = {
0, 0,
1, 0,
0, 1,
1, 1,
};
private Bitmap watermark;
private int[] buffers = new int[2];
private float[] projectionMatrix = new float[16];
private FloatBuffer vertexBuffer;
private FloatBuffer textureBuffer;
#Override
public void configureOpenGL() {
GLES20.glGenTextures(textureHandles.length, textureHandles, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[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);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glGenBuffers(buffers.length, buffers, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 8, vertexBuffer, GLES20.GL_STATIC_DRAW );
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 8, textureBuffer, GLES20.GL_STATIC_DRAW );
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
}
#Override
public void createBuffers() {
vertexBuffer = FloatBuffer.allocate(8);
vertexBuffer.put(vertices);
vertexBuffer.position(0);
textureBuffer = FloatBuffer.allocate(8);
textureBuffer.put(texCoords);
textureBuffer.position(0);
}
#Override
public void draw() {
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
//GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
//GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA );
if (watermark != null) {
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, watermark, 0);
watermark.recycle();
watermark = null;
}
/*
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glEnableVertexAttribArray(AttributeLocations.POSITION);
GLES20.glVertexAttribPointer(AttributeLocations.POSITION, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glEnableVertexAttribArray(AttributeLocations.TEXTURE_COORDINATES );
GLES20.glVertexAttribPointer(AttributeLocations.TEXTURE_COORDINATES, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4 );
GLES20.glDisableVertexAttribArray(AttributeLocations.POSITION);
GLES20.glDisableVertexAttribArray(AttributeLocations.TEXTURE_COORDINATES);
*/
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
}
#Override
public void setProjectionMatrix(float[] projectionMatrix) {
this.projectionMatrix = projectionMatrix;
}
public void setWatermarkTexture(Bitmap bitmap) {
watermark = bitmap;
}
}
I solved my issue.
Here is the source code.
public class WatermarkRenderer implements Renderer {
private final float[] TEX_VERTICES = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
private final float[] POS_VERTICES = {
0.2f, -1.0f,
1.0f, -1.0f,
0.2f, -0.9f,
1.0f, -0.9f
};
private static final String VERTEX_SHADER =
"attribute vec4 a_position;\n" +
"attribute vec2 a_texcoord;\n" +
"varying vec2 v_texcoord;\n" +
"void main() {\n" +
" gl_Position = a_position;\n" +
" v_texcoord = a_texcoord;\n" +
"}\n";
private static final String FRAGMENT_SHADER =
"precision mediump float;\n" +
"uniform sampler2D tex_sampler;\n" +
"varying vec2 v_texcoord;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(tex_sampler, v_texcoord);\n" +
"}\n";
private final int FLOAT_SIZE_BYTES = 4;
private Bitmap watermark;
private int shaderProgram;
private int texSamplerHandle;
private int texCoordHandle;
private int posCoordHandle;
private FloatBuffer texVertices;
private FloatBuffer posVertices;
private int[] textureHandles = new int[1];
#Override
public void configureOpenGL() {
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, OpenGLUtils.loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER));
GLES20.glAttachShader(shaderProgram, OpenGLUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER));
GLES20.glLinkProgram(shaderProgram);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(shaderProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
String info = GLES20.glGetProgramInfoLog(shaderProgram);
GLES20.glDeleteProgram(shaderProgram);
shaderProgram = 0;
throw new RuntimeException("Could not link program: " + info);
}
texSamplerHandle = GLES20.glGetUniformLocation(shaderProgram, "tex_sampler");
texCoordHandle = GLES20.glGetAttribLocation(shaderProgram, "a_texcoord");
posCoordHandle = GLES20.glGetAttribLocation(shaderProgram, "a_position");
}
#Override
public void createBuffers() {
ByteBuffer byteBuffer;
byteBuffer = ByteBuffer.allocateDirect(TEX_VERTICES.length * FLOAT_SIZE_BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
texVertices = byteBuffer.asFloatBuffer();
texVertices.put(TEX_VERTICES);
texVertices.position(0);
byteBuffer = ByteBuffer.allocateDirect(POS_VERTICES.length * FLOAT_SIZE_BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
posVertices = byteBuffer.asFloatBuffer();
posVertices.put(POS_VERTICES);
posVertices.position(0);
}
#Override
public void draw() {
// Select the program.
GLES20.glUseProgram(shaderProgram);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA );
// Set the vertex attributes
GLES20.glVertexAttribPointer(texCoordHandle, 2, GLES20.GL_FLOAT, false, 0, texVertices);
GLES20.glEnableVertexAttribArray(texCoordHandle);
GLES20.glVertexAttribPointer(posCoordHandle, 2, GLES20.GL_FLOAT, false, 0, posVertices);
GLES20.glEnableVertexAttribArray(posCoordHandle);
// Set the input texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
GLES20.glUniform1i(texSamplerHandle, 0);
GLES20.glGenTextures(textureHandles.length, textureHandles, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, watermark, 0);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_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);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(texCoordHandle);
GLES20.glDisableVertexAttribArray(posCoordHandle);
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glUseProgram(0);
}
#Override
public void setProjectionMatrix(float[] projectionMatrix) {
}
public void setWatermarkTexture(Bitmap bitmap) {
watermark = bitmap;
}
}
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.
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);