创建网格和启动窗口 SDL/GLEW C++ 时访问冲突

Posted

技术标签:

【中文标题】创建网格和启动窗口 SDL/GLEW C++ 时访问冲突【英文标题】:Access violation when creating a mesh and launching the window SDL/GLEW C++ 【发布时间】:2019-08-30 10:18:15 【问题描述】:

我目前正在学习 openGL 课程,在将我的代码组织到类中时,我在控制台终端上遇到了访问冲突错误。 SDL 窗口创建失败! (我将它编程为在无法创建窗口时输出)

这是我的代码: main.cpp

#include <stdio.h>
#include <string.h>
#include <cmath>
#include <vector>
#include <GL/glew.h>
#define SDL_MAIN_HANDLED
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "Window.h"
#include "Mesh.h"
#include "Shader.h"

//Window dimensions
const GLint width = 800, height = 600;
const float toRadians = 3.14159265f / 180.0f;

Window mainWindow;
std::vector<Mesh*> meshList;
std::vector<Shader*> shaderList;

bool direction = true;
float triOffSet = 0.0f;
float triMaxOffSet = 0.7f;
float triIncrement = 0.010f;

float curAngle = 0.0f;

bool sizeDirection = true;
float curSize = 0.4f;
float maxSize = 0.8f;
float minSize = 0.1f;

//Vertex shader
static const char* vShader = "Shaders/shader.vert";

//Fragment shader
static const char* fShader = "Shaders/shader.frag";




void CreateObjects() 
    unsigned int indices[] = 
        0, 3, 1,
        1, 3, 2,
        2, 3, 0,
        0, 1, 2
    ;
    GLfloat vertices[] = 
        -1.0f, -1.0f, 0.0f,
        0.0f, -1.0f, 1.0f,
        1.0f, -1.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    ;
    Mesh* obj1 = new Mesh();
    obj1->CreateMesh(vertices, indices, 12, 12);
    meshList.push_back(obj1);

    Mesh* obj2 = new Mesh();
    obj2->CreateMesh(vertices, indices, 12, 12);
    meshList.push_back(obj2);

    Mesh* obj3 = new Mesh();
    obj3->CreateMesh(vertices, indices, 12, 12);
    meshList.push_back(obj3);


void CreateShaders() 
    Shader *shader1 = new Shader();
    shader1->CreateFromFiles(vShader, fShader);
    shaderList.push_back(shader1);


int main() 
    mainWindow = Window(800, 600);
    mainWindow.Initialise();
    CreateObjects();
    CreateShaders();

    GLuint uniformProjection = 0, uniformModel = 0;

    glm::mat4 projection = glm::perspective(45.0f, (GLfloat)mainWindow.getBufferWidth() / mainWindow.getBufferHeight(), 0.1f, 100.0f);

    SDL_Event windowEvent;
    while (true) 
        if (SDL_PollEvent(&windowEvent)) 
            if (windowEvent.type == SDL_QUIT) 
                break;
            
        

        if (direction) 
            triOffSet += triIncrement;
        
        else 
            triOffSet -= triIncrement;
        

        if (abs(triOffSet) >= triMaxOffSet) 
            direction = !direction;
        

        curAngle += 1.0f;
        if (curAngle >= 360) 
            curAngle -= 360;
        

        if (direction) 
            curSize += 0.001f;
        
        else 
            curSize -= 0.001f;
        

        if (curSize >= maxSize || curSize <= minSize) 
            sizeDirection = !sizeDirection;
        

        //Clear window
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        shaderList[0]->UseShader();
        uniformModel = shaderList[0]->GetModelLocation();
        uniformProjection = shaderList[0]->GetProjectionLocation();

        glm::mat4 model(1.0f);
        model = glm::translate(model, glm::vec3(0.0f, 0.0f, -2.5f));
        model = glm::rotate(model, curAngle * toRadians, glm::vec3(0.0f, 1.0f, 0.0f));
        model = glm::scale(model, glm::vec3(0.4f, 0.4f, 1.0f));

        glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
        glUniformMatrix4fv(uniformProjection, 1, GL_FALSE, glm::value_ptr(projection));

        meshList[0]->RenderMesh();

        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(-triOffSet, 1.0f, -2.5f));
        model = glm::scale(model, glm::vec3(0.4f, 0.4f, 1.0f));

        glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
        meshList[1]->RenderMesh();

        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(triOffSet, -1.0f, -2.5f));
        model = glm::scale(model, glm::vec3(0.4f, 0.4f, 1.0f));

        glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
        meshList[2]->RenderMesh();

        glUseProgram(0);
        mainWindow.swapWindows();
    
    return 0;

Mesh.h

#pragma once

#include <GL/glew.h>

class Mesh

private:
    GLuint VAO, VBO, IBO;
    GLsizei indexCount;
public:
    Mesh();
    void CreateMesh(GLfloat *vertices, unsigned int *indices, unsigned int numOfVertices, unsigned int numOfIndices);
    void RenderMesh();
    void ClearMesh();
    ~Mesh();
;

Mesh.cpp

#include "Mesh.h"
#include <GL/glew.h>

Mesh::Mesh() 
    VAO = 0;
    VBO = 0;
    IBO = 0;
    indexCount = 0;


void Mesh::CreateMesh(GLfloat* vertices, unsigned int* indices, unsigned int numOfVertices, unsigned int numOfIndices) 
    indexCount = numOfIndices;

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1, &IBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * numOfIndices, indices, GL_STATIC_DRAW);

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * numOfVertices, vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);


void Mesh::RenderMesh() 
    glBindVertexArray(VAO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
    glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);


void Mesh::ClearMesh() 
    if (IBO != 0) 
        glDeleteBuffers(1, &IBO);
        IBO = 0;
    
    if (VBO != 0) 
        glDeleteBuffers(1, &VBO);
        VBO = 0;
    
    if (VAO != 0) 
        glDeleteBuffers(1, &VAO);
        VAO = 0;
    
    indexCount = 0;

Mesh::~Mesh() 
    ClearMesh();

着色器.h

#pragma once

#include <stdio.h>
#include <string>
#include <iostream>
#include <fstream>

#include <GL/glew.h>
class Shader

private:
    GLuint shaderID, uniformProjection, uniformModel;
    void CompileShader(const char* vertexCode, const char* fragmentCode);
    void AddShader(GLuint theProgram, const char* shaderCode, GLenum shaderType);
public:
    Shader();
    void CreateFromString(const char* vertexCode, const char* fragmentCode);
    void CreateFromFiles(const char* vertexLocation, const char* fragmentLocation);

    std::string ReadFile(const char* fileLocation);

    GLuint GetProjectionLocation();
    GLuint GetModelLocation();
    void UseShader();
    void ClearShader();
    ~Shader();
;

着色器.cpp

#include "Shader.h"

Shader::Shader()

    shaderID = 0;
    uniformModel = 0;
    uniformProjection = 0;


void Shader::CreateFromString(const char* vertexCode, const char* fragmentCode)

    CompileShader(vertexCode, fragmentCode);



void Shader::CreateFromFiles(const char* vertexLocation, const char* fragmentLocation)

    std::string vertexString = ReadFile(vertexLocation);
    std::string fragmentString = ReadFile(fragmentLocation);
    const char* vertexCode = vertexString.c_str();
    const char* fragmentCode = fragmentString.c_str();

    CompileShader(vertexCode, fragmentCode);


std::string Shader::ReadFile(const char* fileLocation)

    std::string content;
    std::ifstream fileStream(fileLocation, std::ios::in);

    if (!fileStream.is_open()) 
        printf("Failed to read %s! File doesn't exist.", fileLocation);
        return "";
    

    std::string line = "";
    while (!fileStream.eof())
    
        std::getline(fileStream, line);
        content.append(line + "\n");
    

    fileStream.close();
    return content;


void Shader::CompileShader(const char* vertexCode, const char* fragmentCode)

    shaderID = glCreateProgram();

    if (!shaderID)
    
        printf("Error creating shader program!\n");
        return;
    

    AddShader(shaderID, vertexCode, GL_VERTEX_SHADER);
    AddShader(shaderID, fragmentCode, GL_FRAGMENT_SHADER);

    GLint result = 0;
    GLchar eLog[1024] =  0 ;

    glLinkProgram(shaderID);
    glGetProgramiv(shaderID, GL_LINK_STATUS, &result);
    if (!result)
    
        glGetProgramInfoLog(shaderID, sizeof(eLog), NULL, eLog);
        printf("Error linking program: '%s'\n", eLog);
        return;
    

    glValidateProgram(shaderID);
    glGetProgramiv(shaderID, GL_VALIDATE_STATUS, &result);
    if (!result)
    
        glGetProgramInfoLog(shaderID, sizeof(eLog), NULL, eLog);
        printf("Error validating program: '%s'\n", eLog);
        return;
    

    uniformProjection = glGetUniformLocation(shaderID, "projection");
    uniformModel = glGetUniformLocation(shaderID, "model");


GLuint Shader::GetProjectionLocation()

    return uniformProjection;

GLuint Shader::GetModelLocation()

    return uniformModel;


void Shader::UseShader()

    glUseProgram(shaderID);


void Shader::ClearShader()

    if (shaderID != 0)
    
        glDeleteProgram(shaderID);
        shaderID = 0;
    

    uniformModel = 0;
    uniformProjection = 0;



void Shader::AddShader(GLuint theProgram, const char* shaderCode, GLenum shaderType)

    GLuint theShader = glCreateShader(shaderType);

    const GLchar* theCode[1];
    theCode[0] = shaderCode;

    GLint codeLength[1];
    codeLength[0] = strlen(shaderCode);

    glShaderSource(theShader, 1, theCode, codeLength);
    glCompileShader(theShader);

    GLint result = 0;
    GLchar eLog[1024] =  0 ;

    glGetShaderiv(theShader, GL_COMPILE_STATUS, &result);
    if (!result)
    
        glGetShaderInfoLog(theShader, sizeof(eLog), NULL, eLog);
        printf("Error compiling the %d shader: '%s'\n", shaderType, eLog);
        return;
    

    glAttachShader(theProgram, theShader);


Shader::~Shader()

    ClearShader();

窗口.h

#pragma once

#include <stdio.h>
#include <GL/glew.h>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>

class Window

private:
    SDL_Window* mainWindow;
    SDL_Event windowEvent;
    GLint width, height;
public:
    Window();
    Window(GLint windowWidth, GLint windowHeight);

    int Initialise();
    GLint getBufferWidth()  return width; 
    GLint getBufferHeight()  return height; 

    void swapWindows()  SDL_GL_SwapWindow(mainWindow); 
    ~Window();
;

窗口.cpp

#include "Window.h"

Window::Window() 
    width = 800;
    height = 600;


Window::Window(GLint width, GLint height) 
    width = width;
    height = height;


int Window::Initialise() 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) 
        printf("SDL initialisation failed\n");
        SDL_Quit();
        return 1;
    

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

    mainWindow = SDL_CreateWindow("Test game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL);
    if (!mainWindow) 
        printf("SDL window creation failed!\n");
        SDL_Quit();
        return 1;
    

    //Set context for GLEW to use
    SDL_GLContext context = SDL_GL_CreateContext(mainWindow);

    //Allow modern extension features
    glewExperimental = GL_TRUE;

    if (glewInit() != GLEW_OK) 
        printf("GLEW initialization failed!\n");
        SDL_DestroyWindow(mainWindow);
        SDL_Quit();
        return 1;
    

    glEnable(GL_DEPTH_TEST);

    //Setup viewport size
    glViewport(0, 0, 800, 600);


Window::~Window() 
    SDL_DestroyWindow(mainWindow);
    SDL_Quit();

我听说对此的解决方案可能是将 glewExperimental = GL_True 放在 glewInit() 之前,但这没有奏效,因为这两行在 Window.cpp 中,我不知道这会如何影响网格。 cpp.

调试在底部读取: 在 OpenGLCourseApp.exe 中的 0x00000000 处引发异常:0xC0000005:访问冲突执行位置 0x00000000。

Call stack

【问题讨论】:

请在调试器下运行您的进程并在此处添加堆栈跟踪。 如果没有窗口,就没有上下文,这意味着网格创建将调用尚未从 OpenGL dll 中获取的函数。 @Botjie 刚刚更新了底部的帖子,这有帮助吗,还是您需要别的东西? 不,那没用。我们需要一个实际的堆栈跟踪,其中包含被调用的函数。 @Botjie 添加了调用堆栈的图像,有帮助吗? 【参考方案1】:

您的 Window 构造函数实际上并未初始化 Window 对象的字段,这意味着您使用随机的 widthheight 调用 SDL_CreateWindow。 改用初始化列表,它不会遇到这个问题:

Window::Window(int width, int height) 
  : width(width), height(height) 

一旦你克服了这一点,请记住声明

mainWindow = Window(800, 600);

将创建一个临时的Window 对象,将其分配给mainWindow,然后立即销毁它! 我建议您将mainWindow 的类型更改为Window*(或者更好的是std::unique_ptr&lt;Window&gt;), 并将该行更改为

mainWindow = new Window(800, 600);

mainWindow = std::make_unique<Window>(800, 600);

【讨论】:

对不起@Botje,我有点困惑,你能在我的代码中举一个你的实现例子吗? 用我的版本更改Window::Window的定义,将Window mainWindow的声明更改为Window * mainWindow,将初始化更改为我上面发布的内容,并将mainWindow的所有用途更改为使用-&gt; 而不是 .

以上是关于创建网格和启动窗口 SDL/GLEW C++ 时访问冲突的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL VBO 不显示

具有 0 个颜色位和 0 个深度位的 SDL2 OpenGL 4.2 上下文

MSYS2 上的 GLEW APIENTRY 警告和可能相关的错误

OpenGL glGenVertexArray() 异常

在 C++ 中的 Windows 应用程序中构建类似 Excel 的数据网格

如何使用具有绝对布局的框架在网格顶部创建弹出窗口?