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.

  • Try checking for this extension: opengl.org/registry/specs/ARB/texture_non_power_of_two.txt Most likely it is not supported by your Intel (R) HD Graphics. - Unick
  • Specify what it means "we want to draw 5 points, and draws 4"? It is possible that Intel (R) HD Graphics crookedly processes NPOT textures, and the 5th point is sampled from empty, which complements NPOT to POT size. - Kromster
  • @Unick checked this extension is supported. And the same shader in vispy is perfectly drawn not with powers of two. And in the Qt-project is not. Maybe you need to use some glEnable? - Helen
  • @Kromster if the number of points is not a power of two, then the program rounds down to the nearest power of two. 5,6,7 - to 4. 15, 14, ..., 9 - to 8. - Helen
  • @Helen did not google in detail, but they write that support for Vertex Texture Fetch (sampling from textures in a vertex shader) did not appear immediately and not among all manufacturers. Perhaps on your Intel HD it does not work properly. Try to update the driver or google how to check the presence / completeness of support for VTF. - Kromster

0