Gl.DrawArrays中的AccessViolationException

时间:2017-03-24 17:15:53

标签: c# opengl access-violation

我正在使用OpenGL.net(通过NuGet提供)和C#,我正在尝试为现代OpenGL组建一个最小的工作示例。

清除屏幕和Shader Conpilation有效,但我在第158行的 Gl.DrawArrays 调用中收到 AccessViolationException

到目前为止我做了什么:

  • 上传了相关的Vertex数据
  • 检查Gl.DrawArrays中的计数参数是否正确
  • 选中的着色器正确并已编译
  • 检查尺寸参数在任何地方都是正确的
  • 使用OpenGL和c#
  • 在上下文中显示错误消息的google链接的前几页

代码:

using System;
using System.Text;
using System.Windows.Forms;
using System.IO;
using OpenGL;
using System.Runtime.ExceptionServices;

namespace RenderEngine
{
    public class RenderForm : Form
    {
        private Timer tmr_Render;
        private System.ComponentModel.IContainer components;
        private GlControl glc_screen;
        MemoryLock vertexArrayLock;
        uint vertexArrayID;
        uint vertexbuffer;
        uint shaderProgram;
        private static readonly float[] _ArrayPosition = new float[] {
            0.0f, 0.0f,
            0.5f, 1.0f,
            1.0f, 0.0f
        };

        private static readonly float[] _ArrayColor = new float[] {
            1.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 1.0f
        };


        public RenderForm()
        {
            InitializeComponent();
        }

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.glc_screen = new OpenGL.GlControl();
            this.tmr_Render = new System.Windows.Forms.Timer(this.components);
            this.SuspendLayout();
            // 
            // glc_screen
            // 
            this.glc_screen.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            this.glc_screen.ColorBits = ((uint)(24u));
            this.glc_screen.DepthBits = ((uint)(0u));
            this.glc_screen.Dock = System.Windows.Forms.DockStyle.Fill;
            this.glc_screen.Location = new System.Drawing.Point(0, 0);
            this.glc_screen.MultisampleBits = ((uint)(0u));
            this.glc_screen.Name = "glc_screen";
            this.glc_screen.Size = new System.Drawing.Size(784, 561);
            this.glc_screen.StencilBits = ((uint)(0u));
            this.glc_screen.TabIndex = 0;
            this.glc_screen.ContextCreated += new System.EventHandler<OpenGL.GlControlEventArgs>(this.glc_screen_ContextCreated);
            this.glc_screen.Render += new System.EventHandler<OpenGL.GlControlEventArgs>(this.glc_screen_Render);
            // 
            // tmr_Render
            // 
            this.tmr_Render.Enabled = true;
            this.tmr_Render.Interval = 16;
            this.tmr_Render.Tick += new System.EventHandler(this.tmr_Render_Tick);
            // 
            // RenderForm
            // 
            this.ClientSize = new System.Drawing.Size(784, 561);
            this.Controls.Add(this.glc_screen);
            this.Name = "RenderForm";
            this.ResumeLayout(false);

        }

        private void glc_screen_ContextCreated(object sender, GlControlEventArgs e)
        {
            GlControl glControl = (GlControl)sender;

            shaderProgram = LoadShaders("../../../RenderEngine/vertex.shader", "../../../RenderEngine/fragment.shader");

            vertexArrayID = Gl.GenVertexArray();
            Gl.BindVertexArray(vertexArrayID);
            Gl.EnableVertexAttribArray(vertexArrayID);

            vertexArrayLock = new MemoryLock(_ArrayPosition);
            vertexbuffer = Gl.GenBuffer();
            Gl.BindBuffer(BufferTargetARB.ArrayBuffer, vertexbuffer);
            Gl.BufferData(BufferTargetARB.ArrayBuffer, /*sizeof(float)*(uint)_ArrayPosition.Length*/ 100, vertexArrayLock.Address, BufferUsageARB.DynamicDraw);
            int indexInShader = 0;// Gl.GetAttribLocation(shaderProgram, "vertexPosition_modelspace");
            int floatsPerVertex = 2;
            bool normalized = false;
            int stride = floatsPerVertex*sizeof(float);
            int arrayBufferOffset = 0;
            Gl.VertexAttribPointer((uint)indexInShader, floatsPerVertex, Gl.FLOAT, normalized, stride, arrayBufferOffset);
            Gl.BindBuffer(BufferTargetARB.ArrayBuffer, 0);
        }

        private uint LoadShaders(string vertexPath, string fragmentPath) {
            uint vertexShaderId = Gl.CreateShader(Gl.VERTEX_SHADER);
            uint fragmentShaderId = Gl.CreateShader(Gl.FRAGMENT_SHADER);

            string vertexCode = File.ReadAllText(vertexPath);
            string fragmentCode = File.ReadAllText(fragmentPath);

            int vertexResult;
            int vertexInfoLogLength;
            StringBuilder vertexInfoLog = new StringBuilder(200);
            Gl.ShaderSource(vertexShaderId, new string[] { vertexCode }/*vertexCode.Split(new char[] { '\r', '\n' })*/);
            Gl.CompileShader(vertexShaderId);
            Gl.GetShader(vertexShaderId, Gl.COMPILE_STATUS, out vertexResult);
            Gl.GetShaderInfoLog(vertexShaderId, 200, out vertexInfoLogLength, vertexInfoLog);
            Console.WriteLine(vertexInfoLog.Length == 0 ? "Vertex shader compiled sucessfully" : vertexInfoLog.ToString());

            int fragmentResult;
            int fragmentInfoLogLength;
            StringBuilder fragmentInfoLog = new StringBuilder(200);
            Gl.ShaderSource(fragmentShaderId, new string[] { fragmentCode }/*fragmentCode.Split(new char[] { '\r', '\n' })*/);
            Gl.CompileShader(fragmentShaderId);
            Gl.GetShader(fragmentShaderId, Gl.COMPILE_STATUS, out fragmentResult);
            Gl.GetShaderInfoLog(fragmentShaderId, 200, out fragmentInfoLogLength, fragmentInfoLog);
            Console.WriteLine(fragmentInfoLog.Length==0 ? "Fragment shader compiled sucessfully" : fragmentInfoLog.ToString());

            uint programId = Gl.CreateProgram();
            Gl.AttachShader(programId, vertexShaderId);
            Gl.AttachShader(programId, fragmentShaderId);
            Gl.LinkProgram(programId);
            int programResult;
            int programInfoLogLength;
            StringBuilder programInfoLog = new StringBuilder(200);
            Gl.GetProgram(programId, Gl.LINK_STATUS, out programResult);
            Gl.GetProgramInfoLog(programId, 200, out programInfoLogLength, programInfoLog);
            Console.WriteLine(programInfoLog.Length == 0 ? "Program linked sucessfully" : programInfoLog.ToString());

            Gl.DetachShader(programId, vertexShaderId);
            Gl.DetachShader(programId, fragmentShaderId);

            Gl.DeleteShader(vertexShaderId);
            Gl.DeleteShader(fragmentShaderId);

            return programId;
        }

        private void glc_screen_Render(object sender, GlControlEventArgs e)
        {
            GlControl senderControl = (GlControl)sender;

            Gl.BindVertexArray(vertexArrayID);
            Gl.BindBuffer(BufferTargetARB.ArrayBuffer, vertexbuffer);


            Gl.CheckErrors();
            Console.WriteLine(Gl.GetError());
            int floatsPerVertex = 2;
            int start = 0;
            int verticies = _ArrayPosition.Length / floatsPerVertex;
            Gl.Clear(ClearBufferMask.ColorBufferBit);
            Gl.ClearColor(1f, .5f, 1f, 0f);
            Gl.UseProgram(shaderProgram);
            Gl.DrawArrays(PrimitiveType.Triangles, start, verticies);

            Gl.DisableVertexAttribArray(vertexArrayID);
        }

        private void tmr_Render_Tick(object sender, EventArgs e)
        {
            glc_screen.Invalidate();
        }
    }
} 

顶点着色器:

#version 330 core
layout(location = 0) in vec2 vertexPosition_modelspace;
void main() {
    gl_Position.xy = vertexPosition_modelspace;
    gl_Position.z = 1.0;
    gl_Position.w = 1.0;
}

片段着色器:

#version 330 core
out vec4 color;
void main() {
    color = vec4(1, 0, 0, 0);
}

我不知道此时出了什么问题,非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

我怀疑

Gl.BufferData(BufferTargetARB.ArrayBuffer, /*sizeof(float)*(uint)_ArrayPosition.Length*/ 100, vertexArrayLock.Address, BufferUsageARB.DynamicDraw);

是问题的根源。您告诉OpenGL定义一个100字节的缓冲区,并从vertexArrayLock.Address初始化内容。遗憾的是,vertexArrayLock.Address指向一个大6 * sizeof(float)= 24字节的内存。

但是,我不明白为什么你会在DrawArrays上获得例外;可能还有其他问题我没有看到。

---几分钟后---

知道了。删除行:

Gl.BindBuffer(BufferTargetARB.ArrayBuffer, 0);

来自glc_screen_ContextCreated。它将以不使用缓冲区的方式改变VAO状态。 VAO状态向量的焦点,你将获得一个成功的DrawArrays。