I am creating a simple traingle strip to cover the whole viewport with a single rectangle. Then I am applying a 100x100 texture to this surface which changes with every frame.
I set up viewPort and initialise my vertexBuffer etc. in the onSurfaceChanged method of my GLSurfaceView class, then call my rendering function from onDrawFrame.
This setup works as it should, but at random occasions only the right lower quarter of my rectangle gets rendered, the other 3/4th of the canvas is filled with background color! It doesn't happen every time, and the anomaly disappears after rotating the device back and forth (I guess because everything gets a reset in onSurfaceChanged)
I have tried to re-upload all vertices at every frame update with GLES20.glBufferData, which seems to get rid of this bug, although it might be that I just wasn't patient enough to observe it happening (as it is quite unpredictible). It's a very simple triangle strip, so I don't think that it consumes a lot of time, but it just feels bad practice to upload a data 60/sec which isn't changing at all!
//called from onSurfaceChanged
private fun initGL (side:Int) {
/*======== Defining and storing the geometry ===========*/
//vertices for TRIANGLE STRIP
val verticesData = floatArrayOf(
-1.0f,1.0f,//LU
-1.0f,-1.0f,//LL
1.0f,1.0f,//RU
1.0f,-1.0f//RL
)
//float : 32 bit -> 4 bytes
val vertexBuffer : FloatBuffer = ByteBuffer.allocateDirect(verticesData.size * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer()
vertexBuffer.put(verticesData).position(0)
val buffers = IntArray(1)
GLES20.glGenBuffers(1, buffers, 0)
vertexBufferId = buffers[0]
//upload vertices to GPU
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId)
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
vertexBuffer.capacity() * 4, // 4 = bytes per float
vertexBuffer,
GLES20.GL_STATIC_DRAW)
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0)
/*================ Shaders ====================*/
// Vertex shader source code
val vertCode =
"""
attribute vec4 aPosition;
void main(void) {
gl_Position = aPosition;
}
"""
val fragCode =
"""
precision mediump float;
varying vec2 vCoord;
uniform sampler2D u_tex;
void main(void) {
//1-Y, because we need to flip the Y-axis!!
vec4 color = texture2D(u_tex, vec2(gl_FragCoord.x/$side.0, 1.0-(gl_FragCoord.y/$side.0)));
gl_FragColor = color;
}
"""
// Create a shader program object to store
// the combined shader program
val shaderProgram = createProgram(vertCode, fragCode)
// Use the combined shader program object
GLES20.glUseProgram(shaderProgram)
val vertexCoordLocation = GLES20.glGetAttribLocation(shaderProgram, "aPosition")
GLES20.glVertexAttribPointer(vertexCoordLocation, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer)
GLES20.glEnableVertexAttribArray(vertexCoordLocation)
//set ClearColor
GLES20.glClearColor(1f,0.5f,0.5f,0.9f)
//setup a texture buffer array
val texArray = IntArray(1)
GLES20.glGenTextures(1,texArray,0)
textureId = texArray[0]
if (texArray[0]==0) Log.e(TAG, "Error with Texture!")
else Log.e(TAG, "Texture id $textureId created!")
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
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.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.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT,1)
}
//called from onDrawFrame
private fun updateGLCanvas (matrix : ByteArray, side : Int) {
//create ByteBuffer from updated texture matrix
val textureImageBuffer : ByteBuffer = ByteBuffer.allocateDirect(matrix.size * 1)//Byte = 1 Byte
.order(ByteOrder.nativeOrder())//.asFloatBuffer()
textureImageBuffer.put(matrix).position(0)
//do I need to bind the texture in every frame?? I am desperate XD
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,GLES20.GL_RGB, side, side, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, textureImageBuffer)
//bind vertex buffer
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId)
// Clear the color buffer bit
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
//draw from vertex buffer
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,0,4)
//unbind vertex buffer
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0)
}
There are no error messages and most of the time the code is behaving as it should ... which makes this a bit difficult to track ...
If you want to use a vertex buffer, then the buffer object has to be the currently bound to the target GLES20.GL_ARRAY_BUFFER, when the array of generic vertex attribute data is specified by glVertexAttribPointer. The vertex attribute specification refers to this buffer.
In this case the last parameter of glVertexAttribPointer is treated as a byte offset into the buffer object's data store.
In your case this means the last parameter has to be 0.
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId)
GLES20.glVertexAttribPointer(vertexCoordLocation, 2, GLES20.GL_FLOAT, false, 0, 0)
Note, if no named buffer buffer object is bound (zero), then the last parameter is a pointer to the buffer memory. Every time when a draw call is performed, this buffer is read.
In your implementation, the data which was uploaded to the GPU is never used, because it isn't referenced by the vertex array specification.
See also Vertex Specification.
Related
I currently have allocated an immutable texture using OpenGL ES 3.1 on Android using the Java bindings like this:
GLES32.glGenTextures(1, velocityMap, 0);
GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, velocityMap[0]); // Bind our texture to target
GLES32.glActiveTexture(GLES32.GL_TEXTURE0); // Use texture unit 0
GLES32.glTexStorage2D(GLES32.GL_TEXTURE_2D, 1, GLES32.GL_RGBA32F, texWidth, texHeight); // Allocate immutable storage
// Set interpolation to nearest
GLES32.glTexParameteri(GLES32.GL_TEXTURE_2D, GLES32.GL_TEXTURE_MAG_FILTER, GLES32.GL_LINEAR);
GLES32.glTexParameteri(GLES32.GL_TEXTURE_2D, GLES32.GL_TEXTURE_MIN_FILTER, GLES32.GL_LINEAR);
///////////////////////////// ADDED THANKS TO SOLIDPIXEL -->
GLES32.glGenFramebuffers(1, fbo, 0); // Generate an FBO
GLES32.glBindFramebuffer(GLES32.GL_DRAW_FRAMEBUFFER, fbo[0]); // Bind it to frame buffer target
GLES32.glFramebufferTexture2D(
GLES32.GL_DRAW_FRAMEBUFFER,
GLES32.GL_COLOR_ATTACHMENT0,
GLES32.GL_TEXTURE_2D,
velocityMap[0], 0); // Attach texture
int colourBufs[] = {GLES32.GL_COLOR_ATTACHMENT0};
GLES32.glDrawBuffers(1, colourBufs, 0); // Specify list of colour buffers to draw to
float[] clearColor = {0.0f, 0.0f, 1.0f, 1.0f}; // Set to blue
GLES32.glClearBufferfv(GLES32.GL_COLOR, 0, clearColor, 0); // Clear buffer
<-- ///////////////////////////// END EDIT
// Get the unit number of image2d variable in shader and bind the immutable texture
texLoc = GLES32.glGetUniformLocation(idComputeShaderProgram, "colourMap");
GLES32.glGetUniformiv(idComputeShaderProgram, texLoc, unit, 0);
GLES32.glBindImageTexture(unit[0], velocityMap[0], 0, false, 0, GLES32.GL_WRITE_ONLY, GLES32.GL_RGBA32F);
In a compute shader I use imageStore() to write data:
#version 320 es
#define S_WORKGROUP_SIZE_X 128
#define S_WORKGROUP_SIZE_Y 1
#define S_WORKGROUP_SIZE_Z 1
layout(binding = 0, rgba32f) writeonly uniform lowp image2D colourMap;
layout(local_size_x = S_WORKGROUP_SIZE_X, local_size_y = S_WORKGROUP_SIZE_Y, local_size_z = S_WORKGROUP_SIZE_Z) in;
void main()
{
imageStore(colourMap, ivec2(gl_GlobalInvocationID.xy), vec4(1.0f, 0.0f, 0.0f, 1.0f));
}
and then once complete I use a separate graphics shader program with a with a uniform 2Dsampler called image to draw the modified texture on a triangle strip. Initialised as:
GLES32.glUseProgram(idGraphicsShaderProgram);
GLES32.glBindTexture(GLES31.GL_TEXTURE_2D, velocityMap[0]);
GLES32.glUniform1i(GLES31.glGetUniformLocation(idGraphicsShaderProgram, "image"), 0); // Use texture unit 0
This is executed in the render method as:
GLES32.glUseProgram(idGraphicsShaderProgram);
GLES32.glBindTexture(GLES31.GL_TEXTURE_2D, velocityMap[0]);
GLES32.glClear(GLES31.GL_COLOR_BUFFER_BIT);
GLES32.glBindVertexArray(vao[0]);
GLES32.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
I'm currently seeing a black texture which suggests to me that there is not data to show. If I modify my fragment shader to output a flat colour, that works fine so I believe the graphics shader is working properly.
In order to help debug, I would like to initialise the texture I allocate as a filled blue texture to isolate whether the problem is with the graphics shader reading the texture or the compute shader modifying the texture but I don't see how I can buffer data to the texture once I've allocated it with glTexStorage2D() -- I use glTexImage2D() on desktop as there wasn't an immutable storage restriction like there is in GLES and I could buffer data directly. How do I fill an immutable texture with data from the client?
Update:
Having implemented solidpixel's original suggestion I still cannot seen any texture. Is there anything else in this minimal code that is obviously incorrect?
Create a framebuffer object, attach the texture as an attachment, and use "glClear" to set it to a constant color.
this question is similar to something I asked here Android OpenGL ES 2: Introduction to VBOs
however I tried multiple aproaches since then and I still haven't succeeded, so I think posting another question where I offer aditional details would be a better aproach.
I am new to OpenGL ES 2 on Android (I have never worked with another OpenGL, I just need to draw something for an app I am developing for Android) and I would very much like to understand how to use VBOs. I tried to modify this OpenGL ES 2 for Android tutorial to use VBOs when drawing the triangle. I tried to use this step by step guide and this tutorial but I still don't understand everything, I am rather new to all of these things. My app currently crashes on start. Here's what I have:
public class Triangle {
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final FloatBuffer vertexBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private final int buffer[] = new int[1];
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = {
// in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f };
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public Triangle() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
// First, generate as many buffers as we need.
// This will give us the OpenGL handles for these buffers.
GLES20.glGenBuffers(1, buffer, 0);
// prepare shaders and OpenGL program
int vertexShader = MyGLRenderer.loadShader(
GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(
GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // create OpenGL program executables
}
/**
* Encapsulates the OpenGL ES instructions for drawing this shape.
*
* #param mvpMatrix - The Model View Project matrix in which to draw
* this shape.
*/
public void draw(float[] mvpMatrix) {
// 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);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//these I don't fully understand
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffer[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,vertexBuffer.capacity() * 4,vertexBuffer,GLES20.GL_STATIC_DRAW);
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// 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, 0);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// //is this still necesary? or do i have to use glDeleteBuffers?
// GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}
}
when I put 0 instead of vertexBuffer inside glVertexAttribPointer() I get an error saying I don't provide the necesarry parameter: expected parameter: ptr: java.nio.Buffer; actual arguments: 0(int)
The transition to the VBO can be a bit strange due to the data pointer usage.
From a quick inspection your main issue is in
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
as this should be
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, 0);
So about this buffers: A VBO is a custom buffer on the GPU generally used and optimised to store the vertex data directly to the GPU. The performance you gain by doing so is that the vertex data do not need to be copied to the GPU on every draw call.
These buffers are still custom and on generating them all you need to set is their size. I see you are using factor *4 on the vertex count assuming a float value has a size of 4 bytes, this is not the best idea since that might not always be true. If possible always try to use some form of "sizeOf". Anyway your buffer is created correctly and data are sent to it.
After the data are sent to the VBO you should keep them there until you need them. That means you generally create a single VBO per unique object (a square for instance) and then just hold its ID. Whenever you wish to draw it you just simply bind the buffer and draw as you did. In other words the buffer should never be created in the draw method. What you did there is a memory leak as well since you are responsible for releasing the buffer by calling delete once the buffer is no longer needed.
So about your pointer issue on glVertexAttribPointer: There are 2 ways to use this method. Without the VBO the last parameter is the pointer to the data on your CPU. With the VBO you need to set that as a relative pointer inside the VBO. That means when VBO is bound the beginning of the buffer would be NULL (0), you might even need to typecast that value. For other positions in the buffer you need to manually calculate them.
And the code you posted specifically:
// First, generate as many buffers as we need.
// This will give us the OpenGL handles for these buffers.
final int buffer[] = new int[1];
GLES20.glGenBuffers(1, buffer, 0);
//these I don't fully understand
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffer[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,vertexBuffer.capacity() * 4,vertexBuffer,GLES20.GL_STATIC_DRAW);
This all goes into some load time and have a reference to the buffer[] beside that you should add GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); what this call does is unbind the buffer. This is not something you NEED to do but it is best that you do so you have no confusion what buffer is bound if any.
Before the glVertexAttribPointer is called you need to bind your buffer. Then set the last parameter as described above.
After you are done using this buffer (done drawing) you should (again not necessary) unbind the buffer.
So I'm able to display 1 texture at a time but I have a problem with displaying more textures. The render function is called for every texture separately (tex_nr), not sure if that's a good approach. Here's the rendering code:
private void Render(float[] m, int tex_nr) {
// Set our shaderprogram to image shader
GLES20.glUseProgram(riGraphicTools.sp_Image);
// clear Screen and Depth Buffer, we have set the clear color as black.
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// get handle to vertex shader's vPosition member
int mPositionHandle = GLES20.glGetAttribLocation(riGraphicTools.sp_SolidColor, "vPosition");
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, 3,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
// Get handle to texture coordinates location
int mTexCoordLoc = GLES20.glGetAttribLocation(riGraphicTools.sp_Image,
"a_texCoord" );
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT,
false,
0, uvBuffer);
// Get handle to shape's transformation matrix
int mtrxhandle = GLES20.glGetUniformLocation(riGraphicTools.sp_Image,
"uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
// Get handle to textures locations
int mSamplerLoc = GLES20.glGetUniformLocation (riGraphicTools.sp_Image,
"s_texture" );
// Set the sampler texture unit to where we have saved the texture.
GLES20.glUniform1i ( mSamplerLoc, tex_nr);
// Draw the triangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
}
And here the loading textures code:
texturenames = new int[GameObject.spritePaths.size()];
GLES20.glGenTextures(GameObject.spritePaths.size(), texturenames, 0);
for(int i = 0; i < GameObject.spritePaths.size(); i++)
{
// Retrieve our image from resources.
int id = mContext.getResources().getIdentifier(GameObject.spritePaths.get(i), null, mContext.getPackageName());
// Temporary create a bitmap
Bitmap bmp = BitmapFactory.decodeResource(mContext.getResources(), id);
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0+i);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[i]);
// Set filtering
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);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
// We are done using the bitmap so we should recycle it.
bmp.recycle();
}
As a result of this code, only the last loaded texture is displayed and I have no idea why the former ones do not show up. I would be very grateful for any clues!
edit:
Actually, I have just found out that I can display all of the textures that I loaded but only 1 at a time. So I guess that the problem isn't connected with loading? It looks as if each consecutive Render call(my function) prevented the drawing in the previous call...
You have a call to glClear() in your Render() method:
// clear Screen and Depth Buffer, we have set the clear color as black.
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
This does pretty much what the name suggests, and what's also captured in your comment: It clears all rendering that has been done so far. So if you call the Render() method multiple times, only the rendering from the last call will be visible.
If you want to invoke Render() multiple times for the same frame, you will need to take it out of Render(), and call it only once at the start of rendering the frame.
There's another thing in your code that looks slightly suspicious:
int mPositionHandle = GLES20.glGetAttribLocation(riGraphicTools.sp_SolidColor, "vPosition");
....
int mTexCoordLoc = GLES20.glGetAttribLocation(riGraphicTools.sp_Image, "a_texCoord");
Unless sp_SolidColor and sp_Image have the same value, you're querying attribute locations from two different shader programs. Since sp_Image is the program you are using, you should pass it in as the first parameter for both these calls.
I have a one big Sprite on the Scene - for example 200x200 and in the app i have an array[200][200] in which i store 0 or 1 for each pixel in big sprite.
I want to draw one more textured sprite (for example 10x10) above existing one, but i want to calculate for eache pixel in new sprite if it needs to draw it on this scene depends on provided array (if in corresponding position of the pixel in new sprite in array is '1' - i need to draw this pixel, if '0' - i don't want to draw it (maybe set alpha = 0)).
I think i can use fragment shader for each of new sprites, but i can't understand how to provide array data to the shader to calculate color for each pixel.
I think also can use fragment shader for the whole scene (if render to texture).
I am quite new in opengl and can't figure out in what way to move.
When i create resources for the scene - i try to create my mask:
mask = new float[512*512*4];
for (int i = 0; i < mask.length; i++)
{
mask[i] = 2f;
}
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 1029384756);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 1, GLES20.GL_RGBA, 512, 512, 0, GLES20.GL_RGBA, GLES20.GL_FLOAT, FloatBuffer.wrap(mask));
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
Then when i draw new item on scene i use shader:
setShaderProgram(ShaderProgram.getInstance());
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glUniform1i(RadialBlurExample.RadialBlurShaderProgram.sUniformMask, GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 1029384756);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
But i can't see new item on scene (maskVal is <0.5).
I try to find working way to pass array as a texture but i can't find it.
Upload your array as a second texture with the same dimensions as the sprite, and then when you draw the sprite, sample the second texture at the same texcoord.
If the second texture doesn't meet the mask criteria, discard the fragment
uniform sampler2d sprite;
uniform sampler2d mask;
in vec2 uv;
main() {
float maskVal = texture2D(mask, uv).r;
if(maskVal > 0.5) {
gl_FragColor = texture2D(sprite,uv);
} else {
discard;
}
}
NOTE: I've updated this code now to the working form and provided everything I attempted in an answer. Hopefully it helps somebody else with the same problem.
My texture is being shown as black (that is, no texture). I've gone through several other questions here with the same problem, but could not find a solution. I'm sure I'm missing something quite simple (likely ordering), but can't figure it out.
I setup my texture like this (GLProgram.checkError checks for GL errors and logs them -- I get no errors anywhere):
/*Bitmap*/ bitmap = BitmapFactory.decodeResource( context.getResources(),
R.drawable.gears );
int textures[] = new int[1];
GLES20.glGenTextures( 1, textures, 0 );
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
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.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, bitmap, 0);
GLProgram.checkError( "texImage2D" );
texture = textures[0];
To draw a square which should be textured I do this:
GLES20.glVertexAttribPointer(glProgram.hATex, 2, GLES20.GL_FLOAT, false,
2*SIZEOF_FLOAT, texBuffer.under);
GLProgram.checkError( "hATex" );
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 );
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(glProgram.hUTex, 0);
GLProgram.checkError( "Uniform" );
GLES20.glVertexAttribPointer( glProgram.hAttribPosition, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer.under );
GLProgram.checkError( "Vertex" );
GLES20.glDrawArrays( GLES20.GL_TRIANGLE_FAN, 0, vertexBuffer.size/COORDS_PER_VERTEX );
GLProgram.checkError( "draw" );
My vertex shader is:
precision mediump float;
attribute vec4 vPosition;
uniform mat4 mTransform;
attribute vec2 aTex;
varying mediump vec2 vTex;
void main() {
gl_Position = mTransform * vPosition;
vTex = aTex;
}
My fragment shader is:
precision mediump float;
uniform vec4 vColor;
uniform sampler2D uTex;
varying mediump vec2 vTex;
void main(void)
{
//gl_FragColor = vColor;
//testing vTex, and it is fine
//gl_FragColor = vec4( vTex[0], vTex[1], 0, 1.0 );
//so it must be uTex which is program
gl_FragColor = texture2D(uTex,vTex);
}
I left in the commented bits to show what I checked. My vTex parameter is correct, since that bit produces the expected red/green color sweep. So I assume it must be the texture itself.
Also, uTex, aTex are located via:
hATex = GLES20.glGetAttribLocation( hProgram, "aTex" );
checkError( "aTex" );
hUTex = GLES20.glGetUniformLocation( hProgram, "uTex" );
checkError( "uTex" );
My texture comes a JPG and is 64x64 in size. I checked just after loading and it has the correct size and does appear to have pixel colors (dumping a few at random were non-zero).
The code, as presented, now works. I modified it as I tried things and for the comments. I can't be sure at which step it actually started working, since it didn't work before. Here are some of the things I checked/double-checked in the process -- I presume it has to be a combination of these somehow:
Verify source image is square and a power of two in size
non-square works so long as power of 2 in both dimensions
non-power 2 works so long as TEXTURE_WRAP is set to CLAMP_TO_EDGE
Set Min/Mag to nearest
Call bindTexture during setup and in each draw
These are things I tried, and tried again now, and appear to make no different (that is, it works either way):
use bitmap options.inScaled = false (using default options works fine)
put texImage2d before/after the glTexParameter functions
add/remove mediump from vTex (mismatched works fine, probably because default)
not calling glEnableVertexAttribArray (this results in a white box, so it wasn't my problem)
changing order of vertices and texture coords (all orders work once other things are correct -- texture may be skewed, but it does appear)
changing resource format (JPG/PNG) (RGB/Grayscale)
changing object transform matrix
TEXTURE_WRAP settings (not needed in this case, works without)
In the case when it wasn't working the error was silent: calls to glGetError returned okay and glGetProgramInfoLog was empty.