c# - gl.DrawArrays 中的 AccessViolationException

标签 c# opengl access-violation

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

清除屏幕和着色器编译可以工作,但是我在第 158 行的 Gl.DrawArrays 调用中收到 AccessViolationException p>

到目前为止我所做的事情:

  • 放心的顶点数据已上传
  • 检查 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);
}

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

最佳答案

我怀疑

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。

关于c# - gl.DrawArrays 中的 AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43005460/

相关文章:

c# - 如何从 azure OAuth 2.0 token (v2) 端点获取/生成访问 token ?

c# - WPF 应用程序 - 按 F1 在浏览器中打开帮助(不适用于 CHM 文件)

opengl - QOpenGLContext 和 QGLWidget 之间的共享

c++ - 访问冲突读取位置 0xfeef002A

c++ - 负数组索引

c# - 向 mvc 中已填充的下拉列表添加额外选项

c# - IQueryable 的结构是什么?

c++ - 移植我的 C++ 应用程序以在浏览器中运行

c++ - fatal error : GL/gl. h: 没有那个文件或目录

c - 文件解析期间访问违规写入位置