drawwelements导致GL_INVALID_OPERATION错误

本文关键字:OPERATION 错误 INVALID drawwelements GL 导致 | 更新日期: 2023-09-27 17:50:49

如标题所述,我从glDrawElements得到GL_INVALID_OPERATION错误,然而,这只发生在GL 3.1以上的GL上下文中,在3.1上下文中,它呈现正确,没有问题。我的模型是这样加载的:

public IModel LoadData( Shape a_Shape ) {
        int VertexStride = BlittableValueType<Vertex>.Stride;
        int IndexStride = sizeof ( uint );
        m_Backing = a_Shape;
        m_GLDataBuffer = GL.GenBuffer( );
        GL.BindBuffer( BufferTarget.ArrayBuffer, m_GLDataBuffer );
        GL.BufferData( BufferTarget.ArrayBuffer, ( IntPtr ) ( m_Backing.Vertices.Count * VertexStride ), m_Backing.Vertices.ToArray( ), BufferUsageHint.StaticDraw );
        m_GLIndexBuffer = GL.GenBuffer( );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, m_GLIndexBuffer );
        GL.BufferData( BufferTarget.ElementArrayBuffer, ( IntPtr ) ( m_Backing.Indices.Count * IndexStride ), m_Backing.Indices.ToArray( ), BufferUsageHint.StaticDraw );
        GL.EnableVertexAttribArray( 0 );
        GL.EnableVertexAttribArray( 1 );
        GL.EnableVertexAttribArray( 2 );
        GL.VertexAttribPointer( 0, 3, VertexAttribPointerType.Float, false, VertexStride, 0 );
        GL.VertexAttribPointer( 1, 3, VertexAttribPointerType.Float, false, VertexStride, ( sizeof ( float ) * 3 ) );
        GL.VertexAttribPointer( 2, 2, VertexAttribPointerType.Float, false, VertexStride, ( sizeof ( float ) * 6 ) );
        GL.DisableVertexAttribArray( 2 );
        GL.DisableVertexAttribArray( 1 );
        GL.DisableVertexAttribArray( 0 );
        GL.BindBuffer( BufferTarget.ArrayBuffer, 0 );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, 0 );
        return this;
    }

其中a_Shape只是一个从文件加载或由用户定义的任意形状,它包含一个顶点列表,它只包含两个Vector3(位置和法线)和一个Vector2 (texcoord)。然后使用以下函数绘制模型:

void IModel.Draw( ) {
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, m_GLIndexBuffer );
        GL.EnableVertexAttribArray( 0 );
        GL.EnableVertexAttribArray( 1 );
        GL.EnableVertexAttribArray( 2 );
        GL.DrawElements( PrimitiveType.Triangles, m_Backing.Indices.Count, DrawElementsType.UnsignedInt, 0 ); //This is the line that's producing the Error
        GL.DisableVertexAttribArray( 2 );
        GL.DisableVertexAttribArray( 1 );
        GL.DisableVertexAttribArray( 0 );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, 0 );
    }

就像我说的,这工作得很好,直到我尝试使用3.1版本以上的GL上下文。我真的很困惑,它只是不会工作在3.1以上的事实。我看了一下,它在OpenGL参考上说:

如果非零缓冲区对象名称绑定到已启用的数组或元素数组,并且缓冲区对象的数据存储当前已映射,则生成GL_INVALID_OPERATION。

我不太明白这是什么意思,虽然。所以我想我的问题是:什么可能导致glDrawElements只在某些上下文中工作,我该如何去修复它?还是我的代码中有什么问题,我只是没有看到?

任何帮助都将是非常感激的,经过大约5个小时的努力,我想是时候寻求帮助了。

所以我重新编写了我的代码如下:

    public IModel LoadData( Shape a_Shape ) {
        m_Backing = a_Shape;
        Single[] Positions = new Single[a_Shape.Vertices.Count * 3];
        Single[] Normals = new Single[a_Shape.Vertices.Count * 3];
        Single[] TexCoords = new Single[a_Shape.Vertices.Count * 2];
        for ( int i = 0; i < Positions.Length; i += 3 ) {
            Positions[i + 0] = a_Shape.Vertices[i / 3].Position.X;
            Positions[i + 1] = a_Shape.Vertices[i / 3].Position.Y;
            Positions[i + 2] = a_Shape.Vertices[i / 3].Position.Z;
            Normals[i + 0] = a_Shape.Vertices[i / 3].Normal.X;
            Normals[i + 1] = a_Shape.Vertices[i / 3].Normal.Y;
            Normals[i + 2] = a_Shape.Vertices[i / 3].Normal.Z;
        }
        for ( int i = 0; i < TexCoords.Length; i += 2 ) {
            TexCoords[i + 0] = a_Shape.Vertices[i / 2].TexCoord.X;
            TexCoords[i + 1] = a_Shape.Vertices[i / 2].TexCoord.Y;
        }
        m_GLVertexArray = GL.GenVertexArray( );
        GL.BindVertexArray( m_GLVertexArray );
        m_GLIndexBuffer = GL.GenBuffer( );
        GL.GenBuffers( 3, m_GLDataBuffers );
        GL.EnableVertexAttribArray( 0 );
        GL.EnableVertexAttribArray( 1 );
        GL.EnableVertexAttribArray( 2 );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, m_GLIndexBuffer );
        GL.BufferData( BufferTarget.ElementArrayBuffer, ( IntPtr ) ( sizeof ( uint ) * a_Shape.Indices.Count ), a_Shape.Indices.ToArray( ), BufferUsageHint.StaticDraw );
        GL.BindBuffer( BufferTarget.ArrayBuffer, m_GLDataBuffers[0] ); // Bind the Position Buffer
        GL.BufferData( BufferTarget.ArrayBuffer, ( IntPtr ) ( sizeof ( Single ) * Positions.Length ), Positions, BufferUsageHint.StaticDraw );
        GL.VertexAttribPointer( 0, 3, VertexAttribPointerType.Float, false, 0, 0 );
        GL.BindBuffer( BufferTarget.ArrayBuffer, m_GLDataBuffers[1] ); // Bind the Normal Buffer
        GL.BufferData( BufferTarget.ArrayBuffer, ( IntPtr ) ( sizeof ( Single ) * Normals.Length ), Normals, BufferUsageHint.StaticDraw );
        GL.VertexAttribPointer( 1, 3, VertexAttribPointerType.Float, false, 0, 0 );
        GL.BindBuffer( BufferTarget.ArrayBuffer, m_GLDataBuffers[2] ); // Bind the TexCoord Buffer
        GL.BufferData( BufferTarget.ArrayBuffer, ( IntPtr ) ( sizeof ( Single ) * TexCoords.Length ), TexCoords, BufferUsageHint.StaticDraw );
        GL.VertexAttribPointer( 2, 2, VertexAttribPointerType.Float, false, 0, 0 );
        GL.BindBuffer( BufferTarget.ArrayBuffer, 0 );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, 0 );
        GL.BindVertexArray( 0 );
        return this;
    }

用于加载和:

    void IModel.Draw( ) {
        GL.BindVertexArray( m_GLVertexArray );
        GL.DrawElements( PrimitiveType.Triangles, m_Backing.Indices.Count, DrawElementsType.UnsignedInt, 0 );
        GL.BindVertexArray( 0 );
    }

对于这幅画,我使用了从Reto的评论中找到的东西。我不再得到任何GL错误,但现在没有渲染。我还是看不出问题在哪里。

编辑修复了不能正确地将顶点转换为位置、Normal和TexCoord数组的问题。

drawwelements导致GL_INVALID_OPERATION错误

我原来的问题的解决方案是使用顶点数组,因为从OpenGL 3.1 Core到OpenGL 3.2 Core的弃用,试图渲染没有抛出GL_INVALID_OPERATION错误。后来我又遇到了一个问题,没有渲染,这是我的一个简单的错误,没有重新绑定GL_ELEMENT_ARRAY_BUFFER。主post中的LoadData方法场景工作正常,最终的Draw方法如下:

    void IModel.Draw( ) {
        GL.BindVertexArray( m_GLVertexArray );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, m_GLIndexBuffer ); //Rebinding the GL_ELEMENT_ARRAY_BUFFER solved the second issue.
        GL.DrawElements( PrimitiveType.Triangles, m_Backing.Indices.Count, DrawElementsType.UnsignedInt, 0 );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, 0 );
        GL.BindVertexArray( 0 );
    }

编辑

经过进一步的讨论,我了解到在解绑定VAO之前解绑定GL_ELEMENT_ARRAY_BUFFER(从这里开始称为IBO)会导致VAO引用ID 0的IBO,而不是我想要的IBO。下面是我使用的最终代码。

    public IModel LoadData( Shape a_Shape ) {
        m_Backing = a_Shape;
        Single[] Positions = new Single[a_Shape.Vertices.Count * 3];
        Single[] Normals = new Single[a_Shape.Vertices.Count * 3];
        Single[] TexCoords = new Single[a_Shape.Vertices.Count * 2];
        for ( int i = 0; i < Positions.Length; i += 3 ) {
            Positions[i + 0] = a_Shape.Vertices[i / 3].Position.X;
            Positions[i + 1] = a_Shape.Vertices[i / 3].Position.Y;
            Positions[i + 2] = a_Shape.Vertices[i / 3].Position.Z;
            Normals[i + 0] = a_Shape.Vertices[i / 3].Normal.X;
            Normals[i + 1] = a_Shape.Vertices[i / 3].Normal.Y;
            Normals[i + 2] = a_Shape.Vertices[i / 3].Normal.Z;
        }
        for ( int i = 0; i < TexCoords.Length; i += 2 ) {
            TexCoords[i + 0] = a_Shape.Vertices[i / 2].TexCoord.X;
            TexCoords[i + 1] = a_Shape.Vertices[i / 2].TexCoord.Y;
        }
        m_GLVertexArray = GL.GenVertexArray( );
        GL.BindVertexArray( m_GLVertexArray );
        m_GLIndexBuffer = GL.GenBuffer( );
        GL.GenBuffers( 3, m_GLDataBuffers );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, m_GLIndexBuffer );
        GL.BufferData( BufferTarget.ElementArrayBuffer, ( IntPtr ) ( sizeof ( uint ) * a_Shape.Indices.Count ), a_Shape.Indices.ToArray( ), BufferUsageHint.StaticDraw );
        GL.BindBuffer( BufferTarget.ArrayBuffer, m_GLDataBuffers[0] ); // Bind the Position Buffer
        GL.BufferData( BufferTarget.ArrayBuffer, ( IntPtr ) ( sizeof ( Single ) * Positions.Length ), Positions, BufferUsageHint.StaticDraw );
        GL.VertexAttribPointer( 0, 3, VertexAttribPointerType.Float, false, 0, 0 );
        GL.EnableVertexAttribArray( 0 );
        GL.BindBuffer( BufferTarget.ArrayBuffer, m_GLDataBuffers[1] ); // Bind the Normal Buffer
        GL.BufferData( BufferTarget.ArrayBuffer, ( IntPtr ) ( sizeof ( Single ) * Normals.Length ), Normals, BufferUsageHint.StaticDraw );
        GL.VertexAttribPointer( 1, 3, VertexAttribPointerType.Float, false, 0, 0 );
        GL.EnableVertexAttribArray( 1 );
        GL.BindBuffer( BufferTarget.ArrayBuffer, m_GLDataBuffers[2] ); // Bind the TexCoord Buffer
        GL.BufferData( BufferTarget.ArrayBuffer, ( IntPtr ) ( sizeof ( Single ) * TexCoords.Length ), TexCoords, BufferUsageHint.StaticDraw );
        GL.VertexAttribPointer( 2, 2, VertexAttribPointerType.Float, false, 0, 0 );
        GL.EnableVertexAttribArray( 2 );
        GL.BindBuffer( BufferTarget.ArrayBuffer, 0 );
        GL.BindVertexArray( 0 );
        GL.BindBuffer( BufferTarget.ElementArrayBuffer, 0 );
        return this;
    }

:

void IModel.Draw( ) {
    GL.BindVertexArray( m_GLVertexArray );
    GL.DrawElements( PrimitiveType.Triangles, m_Backing.Indices.Count, DrawElementsType.UnsignedInt, 0 );
    GL.BindVertexArray( 0 );
}