【问题标题】:Why does my OpenGL ES app crash on glDrawElements?为什么我的 OpenGL ES 应用程序在 glDrawElements 上崩溃?
【发布时间】:2020-09-02 14:11:52
【问题描述】:

我在 Xamarin(使用 OpenTK)上使用 OpenGL ES 3 开发了一款手机游戏。它在大多数设备上运行良好,但在某些设备上崩溃(HUAWEI Y5 lite)。不幸的是,我没有得到详细的错误日志:

  #00  pc 0000000000093d2a  /vendor/lib/egl/libGLESv2_mtk.so
  #01  pc 000000000001c137  /vendor/lib/egl/libGLESv2_mtk.so
  #02  pc 000000000001eddf  /vendor/lib/egl/libGLESv2_mtk.so
  #03  pc 000000000001af75  /vendor/lib/egl/libGLESv2_mtk.so
  #04  pc 000000000001aabf  /vendor/lib/egl/libGLESv2_mtk.so (glDrawElements+54)
  #05  pc 000000000000ca0c  <anonymous>

我猜这与我的绘图代码有关,或者更糟糕的是与手机的某些驱动程序问题有关。我正在使用以下代码来渲染四边形:

public void BeforeRender()
{
    // Use shader program.
    GL.UseProgram(shader.Program);

    // Enable transparency
    GL.Enable(EnableCap.Blend);
    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

    // Use texture
    GL.ActiveTexture(TextureUnit.Texture0);
    GL.Uniform1(shader.UniformTexture, 0);

    // Only bind once for all quads
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBufferId);
}

public void Render(Sprite sprite, Vector4 color, Matrix4 modelViewProjection)
{            
    // Set model view projection
    GL.UniformMatrix4(shader.UniformModelViewProjection, false, ref modelViewProjection);

    // Set color
    GL.Uniform4(shader.UniformColor, color);

    // Set texture
    GL.BindTexture(TextureTarget.Texture2D, sprite.TextureId);

    // Update attribute value Position
    GL.BindBuffer(BufferTarget.ArrayBuffer, sprite.Vbo);
    GL.VertexAttribPointer(shader.AttribVertex, 3, VertexAttribPointerType.Float, false, sizeof(float) * 5, IntPtr.Zero); // 3 + 2 = 5
    GL.EnableVertexAttribArray(shader.AttribVertex);

    // Update attribute value TexCoord
    GL.VertexAttribPointer(shader.AttribTexCoord, 2, VertexAttribPointerType.Float, false, sizeof(float) * 5, new IntPtr(sizeof(float) * 3));
    GL.EnableVertexAttribArray(shader.AttribTexCoord);

    // Draw quad
    GL.DrawElements(BeginMode.Triangles, faceIndexes.Length, DrawElementsType.UnsignedShort, IntPtr.Zero); 
}

public void AfterRender()
{
    // Unbind / Disable
    GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
    GL.Disable(EnableCap.Blend);
}

要绘制多个四边形,我只需调用如下方法:

BeforeRender();

foreach(var sprite in sprites)
{
    Render(sprite);
}

AfterRender();

我的代码总体上是否有问题,可能会在某些设备上导致其他设备“容忍”的问题?

提前致谢!

更新:

这是我创建缓冲区的方法:

public int Load<T>(T[] data) 
        where T : struct
    {
        int bufferId;

        GL.GenBuffers(1, out bufferId);

        bufferIds.Add(bufferId);

        GL.BindBuffer(BufferTarget.ArrayBuffer, bufferId);
        GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * Marshal.SizeOf(default(T))), data, BufferUsage.StaticDraw);
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0);

        return bufferId;
    }

对于我使用的索引缓冲区:

ushort[] faceIndexes =
        {
            0, 1, 2, 1, 3, 2
        };

indexBufferId = bufferManager.Load(faceIndexes);

对于我使用的顶点缓冲区:

float[] vertices =
            {
                0f, 0f, 0f, 0f, ty,
                width, 0f, 0f, tx, ty,
                0f, height, 0f, 0f, 0f,
                width, height, 0f, tx, 0f
            };

int vboId = bufferManager.Load(vertices);

【问题讨论】:

  • 如何创建BufferTarget.ElementArrayBuffer 缓冲区?
  • 我用代码更新了我的问题。 BufferTarget.ElementArrayBuffer 只是一个枚举。感谢您的问题,我注意到,我总是在 Load 方法中使用 BufferTarget.ArrayBuffer 。您认为这可能会导致问题吗?

标签: c# android xamarin opengl-es opentk


【解决方案1】:

索引必须存储到ElementArrayBuffer 而不是ArrayBuffer

GL.BindBuffer(BufferTarget.ArrayBuffer, bufferId); ...

GL.BindBuffer(BufferTarget.ElementArrayBuffer, bufferId);
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(data.Length * Marshal.SizeOf(default(T))), data, BufferUsage.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);

target 参数添加到通用Load 方法。例如:

public int Load<T>(T[] data, BufferTarget target) 
    where T : struct
{
    int bufferId;
    GL.GenBuffers(1, out bufferId);
    bufferIds.Add(bufferId);

    GL.BindBuffer(target, bufferId);
    GL.BufferData(target, (IntPtr)(data.Length * Marshal.SizeOf(default(T))), data, BufferUsage.StaticDraw);
    GL.BindBuffer(target, 0);

    return bufferId;
}
indexBufferId = bufferManager.Load(faceIndexes, BufferTarget.ElementArrayBuffer);
int vboId = bufferManager.Load(vertices, BufferTarget.ArrayBuffer);

【讨论】:

  • 感谢您的快速答复。这正是我现在所做的。您清楚地发现了我的代码中的不一致之处。我会在收到 Android Vitals 或我的客户的反馈后立即将此答案标记为已解决!
  • 不幸的是它没有解决问题。在某些设备上仍然会出现该错误。
  • @Snaketec “在某些设备上” - 所以问题解决了,但在某些与硬件相关的设备上,您遇到了不同的问题。
  • 不是真的,因为它最初只发生在某些设备上,正如我在原始问题“HUAWEI Y5 lite”中提到的那样。所以它实际上并没有改变任何东西(因为它发生在相同的设备上)。我想将其标记为已解决,但事实并非如此。
  • @Snaketec 所以问题与代码无关。跟硬件有关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多