The task is to draw 5 (or another number that is not a power of two) points on the screen using a texture. An array of coordinates along the 0X axis comes to the shader as an attribute. On axis 0Y, 0Z zeros.
Drawing these points without using the texture is correct. Here is the code:
// vert x-coord attribute float a_xcoord; void main(){ gl_PointSize = 10; gl_Position = vec4(a_xcoord, 0, 0, 1); } When instead of an array of attributes, a one-dimensional texture is used with the same data and parameters:
InternalFormat - R32F GL_TEXTURE_MIN_FILTER - GL_NEAREST, GL_TEXTURE_MAG_FILTER - GL_NEAREST DataFormat - GL_RED the number of points on the screen is equal to degree 2 (1, 2, 4, etc.), even if the texture had a size not equal to the power of two. Example: we want to draw 5 points, and draws 4. Here is the code:
// номер вершины (0, 1, 2 и т.д.) attribute float a_id; // текстура с x-компонентами точек uniform sampler1D u_x; // размер текстуры uniform float x_len; void main(){ // по номеру точки получаем значение из текстуры // + 0.5 - чтобы попасть в середину пикселя float x = texture1D(u_x, (a_id + 0.5) / x_len).r; gl_PointSize = 10; gl_Position = vec4(x, 0, 0, 1); } The GL_UNPACK_ALIGNMENT parameter is:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); Big note: the second code works correctly on the NVIDIA video card. The problem with powers of two occurs on the Intel (R) HD Graphics card. Driver Version: 8.15.10.2622
I attach the whole code:
string vertex_code = "#version 120\n" "uniform sampler1D u_x;" "uniform float x_len;" "attribute float position;" "void main() " "{ " " float x = texture1D(u_x, (position + 0.5) / x_len).r;" " gl_Position = vec4(x / 5.0, 0.0, 0.0, 1.0); " " gl_PointSize = 10.0;" "} "; string fragment_code = "#version 120\n" "void main() " "{ " " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); " "} "; class MyClass { GLuint program_id; GLint a_position_id; GLuint x_tex; GLint u_x_id; GLint x_len_id; GLuint vbo_id; int a_pos_len = 0; public: MyClass() {} void on_initialize(){ // ------------------------------------------------------------------- // ------------------- Build & activate program ---------------------- // ------------------------------------------------------------------- // Request a program and shader slots from GPU program_id = glCreateProgram(); GLuint vertex_id = glCreateShader(GL_VERTEX_SHADER); GLuint fragment_id = glCreateShader(GL_FRAGMENT_SHADER); // Set shaders source glShaderSource(vertex_id, vertex_code); glShaderSource(fragment_id, fragment_code); // Compile vertex shader glCompileShader(vertex_id); GLint compile_ok = glGetShader1i(vertex_id, GL_COMPILE_STATUS); if (!compile_ok){ std::string log = glGetShaderInfoLog(vertex_id); glDeleteShader(vertex_id); throw GlException("Error in vertex shader compiling: " + log); } // Compile fragment shader glCompileShader(fragment_id); compile_ok = glGetShader1i(fragment_id, GL_COMPILE_STATUS); if (!compile_ok){ std::string log = glGetShaderInfoLog(fragment_id); glDeleteShader(fragment_id); throw GlException("Error in fragment shader compiling: " + log); } // Attach shader objects to the program glAttachShader(program_id, vertex_id); glAttachShader(program_id, fragment_id); // Build program glLinkProgram(program_id); GLint link_ok = glGetProgram1i(program_id, GL_LINK_STATUS); if (!link_ok){ std::string log = glGetProgramInfoLog(program_id); throw GlException("Error in program linking: " + log); } // ------------------------------------------------------------------- // ------------------------- Create VBO ------------------------------ // ------------------------------------------------------------------- // Create vbo. vbo_id = glCreateBuffer(); // make this buffer default. glBindBuffer(GL_ARRAY_BUFFER, vbo_id); GLfloat a_pos[] = { 0.0, 1.0, 2.0, 3.0, 4.0 }; a_pos_len = 5; glBufferData(GL_ARRAY_BUFFER, sizeof(a_pos), a_pos, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // ------------------------------------------------------------------- // ------------------------- Create Texture -------------------------- // ------------------------------------------------------------------- glGenTextures(1, &x_tex); glBindTexture(GL_TEXTURE_1D, x_tex); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage1D( GL_TEXTURE_1D, 0, GL_R32F, a_pos_len, 0, GL_RED, GL_FLOAT, a_pos ); glBindTexture(GL_TEXTURE_1D, 0); // ------------------------------------------------------------------- // ------------------------- Set Uniforms ---------------------------- // ------------------------------------------------------------------- x_len_id = glGetUniformLocation(program_id, "x_len"); if (x_len_id == -1) throw GlException("Could not bind uniforms"); glUseProgram(program_id); glUniform1f(x_len_id, a_pos_len); glUseProgram(0); } void on_paint() { // ------------------------------------------------------------------- // ------------------- Bind VBO to attribute ------------------------- // ------------------------------------------------------------------- // Get attribute location. a_position_id = glGetAttribLocation(program_id, "position"); if (a_position_id == -1) throw GlException("Could not bind attributes"); glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glVertexAttribPointer( a_position_id, // attribute 1, // number of elements per vertex GL_FLOAT, // the type of each element GL_FALSE, // take our values as-is 0, // no extra data between each position 0 // offset of first element ); // ------------------------------------------------------------------- // ------------------------ Draw arrays ------------------------------ // ------------------------------------------------------------------- // clear screen glClear(GL_COLOR_BUFFER_BIT); // Enable alpha. glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Use glsl program. glUseProgram(program_id); glBindTexture(GL_TEXTURE_1D, x_tex); /* Push each element in buffer_vertices to the vertex shader */ glEnableVertexAttribArray(a_position_id); glDrawArrays(GL_POINTS, 0, a_pos_len); glDisableVertexAttribArray(a_position_id); glBindTexture(GL_TEXTURE_1D, 0); glUseProgram(0); } void on_delete() { // free resources glDeleteProgram(program_id); glDeleteBuffer(vbo_id); } }; The above program draws 4 points instead of 5.