OpenGL ES 2 – 纹理未显示

huangapple go评论77阅读模式
英文:

OpenGL ES 2 - Textures Are Not Displayed

问题

以下是您要翻译的内容:

在我重构代码以显示多个不同纹理之前,一切都正常工作,但现在我得到的只是比它们应该更小的黑色方块,显然它们没有任何纹理!我甚至没有触碰顶点,我不知道为什么尺寸受到影响。

屏幕截图(黑色的大方块本应覆盖整个屏幕,底部的小方块本应更大。不知道是什么影响了它们的大小)OpenGL ES 2 – 纹理未显示

着色器(它们在使用前被编译)

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)
    {
        // 代码部分已省略
    }
}

Batcher(这个类处理 OpenGL 的样板代码,以便代码库的其余部分不会让任何人眼花缭乱)

class Batcher private constructor()
{
    // 代码部分已省略
}

如果您需要进一步的帮助,请随时提问。

英文:

Before I refactored the code to display multiple different textures everything was working fine but now all I am getting are black boxes that are smaller than how their size supposed to be and obviously they don't have any textures! I didn't even touch the vertexes, I don't why the size is affected at all.
<br><br><br>
Screenshot (the black big box should've covered the whole screen and the small square at the bottom should've been way bigger. Have no clue what affected their size):OpenGL ES 2 – 纹理未显示
<br><br><br>
Shaders: (they are compiled before used)

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

const val fragmentShader_Image = &quot;precision mediump float;&quot; +
        &quot;uniform sampler2D u_texture;&quot; +
        &quot;varying vec2 v_texCoord;&quot; +
        &quot;void main() {&quot; +
        &quot;  gl_FragColor = texture2D(u_texture, v_texCoord);&quot; +
        &quot;}&quot; 

TextureLoader: (object is basically a static class in Kotlin if you are not familiar with it)

object TextureLoader
{
    var textures: Map&lt;TextureName, Int&gt; = mutableMapOf()



    fun generateTextures(nameBitmapPair: List&lt;Pair&lt;TextureName, Bitmap&gt;&gt;, screenWidth: Int, screenHeight: Int)
    {

        val textureAmount = nameBitmapPair.size

        val mutableTextureMap = mutableMapOf&lt;TextureName, Int&gt;()

        if(textureAmount &gt; 31 || textureAmount&lt; 0)
            {
                throw IllegalStateException(&quot;Texture amount is bigger than 31 or smaller than 0. Texture limit for OPEN GL is 31, it can&#39;t be bigger than it&quot;)
            }
        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(&quot;created new texture, Name = ${nameBitmapPair.get(i).first}, ID = ${textureHandles[i]}&quot;)

            }
            else
            {
                throw RuntimeException(&quot;Error loading texture.&quot;)
            }
        }
        textures = mutableTextureMap
    }
    
}

Batcher: (The class that handles the OpenGL boilerplate code so the rest of the codebase doesn't bleed anyone's eyes)

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&#39;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&#39;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&#39;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&#39;s transformation matrix
        val u_MVPMatrix = glGetUniformLocation(ShaderHelper.programTexture, &quot;u_MVPMatrix&quot;)
        val a_Position = glGetAttribLocation(ShaderHelper.programTexture, &quot;a_Position&quot;)
        val a_texCoord = glGetAttribLocation(ShaderHelper.programTexture, &quot;a_texCoord&quot;)
        val u_texture = glGetUniformLocation(ShaderHelper.programTexture, &quot;u_texture&quot;)
        glEnableVertexAttribArray(a_Position)
        glEnableVertexAttribArray(a_texCoord)

        // &quot;it&quot; 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&#39;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(&quot;UV array of the sprite is null, skipping rendering. \nSprite: ${it}&quot;)
            }
        }
    }

    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)
    }

答案1

得分: 1

被分配给纹理采样器统一变量的值不是纹理的对象编号,而应该是纹理绑定到的纹理单元。由于您的纹理绑定到纹理单元0(GL_TEXTURE0),您需要将纹理采样器统一变量指定为0(0是默认值):

glUniform1i(u_texture, 0)

glBindTexture 将纹理绑定到指定的目标和当前纹理单元。纹理单元可以通过 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。


您必须确保在绘制网格之前绑定纹理。由于您有不同的纹理,每次要使用纹理渲染几何体时都应调用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)
英文:

The value to be assigned to the texture sampler uniform is not the object number of the texture. It must be the texture unit that the texture is bound to. Since your texture is bound to texture unit 0 (GL_TEXTURE0), you need to assign 0 to the texture sampler uniform (0 is default):

<s>glUniform1i(u_texture, TextureLoader.textures.get(it.textureName)!!)</s>

glUniform1i(u_texture, 0)

glBindTexture binds a texture to the specified target and the current texture unit. The texture unit can be set by glActiveTexture.


If you do

glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[i])

then you have to assign 0 to the texture sampler. But if you do

glActiveTexture(GLES20.GL_TEXTURE1)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[i])

then you have to assign 1 to the texture sampler.


You have to ensure that the texture is bound before drawing the mesh. Since you have different textures, glBindTexture should be called each time when you are going to render a geometry with a texture: For instance:

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)

huangapple
  • 本文由 发表于 2020年10月24日 22:14:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/64514271.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定