java - OpenGL ES 2 - 不显示纹理

标签 java android kotlin opengl-es glsl

在我重构代码以显示多个不同的纹理之前,一切工作正常,但现在我得到的只是黑盒子,它们比它们应该的大小要小,而且显然它们没有任何纹理!我什至没有触摸顶点,我不知道为什么大小会受到影响。

截图(黑色的大框应该已经覆盖了整个屏幕,底部的小方 block 应该更大。不知道是什么影响了它们的大小) : ss

着色器:(使用前编译)

const val vertexShader_Image = "uniform mat4 u_MVPMatrix;" +
        "attribute vec4 a_Position;" +
        "attribute vec2 a_texCoord;" +
        "varying vec2 v_texCoord;" +
        "void main() {" +
        "  gl_Position = u_MVPMatrix * a_Position;" +
        "  v_texCoord = a_texCoord;" +
        "}"

const val fragmentShader_Image = "precision mediump float;" +
        "uniform sampler2D u_texture;" +
        "varying vec2 v_texCoord;" +
        "void main() {" +
        "  gl_FragColor = texture2D(u_texture, v_texCoord);" +
        "}" 
TextureLoader:(对象基本上是 Kotlin 中的一个静态类,如果你不熟悉的话)
object TextureLoader
{
    var textures: Map<TextureName, Int> = mutableMapOf()



    fun generateTextures(nameBitmapPair: List<Pair<TextureName, Bitmap>>, screenWidth: Int, screenHeight: Int)
    {

        val textureAmount = nameBitmapPair.size

        val mutableTextureMap = mutableMapOf<TextureName, Int>()

        if(textureAmount > 31 || textureAmount< 0)
            {
                throw IllegalStateException("Texture amount is bigger than 31 or smaller than 0. Texture limit for OPEN GL is 31, it can't be bigger than it")
            }
        val textureHandles = IntArray(textureAmount)
        GLES20.glGenTextures(textureAmount, textureHandles, 0)

        for (i in 0 until textureAmount)
        {
            if (textureHandles[i] != 0)
            {
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[i])

                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, nameBitmapPair.get(i).second, 0)
                nameBitmapPair.get(i).second.recycle()

                mutableTextureMap.put(nameBitmapPair.get(i).first, textureHandles[i])
                Timber.i("created new texture, Name = ${nameBitmapPair.get(i).first}, ID = ${textureHandles[i]}")

            }
            else
            {
                throw RuntimeException("Error loading texture.")
            }
        }
        textures = mutableTextureMap
    }
    
}
Batcher:(处理 OpenGL 样板代码的类,因此代码库的其余部分不会让任何人眼花缭乱)
class Batcher private constructor()
{
    // Store the model matrix. This matrix is used to move models from object space (where each model can be thought
    // of being located at the center of the universe) to world space.
    private val mtrxModel = FloatArray(16)

    // Allocate storage for the final combined matrix. This will be passed into the shader program.
    private val mtrxMVP = FloatArray(16)

    // Store the projection matrix. This is used to project the scene onto a 2D viewport.
    private val mtrxProjection = FloatArray(16)

/*    This was my UV array before I refactored the code to add animations. Now it's accessed by the 
      sprite.animator.getUvCoordinationForCurrentFrame()

      private var uvArray = floatArrayOf(
            0.0f, 0.0f,
            0.0f, 0.20f,
            0.20f, 0.20f,
            0.20f, 0.0f)
*/

    private var uvBuffer: FloatBuffer? = null
    private var vertexBuffer: FloatBuffer? = null

    private var indices = shortArrayOf(0, 1, 2, 0, 2, 3) // The order of vertexrendering.
    private var indicesBuffer: ShortBuffer? = null

    // NOTE: companion object is the static class of the Kotlin if you are not familiar with it. It's used to create a singleton here.
    companion object
    {
        private var instance: Batcher? = null

        fun getInstance(): Batcher
        {
            if (instance == null)
            {
                instance = Batcher()
            }

            return instance!!
        }
    }

    //Constructor of the Kotlin classes if you aren't familiar with it
    init
    {

        glEnable(GL_BLEND)

        // initialize byte buffer for the draw list
        indicesBuffer = ByteBuffer.allocateDirect(indices.size * 2)
            .order(ByteOrder.nativeOrder())
            .asShortBuffer()
        indicesBuffer!!.put(indices)
            .position(0)
        val vertices = floatArrayOf(
                0f, 0f, 0f,
                0f, 1.0f, 0f,
                1.0f, 1.0f, 0f,
                1.0f, 0f, 0f)

        // The vertex buffer.
        vertexBuffer = ByteBuffer.allocateDirect(vertices.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
        vertexBuffer!!.put(vertices)
            .position(0)
    }


    fun render(sprites: Sprites)
    {
        //TODO should these be called on every draw call??

        // Get handle to shape's transformation matrix
        val u_MVPMatrix = glGetUniformLocation(ShaderHelper.programTexture, "u_MVPMatrix")
        val a_Position = glGetAttribLocation(ShaderHelper.programTexture, "a_Position")
        val a_texCoord = glGetAttribLocation(ShaderHelper.programTexture, "a_texCoord")
        val u_texture = glGetUniformLocation(ShaderHelper.programTexture, "u_texture")
        glEnableVertexAttribArray(a_Position)
        glEnableVertexAttribArray(a_texCoord)

        // "it" here is the currently iterated sprite object 
        sprites.forEach{

            val uvArray = it.animator.getUvCoordinationForCurrentFrame()
            if (uvArray != null)
            {
                updateUVBuffer(uvArray)

                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

                // Matrix op - start
                Matrix.setIdentityM(mtrxMVP, 0)
                Matrix.setIdentityM(mtrxModel, 0)

                Matrix.translateM(mtrxModel, 0, it.x.toFloat(), it.y.toFloat(), 0f)
                Matrix.scaleM(mtrxModel, 0, it.scaledFrameWidth.toFloat(), it.scaledFrameHeight.toFloat(), 0f)

                if (it.isHorizontallyFlipped)
                {
                    Matrix.translateM(mtrxModel, 0, 1f, 0f, 0f)
                    Matrix.scaleM(mtrxModel, 0, -1f, 1f, 0f)
                }


                Matrix.multiplyMM(mtrxMVP, 0, mtrxModel, 0, mtrxMVP, 0)
                Matrix.multiplyMM(mtrxMVP, 0, mtrxProjection, 0, mtrxMVP, 0)


                // Matrix op - end
                // Pass the data to shaders - start
                // Prepare the triangle coordinate data
                //Binds this vertex's data to a spot in the buffer
                glVertexAttribPointer(a_Position, 3, GL_FLOAT, false, 0, vertexBuffer)

                // Prepare the texture coordinates
                glVertexAttribPointer(a_texCoord, 2, GL_FLOAT, false, 0, uvBuffer)
                glUniformMatrix4fv(u_MVPMatrix, 1, false, mtrxMVP, 0)

                // Set the sampler texture unit to where we have saved the texture.
                // second param is the active texture index
               glUniform1i(u_texture,  TextureLoader.textures.get(it.textureName)!!)

                // Draw the triangles
                glDrawElements(GL_TRIANGLES, indices.size, GL_UNSIGNED_SHORT, indicesBuffer)
            }
            else
            {
                Timber.w("UV array of the sprite is null, skipping rendering. \nSprite: ${it}")
            }
        }
    }

    fun setScreenDimension(screenWidth: Int, screenHeight: Int)
    {
        Matrix.setIdentityM(mtrxProjection, 0)

        Matrix.orthoM(mtrxProjection, 0, 0f, screenWidth.toFloat(), screenHeight.toFloat(), 0f, 0f, 1f)
    }

    private fun updateUVBuffer(uvArray: FloatArray)
    {
        uvBuffer = ByteBuffer.allocateDirect(uvArray.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
        uvBuffer!!.put(uvArray)
            .position(0)
    }

最佳答案

要分配给纹理采样器制服的值不是纹理的对象编号。它必须是纹理绑定(bind)到的纹理单元。由于您的纹理绑定(bind)到纹理单元 0 ( GL_TEXTURE0 ),因此您需要将 0 分配给纹理采样器制服(默认为 0):glUniform1i(u_texture, TextureLoader.textures.get(it.textureName)!!)

glUniform1i(u_texture, 0)
glBindTexture 将纹理绑定(bind)到指定目标和当前纹理单元。纹理单元可以通过 glActiveTexture 设置.

如果你这样做
glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[i])
那么您必须将 0 分配给纹理采样器。但如果你这样做
glActiveTexture(GLES20.GL_TEXTURE1)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[i])
那么您必须将 1 分配给纹理采样器。

您必须确保在绘制网格之前绑定(bind)纹理。由于您有不同的纹理,glBindTexture每次要使用纹理渲染几何时都应该调用它:例如:
glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,  TextureLoader.textures.get(it.textureName)!!)
glUniform1i(u_texture, 0)
glDrawElements(GL_TRIANGLES, indices.size, GL_UNSIGNED_SHORT, indicesBuffer)

关于java - OpenGL ES 2 - 不显示纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64514271/

相关文章:

Android Google Play 服务坏了? isConnected() 抛出错误

android - 在数据绑定(bind)中找不到属性的 setter

collections - 如何在Kotlin中使用不可变的持久性集合?

java - Primefaces 数据表中排序不起作用

java - 在不知道日期的情况下设置时间

java - 运行 JAR 文件时出错

java - 在输入回收器 View 时如何避免 Activity 中出现硬编码字符串?

通过 App Store 或 Google Play 下载 Android 应用程序时无法运行 - ANR

Android : Kotlin : MVVM : Why viewModel. onButtonClicked() 导致应用崩溃?

java - REST API Parse.com Java