我的 VAO 不工作,我如何用 Cuda 改变它?

My VAO doesn't work, and how do I change it with Cuda?

我正在尝试使用 Cuda 10.1 和 OpenGL 4.6 互操作在屏幕上绘制一堆点。但是,现在我只是从 CPU 加载一个三角形进行测试。但是,我是 OpenGL 的新手,这是我第一次编写顶点数组对象。所以我想我的第一个问题是:我的 VAO 代码有什么问题?为什么我的三角形不绘制?我已经尽我最大的能力去弄明白了。 我的第二个问题: 如果我用 Cuda 更改与 VAO 关联的两个 VBO 中的数据,VAO 是否仍会更新并绘制更改?

这是我的代码(抱歉,它没有注释,我时间紧迫):

GPUmain.h:

#include <cuda_runtime.h>
#include "device_launch_parameters.h"
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/remove.h>
#include <curand.h>
#include <GL/glew.h>
#include <SDL_opengl.h>
#include <cuda_gl_interop.h>

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

struct pos {

    GLint x, y, z;

};

struct col {

    GLubyte r, g, b, a;

};

struct phy {

    GLdouble spd;

    GLdouble dir;

};

struct ver {

    pos p;

    col c;

};

class GPU {

public:

    static int nParticles;

    static GLuint vboidP;

    static GLuint vboidC;

    static GLuint vaoid;

    static GLuint vrshaderid;

    static GLuint frshaderid;

    static GLuint lkshaderid;

    static cudaGraphicsResource *CGRp;

    static cudaGraphicsResource *CGRc;

    static const char* shaders[2];

    static thrust::device_vector<ver> verts;

    static void init(int w, int h);

    static void compute();

    static void render();

    static void GPUmain();

    static void free();

};

GPUmain.cu:

#include "GPUmain.cuh"

__global__ void uploadVerts(ver *ve, pos *po, col *co) {
    int id = threadIdx.x + (blockDim.x * blockIdx.x);
    po[id].x = ve[id].p.x;
    po[id].y = ve[id].p.y;
    po[id].z = ve[id].p.z;
    co[id].r = ve[id].c.r;
    co[id].g = ve[id].c.g;
    co[id].b = ve[id].c.b;
    co[id].a = ve[id].c.a;
}

__global__ void genGrid(ver *v) {
    int i = threadIdx.x + (blockDim.x * blockIdx.x);
    int x = i % 1920;
    int y = i / 1920;

    v[i].p.x = x;
    v[i].p.y = y;
    v[i].p.z = 0;

    v[i].c.r = 127;
    v[i].c.g = 255;
    v[i].c.b = 0;
    v[i].c.a = 255;
}

int GPU::nParticles;

GLuint GPU::vboidP;

GLuint GPU::vboidC;

GLuint GPU::vaoid;

GLuint GPU::vrshaderid;

GLuint GPU::frshaderid;

GLuint GPU::lkshaderid;

cudaGraphicsResource *GPU::CGRp;

cudaGraphicsResource *GPU::CGRc;

const char* GPU::shaders[2] = {
    "#version 460\n"
    "layout(location = 0) in vec3 vertex_position;"
    "layout(location = 1) in vec4 vertex_colour;"
    "out vec4 colour;"
    "void main() {"
    "   colour = vertex_colour;"
    "   gl_Position = vec4(vertex_position, 1.0);"
    "}"
    ,
    "#version 460\n"
    "in vec4 colour;"
    "out vec4 frag_colour;"
    "void main() {"
    "   frag_colour = colour;"
    "}"
};

//collection of vertices to be simulated and rendered
thrust::device_vector<ver> GPU::verts;



void GPU::init(int w, int h)
{

    /*nParticles = w * h;
    verts.resize(nParticles, ver{ pos{0,0,0}, col{255,0,0,255} });
    genGrid<<<nParticles/1024,1024>>>(thrust::raw_pointer_cast(&verts[0]));
    cudaDeviceSynchronize();*/

    pos vp[3] = {
        pos{0,0,0},
        pos{200,0,4},
        pos{100,200,3}

    };
    col vc[3] = {
        col{255,0,0,255},
        col{0,255,0,255},
        col{0,0,255,255}
    };

    vrshaderid = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vrshaderid, 1, &shaders[0], NULL);
    glCompileShader(vrshaderid);
    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vrshaderid, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vrshaderid, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    frshaderid = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(frshaderid, 1, &shaders[1], NULL);
    glCompileShader(frshaderid);
    glGetShaderiv(frshaderid, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(frshaderid, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    lkshaderid = glCreateProgram();
    glAttachShader(lkshaderid, vrshaderid);
    glAttachShader(lkshaderid, frshaderid);
    glLinkProgram(lkshaderid);
    glGetProgramiv(lkshaderid, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(lkshaderid, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }

    glGenVertexArrays(1, &vaoid);
    glGenBuffers(1,&vboidP);
    glGenBuffers(1, &vboidC);
    glBindVertexArray(vaoid);

    glBindBuffer(GL_ARRAY_BUFFER,vboidP);
    glBufferData(GL_ARRAY_BUFFER,3*sizeof(pos),vp,GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_INT, GL_TRUE, 3 * sizeof(pos), NULL);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vboidC);
    glBufferData(GL_ARRAY_BUFFER,3*sizeof(col),vc, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 3 * sizeof(col), NULL);
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    /*cudaGraphicsGLRegisterBuffer(&CGRp,vboidP,cudaGraphicsMapFlagsWriteDiscard);
    cudaGraphicsGLRegisterBuffer(&CGRc,vboidC, cudaGraphicsMapFlagsWriteDiscard);*/

    glBindVertexArray(0);

}

void GPU::compute()
{

}

void GPU::render()
{
    /*pos *posi;
    col *cols;

    size_t sizep;
    size_t sizec;

    cudaGraphicsMapResources(1, &CGRp, 0);
    cudaGraphicsMapResources(1, &CGRc, 0);

    cudaGraphicsResourceGetMappedPointer((void**)&posi, &sizep, CGRp);
    cudaGraphicsResourceGetMappedPointer((void**)&cols, &sizec, CGRc);

    uploadVerts<<<nParticles/1024, 1024>>>(thrust::raw_pointer_cast(&verts[0]), posi, cols);
    cudaDeviceSynchronize();

    cudaGraphicsUnmapResources(1, &CGRp, 0);
    cudaGraphicsUnmapResources(1, &CGRc, 0);*/

    glClearColor(0, 0, 0, 0); // we clear the screen with black (else, frames would overlay...)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the buffer

    glUseProgram(lkshaderid);

    glBindVertexArray(vaoid);

    glDrawArrays(GL_TRIANGLES,0,3);

    glBindVertexArray(0);
}

void GPU::GPUmain()
{

    compute();

    render();

}

void GPU::free()
{
    /*cudaGraphicsUnregisterResource(CGRp);
    cudaGraphicsUnregisterResource(CGRc);*/
    glDeleteVertexArrays(1,&vaoid);
    glDeleteBuffers(1, &vboidP);
    glDeleteBuffers(1, &vboidC);
    verts.clear();
    thrust::device_vector<ver>().swap(verts);
}

window.cpp:

bool Window::init()
{
    //initialize SDL
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {

        log << "Failed to initialize SDL!\n";
        return false;

    }

    //set window atributes
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);

    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);



    //creat window
    window = SDL_CreateWindow(
        name.c_str(),
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        width,
        height,
        SDL_WINDOW_OPENGL

    );

    //create opengl context in the window
    glcontext = SDL_GL_CreateContext(window);

    SDL_GL_SetSwapInterval(1);

    //check if the window was created
    if (window == nullptr) {

        log << "Failed to create window!\n";
        return false;

    }

    //turn on experimental features
    glewExperimental = GL_TRUE;

    //initiallize glew
    if (glewInit() != GLEW_OK) {

        log << "Failed to Init GLEW";

        return false;

    }



    //set drawing parameters
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, width, 0, height, -255, 0);
    glPointSize(1);
    glEnable(GL_BLEND);                                // Allow Transparency
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  // how transparency acts

    std::cout << sizeof(ver);

    GPU::init(width, height);

    return true;
}

void Window::renderFrame()
{

    GPU::render();

    SDL_GL_SwapWindow(window); //swap buffers
}

属性的类型为整数数据类型:

struct pos {
    GLint x, y, z;
};

struct col {
    GLubyte r, g, b, a;
};

所以当你设置通用顶点属性数据的数组时,你必须使用glVertexAttribIPointer(关注I),而不是glVertexAttribPointer.
顶点着色器属性的数据类型也必须是整数数据类型:

layout(location = 0) in vec3 vertex_position
layout(location = 1) in vec4 vertex_colour;

layout(location = 0) in ivec3 vertex_position;
layout(location = 1) in ivec4 vertex_colour;

glVertexAttribIPointerstride参数/glVertexAttribPointer连续通用顶点属性之间的字节偏移量。所以它必须分别是 sizeof(pos) sizeof(col) 而不是 3*sizeof(pos)3*sizeof(col).
如果通用顶点属性被紧密打包,那么 stride 可以设置为 0。这是一种特殊情况,其中步幅由 sizetype 参数自动计算:

glBindBuffer(GL_ARRAY_BUFFER,vboidP);
// [...]
glVertexAttribIPointer(0, 3, GL_INT, 0, NULL);
// [...]

glBindBuffer(GL_ARRAY_BUFFER, vboidC);
// [...]
glVertexAttribIPointer(1, 4, GL_UNSIGNED_BYTE, 0, NULL);
// [...]

核心配置文件上下文 (SDL_GL_CONTEXT_PROFILE_CORE) 不支持固定函数矩阵堆栈。

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -255, 0);

参见 Fixed Function Pipeline and Legacy OpenGL
的答案也可能有所帮助。

我建议使用像 OpenGL Mathematics to calculate the view matrix by ortho() and a uniform 变量这样的库:

version 460
layout(location = 0) in ivec3 vertex_position;

layout(location = 7) uniform mat4 prj_matrix;

void main()
{  
    // [...]

    gl_Position = prj_matrix * vec4(vertex_position, 1.0);"
}
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// [...]

void GPU::render()
{
    // [...]

    glUseProgram(lkshaderid);

    glm::mat4 prj = glm::ortho(0.0f, (float)width, 0.0f, (float)height, -255.0f, 0.0f);
    glUniformMatrix4fv(7, 1, GL_FALSE, glm::value_ptr(prj));

    // [...]
}

统一位置由 Layout qualifier (location = 7) 显式设置。
glUniformMatrix4fv sets the value of the uniform at the specified location in the default uniform block. This has to be done after the progroam was installed by glUseProgram.


完整着色器代码,使用 Raw string literal:

const char* GPU::shaders[2] = {
R"(
#version 460

layout(location = 0) in ivec3 vertex_position;
layout(location = 1) in ivec4 vertex_colour;

layout(location = 7) uniform mat4 prj_matrix;

out vec4 colour;

void main() {
    colour = vec4(vertex_colour) / 255.0;
    gl_Position = prj_matrix * vec4(vertex_position, 1.0);
}
)"
,
R"(
#version 460

in vec4 colour;

out vec4 frag_colour;

void main() {
   frag_colour = colour;
}
)"
};

如果您应用建议的更改,您将看到以下三角形: