实际上这个原理类似opencl,将数据通过draw api做运算,一般通过的绘制方法:
glBeginTransformFeedback(GL_POINTS); glDrawArrays(GL_POINTS, 0, 5); glEndTransformFeedback();
如上绘制5个点,每个点携带一个 float数值,然后再vert shading里面做运算。
下面一个案例将准备好的数值传入gpu,然后做sqrt运算:
#define GLEW_STATIC // GLEW #include <GL/glew.h> #include <cstdlib> #undef GLFW_DLL // GLFW #include <GLFW/glfw3.h> #include <iostream> #include <sstream> #include <fstream> #include <string> using namespace std; string readFile(const char *path){ ifstream stream; stringstream ss; stream.exceptions(ifstream::badbit); try { stream.open(path); // open file ss << stream.rdbuf(); // get strings from file } catch (ifstream::failure e) { cout << "ERROR::OPEN FILE:" << path << endl; } // close file handle stream.close(); // get str() from stringstream string shaderCode = ss.str(); return shaderCode; } void init(){ string code = readFile("shaders/feedback/CP_01.vert"); const char * vertexShaderSrc = code.c_str(); // Create shader and compile GLuint shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(shader, 1, &vertexShaderSrc, nullptr); glCompileShader(shader); // Create program and specify transform feedback variables GLuint program = glCreateProgram(); glAttachShader(program, shader); // binding the out value const GLchar* feedbackVaryings[] = { "outValue" }; glTransformFeedbackVaryings(program, 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS); // finally link program and use glLinkProgram(program); glUseProgram(program); // Create VAO GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); // Create input VBO and vertex format GLfloat data[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); GLint inputAttrib = glGetAttribLocation(program, "inValue"); glEnableVertexAttribArray(inputAttrib); glVertexAttribPointer(inputAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0); // Create transform feedback buffer GLuint tbo; glCreateBuffers(1, &tbo); glBindBuffer(GL_ARRAY_BUFFER, tbo); glBufferData(GL_ARRAY_BUFFER, sizeof(data), nullptr, GL_STATIC_READ); // Perform feedback transform glEnable(GL_RASTERIZER_DISCARD); glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo); // deafault glBeginTransformFeedback(GL_POINTS); glDrawArrays(GL_POINTS, 0, 5); glEndTransformFeedback(); glDisable(GL_RASTERIZER_DISCARD); glFlush(); // Fetch and print results GLfloat feedback[5]; // parm1: target // parm2: offset // parm3: size // parm4: void *data // glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(feedback), feedback); //OGL 4.5 use-> glGetNamedBufferSubData() glGetNamedBufferSubData(tbo,0,sizeof(feedback), feedback); printf("%f %f %f %f %f\n", feedback[0], feedback[1], feedback[2], feedback[3], feedback[4]); glDeleteProgram(program); glDeleteShader(shader); glDeleteBuffers(1, &tbo); glDeleteBuffers(1, &vbo); glDeleteVertexArrays(1, &vao); } int main(){ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_VISIBLE,GL_FALSE); GLFWwindow * window = glfwCreateWindow(800,600,"Hello",NULL,NULL); glfwMakeContextCurrent(window); // glew init glewInit(); /* while( !glfwWindowShouldClose( window ) ) { glfwPollEvents(); glfwSwapBuffers(window); } */ init(); glfwTerminate(); glfwDestroyWindow(window); return 0; }
REF:
OpenGL Programming Guide Ninth Edition