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

标签 c++ opengl cuda interop vao

我正在尝试使用 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);
}

窗口.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.
顶点着色器属性的数据类型也必须是整数数据类型:

vec3 vertex_position 中的布局(location = 0)
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。这是一种特殊情况,其中 stride 由 size 自动计算类型 参数:

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 PipelineLegacy OpenGL
OpenGL gluLookat not working with shaders on 的答案也可能有所帮助。

我建议使用像 OpenGL Mathematics 这样的库来通过 ortho() 和一个 uniform 变量计算 View 矩阵:

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 在默认统一 block 中的指定位置设置统一值。这必须在 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;
}
)"
};

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

关于c++ - 我的 VAO 不工作,我如何用 Cuda 改变它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56115065/

相关文章:

c++ - 避免在本地范围内进行动态分配

c# - vb.net 重载解析失败,出现 "multiple members with this name exist in class"

opengl - 如何使用 glm::project 获取世界空间中某个点的坐标?

c# - CUDA 设备中的内存分配不是预期的

c++ - 如何为 map 提供需要静态数据的比较器?

c++ - Qt为多行文本绘制轮廓

c++ - 为什么 std::bitset 实例中的 std::swap of Bits 不起作用?

c++ - 使用 NSOpenGLView 进行线程渲染

graphics - Ubuntu 14.04如何在不安装nvidia驱动的情况下安装cuda 6.5

performance - 如何计算 GPU 程序的加速比?