OpenTK GL.DrawElements导致GL_INVALID_OPERATION错误

时间:2015-05-27 09:33:46

标签: c# opengl opengl-3 opentk

如标题中所述,我从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(TexCoords)。然后我用这个函数绘制模型:

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错误,但现在根本没有任何渲染。我再也看不出问题所在。

修改 修复了未正确将Vertices转换为Position,Normal和TexCoord数组的问题。

1 个答案:

答案 0 :(得分:0)

我原来的问题的解决方案是使用顶点数组,因为从OpenGL 3.1 Core到OpenGL 3.2 Core的弃用,尝试渲染而没有抛出GL_INVALID_OPERATION错误。之后我遇到了另一个没有渲染的问题,这是我的一个简单错误,而不是重新绑定GL_ELEMENT_ARRAY_BUFFER。主帖中的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 );
}