GLES20 texture does not work on some devices

I tried to add a fairly simple extension on top of the Android OpenGL 2.0 sample project to add texturing to the main shapes. This one seems pretty simple, but on some devices (Samsung Nexus S, LG Optimus 3D, Samsung Galaxy S) the texture just doesn't display.

This is actually a problem that I am experiencing in a much larger project, but I was able to reproduce the problem with a simple project below, hoping that someone here has an idea of ​​where my code represents the problems, or how specifically for GL texture textures for these devices (there may be problems with the devices).

To give an idea of ​​how this object is used: In the GLSurfaceView.Renderer onSurfaceCreated method, I create an instance of the Square() object, and in the onDrawFrame method I call the Square draw() method. However, all the appropriate texture-processing code should appear in this square class, which almost exactly matches Google’s own example.

Many thanks in advance to everyone who hacked this.

 class Square { 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;" + "attribute vec2 a_TexCoordinate;" + "varying vec2 v_TexCoordinate;" + "void main() {" + // the matrix must be included as a modifier of gl_Position " gl_Position = vPosition * uMVPMatrix;" + " v_TexCoordinate = a_TexCoordinate;" + "}"; private final String fragmentShaderCode = "precision mediump float;" + "uniform sampler2D u_Texture;" + "varying vec2 v_TexCoordinate;" + "void main() {" + " gl_FragColor = texture2D(u_Texture, v_TexCoordinate);" + "}"; private final FloatBuffer vertexBuffer; private final FloatBuffer textureBuffer; private final ShortBuffer drawListBuffer; private final int mProgram; private int mPositionHandle; private int mColorHandle; private int mMVPMatrixHandle; // number of coordinates per vertex in this array static final int COORDS_PER_VERTEX = 3; static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left -0.5f, -0.5f, 0.0f, // bottom left 0.5f, -0.5f, 0.0f, // bottom right 0.5f, 0.5f, 0.0f }; // top right final float[] previewTextureCoordinateData = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f }; private int textureDataHandle; private int textureUniformHandle; private int textureCoordinateHandle; private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex // Set color with red, green, blue and alpha (opacity) values float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f }; private 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 Square(Context context) { // initialize vertex byte buffer for shape coordinates ByteBuffer bb = ByteBuffer.allocateDirect( // (# of coordinate values * 4 bytes per float) squareCoords.length * 4); bb.order(ByteOrder.nativeOrder()); vertexBuffer = bb.asFloatBuffer(); vertexBuffer.put(squareCoords); vertexBuffer.position(0); // initialize byte buffer for the draw list ByteBuffer dlb = ByteBuffer.allocateDirect( // (# of coordinate values * 2 bytes per short) drawOrder.length * 2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer = dlb.asShortBuffer(); drawListBuffer.put(drawOrder); drawListBuffer.position(0); ByteBuffer texCoordinates = ByteBuffer.allocateDirect(previewTextureCoordinateData.length * 4); texCoordinates.order(ByteOrder.nativeOrder()); textureBuffer = texCoordinates.asFloatBuffer(); textureBuffer.put(previewTextureCoordinateData); textureBuffer.position(0); // prepare shaders and OpenGL program int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); textureDataHandle = loadTexture(context, R.drawable.color_texture); 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 } public void draw(float[] mvpMatrix) { // Add program to OpenGL environment GLES20.glUseProgram(mProgram); // get handle to vertex shader vPosition member mPositionHandle = GLES20.glGetAttribLocation(mProgram, "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); textureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate"); GLES20.glVertexAttribPointer(textureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, textureBuffer); GLES20.glEnableVertexAttribArray(textureCoordinateHandle); textureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture"); MyGLRenderer.checkGlError("glGetUniformLocation"); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandle); GLES20.glUniform1i(textureUniformHandle, 0); // get handle to shape transformation matrix mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); MyGLRenderer.checkGlError("glGetUniformLocation"); // Apply the projection and view transformation GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); MyGLRenderer.checkGlError("glUniformMatrix4fv"); // Draw the square GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); // Disable vertex array GLES20.glDisableVertexAttribArray(mPositionHandle); } } 
+2
android opengl-es texture-mapping nexus-s texture2d
source share
1 answer

I assume this is a Strength Two issue.

By default, the GL_TEXTURE_WRAP parameter for glTexParameter set to GL_REPEAT , and textures that use GL_REPEAT should be doubled in size:

Similarly, if the width or height of the texture image is not powers of two, and either GL_TEXTURE_MIN_FILTER is set to one of the functions requiring mipmaps or GL_TEXTURE_WRAP_S or GL_TEXTURE_WRAP_T do not set the value GL_CLAMP_TO_EDGE , then the texture image block will return (R, G, 0, A) = , 0, 0, 1).

You can start with a texture with a power of two, but when you use BitmapFactory.decodeResource to generate a bitmap, it helps (?) Scale it based on the density of the device. For example, if you download the original texture 512 * 512 from the drawable folder on the HDPI device, I believe that it scales it by 1.5 times, so you are left with something that is not Po2.

This gives you the result that your textures do not work on a ton of devices, because these devices have a density that forces you to create illegal texture sizes.

The solution in this case is to place the source texture (power 2) in the drawable-nodpi resource folder, which will prevent density-based scaling. Either that, or use CLAMP_TO_EDGE, which doesn't care about Po2.

+4
source share

All Articles