Texturing a cube with different images using OpenGL
Asked Answered
P

1

2

I have a project from school I'm currently working on and I need to texture a non-rotating cube showing just 3 faces. I've tried doing it on my own but I only get one image on all the 3 faces. I don't know if it's my method that's wrong or the way I'm loading the remaining two images. I would really appreciate help from anyone.

This is how I load my textures

GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// texture coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);

// this is for texture coords

//Load Image
//int width, height; // width1, height1;
//unsigned char* image = SOIL_load_image("res/images/image1.jpg", &width, &height, 0, SOIL_LOAD_RGBA);

GLuint texture1, texture2, texture3;
// texture 1
// ---------
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width, height;
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
unsigned char* image = SOIL_load_image("res/images/image1.jpg", &width, &height, 0, SOIL_LOAD_RGBA);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);

SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
// texture 2
// ---------
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width1, height1;
unsigned char* image1 = SOIL_load_image("res/images/image2.jpg", &width1, &height1, 0, SOIL_LOAD_RGBA);

// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1);
glGenerateMipmap(GL_TEXTURE_2D);

SOIL_free_image_data(image1);
glBindTexture(GL_TEXTURE_2D, 1);

// texture 3
// ---------
glGenTextures(1, &texture3);
glBindTexture(GL_TEXTURE_2D, texture3);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width2, height2;
unsigned char* image2 = SOIL_load_image("res/images/image3.jpg", &width2, &height2, 0, SOIL_LOAD_RGBA);

// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, image2);
glGenerateMipmap(GL_TEXTURE_2D);

SOIL_free_image_data(image2);
glBindTexture(GL_TEXTURE_2D, 2);

// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)
// -------------------------------------------------------------------------------------------
shader.Use();
shader.setInt("texture0", 0); // Function to get UniformLocation
shader.setInt("texture1", 0);
shader.setInt("texture2", 2);

And this is the code for when I activate and bind the texture in the rendering Loop

shader.Use();
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);

glBindTexture(GL_TEXTURE_2D, texture1);

glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);

glActiveTexture(GL_TEXTURE1);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture2);

glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);

glActiveTexture(GL_TEXTURE2);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture2);

glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);

This is my fragment shader for the program. I really don't know how to use the 3 sampler2D variables I also created here

#version 330 core
in vec2 textCoords;
//in vec2 textCoords2;
//in vec3 ourColor;

out vec4 color1;
out vec4 color2;

uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;

void main()
{
   // color = vec4(ourColor, 1.0f);
    color1 = texture(texture0,textCoords) ;   
    //color2 = texture(texture1,textCoords2);

}

This is the result I get for now with this code, but I want different images on the three faces:

img

Philippine answered 13/12, 2020 at 13:41 Comment(0)
Q
5

You are not binding textures correctly...

  1. you bind txr1 and render whole cube
  2. then you bind txr2 and render whole cube
  3. then you bind txr3 and render whole cube

so depending on the depth test you see either only txr1 or txr3 or some z fighting mess ...

You need either separate faces with the same texture into separate VAO/VBOs (instead of having whole cube in single one)

Or use texture "atlas" (put all textures into single image) and correct texture coordinates... For example something like this:

cubemap

In the new versions there is also possibility of using bindless teturing (never used that however it should be just a matter of passing texture id to the shaders)

[Edit1] texture atlas

Ok lets have some texture atlas for example this one (I just compiled):

texture atlas

As you can see its 7x7 square textures so each texture i = 0,1,2,...,7*7-1 starts at texture coordinate:

x = (i%7)/7.0;
y = (i/7)/7.0;

so you simply add the x,y to your texture coordinate for each vertex of each face where i is the selected texture and normalize the coordinates to size of individual texture so:

x = ((i%7)+x0)/7.0;
y = ((i/7)+y0)/7.0;

where x0,y0 are texture coordinates for normal texture (like you got now) and i is selected texture. If you have different layout of the atlas then just change the 7 for the xcount of texture in each axis in your atlas.

I modified my complete GL+GLSL+VAO/VBO C++ example and added textures for the cube:

//---------------------------------------------------------------------------
//--- GL simple ver: 1.002 --------------------------------------------------
//---------------------------------------------------------------------------
// [complete GL+GLSL+VAO/VBO C++ example](https://mcmap.net/q/122480/-opengl-vertex-normals-in-obj)
//---------------------------------------------------------------------------
#define GLEW_STATIC
#include "glew.c"
#include <gl\gl.h>
#include <gl\glu.h>
//---------------------------------------------------------------------------
//--- OpenGL GL example -----------------------------------------------------
//---------------------------------------------------------------------------
int     xs,ys;      // screen size
HDC     hdc=NULL;   // device context
HGLRC   hrc=NULL;   // rendering context
int  gl_inicialized=0;
int  gl_init(HWND Handle);
void gl_exit();
void gl_draw();
void gl_resize(int _xs,int _ys);
//---------------------------------------------------------------------------
//--- OpenGL GLSL example ---------------------------------------------------
//---------------------------------------------------------------------------
GLint prog_id=0,    // whole program
      vert_id=0,    // vertex shader
      geom_id=0,    // geometry shader
      frag_id=0;    // fragment shader
char  glsl_log[4096];// compile/link GLSL log
int   glsl_logs=0;
void  glsl_init(char *vert,char *frag);     // create/compile/link GLSL program
void  glsl_exit();
//---------------------------------------------------------------------------
//--- OpenGL VAO example ----------------------------------------------------
//---------------------------------------------------------------------------
#pragma pack(1)
// #define vao_indices
GLuint vbo[5]={-1,-1,-1,-1,-1};
GLuint vao[5]={-1,-1,-1,-1,-1};
const GLfloat vao_pos[]=
    {
//  x    y    z     //ix
    -1.0,+1.0,-1.0, //0
    +1.0,+1.0,-1.0, //1
    +1.0,-1.0,-1.0, //2
    -1.0,-1.0,-1.0, //3

    -1.0,-1.0,+1.0, //4
    +1.0,-1.0,+1.0, //5
    +1.0,+1.0,+1.0, //6
    -1.0,+1.0,+1.0, //7

    #ifndef vao_indices
    -1.0,-1.0,-1.0, //3
    +1.0,-1.0,-1.0, //2
    +1.0,-1.0,+1.0, //5
    -1.0,-1.0,+1.0, //4

    +1.0,-1.0,-1.0, //2
    +1.0,+1.0,-1.0, //1
    +1.0,+1.0,+1.0, //6
    +1.0,-1.0,+1.0, //5

    +1.0,+1.0,-1.0, //1
    -1.0,+1.0,-1.0, //0
    -1.0,+1.0,+1.0, //7
    +1.0,+1.0,+1.0, //6

    -1.0,+1.0,-1.0, //0
    -1.0,-1.0,-1.0, //3
    -1.0,-1.0,+1.0, //4
    -1.0,+1.0,+1.0, //7
    #endif
    };

const GLfloat vao_txr[]=
    {
//  x    y      //ix
    (0.0+0.0)/7.0,(5.0+1.0)/7.0, //0
    (0.0+1.0)/7.0,(5.0+1.0)/7.0, //1
    (0.0+1.0)/7.0,(5.0+0.0)/7.0, //2
    (0.0+0.0)/7.0,(5.0+0.0)/7.0, //3

    (5.0+0.0)/7.0,(5.0+0.0)/7.0, //4
    (5.0+1.0)/7.0,(5.0+0.0)/7.0, //5
    (5.0+1.0)/7.0,(5.0+1.0)/7.0, //6
    (5.0+0.0)/7.0,(5.0+1.0)/7.0, //7

    #ifndef vaices
    (5.0+0.0)/7.0,(4.0+0.0)/7.0, //3
    (5.0+1.0)/7.0,(4.0+0.0)/7.0, //2
    (5.0+1.0)/7.0,(4.0+1.0)/7.0, //5
    (5.0+0.0)/7.0,(4.0+1.0)/7.0, //4

    (3.0+1.0)/7.0,(2.0+0.0)/7.0, //2
    (3.0+1.0)/7.0,(2.0+1.0)/7.0, //1
    (3.0+0.0)/7.0,(2.0+1.0)/7.0, //6
    (3.0+0.0)/7.0,(2.0+0.0)/7.0, //5

    (0.0+1.0)/7.0,(6.0+1.0)/7.0, //1
    (0.0+0.0)/7.0,(6.0+1.0)/7.0, //0
    (0.0+0.0)/7.0,(6.0+0.0)/7.0, //7
    (0.0+1.0)/7.0,(6.0+0.0)/7.0, //6

    (2.0+1.0)/7.0,(6.0+1.0)/7.0, //0
    (2.0+1.0)/7.0,(6.0+0.0)/7.0, //3
    (2.0+0.0)/7.0,(6.0+0.0)/7.0, //4
    (2.0+0.0)/7.0,(6.0+1.0)/7.0, //7
    #endif
    };

const GLfloat vao_col[]=
    {
//  r   g   b    //ix
    0.0,0.0,0.0, //0
    1.0,0.0,0.0, //1
    1.0,1.0,0.0, //2
    0.0,1.0,0.0, //3
    0.0,0.0,1.0, //4
    1.0,0.0,1.0, //5
    1.0,1.0,1.0, //6
    0.0,1.0,1.0, //7

    #ifndef vao_indices
    0.0,0.0,0.0, //0
    1.0,0.0,0.0, //1
    1.0,0.0,1.0, //5
    0.0,0.0,1.0, //4

    1.0,0.0,0.0, //1
    1.0,1.0,0.0, //2
    1.0,1.0,1.0, //6
    1.0,0.0,1.0, //5

    1.0,1.0,0.0, //2
    0.0,1.0,0.0, //3
    0.0,1.0,1.0, //7
    1.0,1.0,1.0, //6

    0.0,1.0,0.0, //3
    0.0,0.0,0.0, //0
    0.0,0.0,1.0, //4
    0.0,1.0,1.0, //7
    #endif
    };

#ifndef vao_indices
const GLfloat vao_nor[]=
    {
//   nx   ny   nz   //ix
     0.0, 0.0,-1.0, //0
     0.0, 0.0,-1.0, //1
     0.0, 0.0,-1.0, //2
     0.0, 0.0,-1.0, //3

     0.0, 0.0,+1.0, //4
     0.0, 0.0,+1.0, //5
     0.0, 0.0,+1.0, //6
     0.0, 0.0,+1.0, //7

     0.0,-1.0, 0.0, //0
     0.0,-1.0, 0.0, //1
     0.0,-1.0, 0.0, //5
     0.0,-1.0, 0.0, //4

    +1.0, 0.0, 0.0, //1
    +1.0, 0.0, 0.0, //2
    +1.0, 0.0, 0.0, //6
    +1.0, 0.0, 0.0, //5

     0.0,+1.0, 0.0, //2
     0.0,+1.0, 0.0, //3
     0.0,+1.0, 0.0, //7
     0.0,+1.0, 0.0, //6

    -1.0, 0.0, 0.0, //3
    -1.0, 0.0, 0.0, //0
    -1.0, 0.0, 0.0, //4
    -1.0, 0.0, 0.0, //7
    };
#endif

#ifdef vao_indices
const GLuint vao_ix[]=
    {
    0,1,2,3,
    4,5,6,7,
    3,2,5,4,
    2,1,6,5,
    1,0,7,6,
    0,3,4,7,
    };
#endif

#pragma pack()
void vao_init();
void vao_exit();
void vao_draw();
//---------------------------------------------------------------------------
//--- bodies: ---------------------------------------------------------------
//---------------------------------------------------------------------------
int gl_init(HWND Handle)
    {
    if (gl_inicialized) return 1;
    hdc = GetDC(Handle);            // get device context
    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory( &pfd, sizeof( pfd ) );      // set the pixel format for the DC
    pfd.nSize = sizeof( pfd );
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 24;
    pfd.iLayerType = PFD_MAIN_PLANE;
    SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
    hrc = wglCreateContext(hdc);            // create current rendering context
    if(hrc == NULL)
            {
            ShowMessage("Could not initialize OpenGL Rendering context !!!");
            gl_inicialized=0;
            return 0;
            }
    if(wglMakeCurrent(hdc, hrc) == false)
            {
            ShowMessage("Could not make current OpenGL Rendering context !!!");
            wglDeleteContext(hrc);          // destroy rendering context
            gl_inicialized=0;
            return 0;
            }
    gl_resize(1,1);
    glEnable(GL_DEPTH_TEST);                // Zbuf
    glDisable(GL_CULL_FACE);                // vynechavaj odvratene steny
    glDisable(GL_TEXTURE_2D);               // pouzivaj textury, farbu pouzivaj z textury
    glDisable(GL_BLEND);                    // priehladnost
    glShadeModel(GL_SMOOTH);                // gourard shading
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);   // background color
    gl_inicialized=1;
    glewInit();
    return 1;
    }
//---------------------------------------------------------------------------
void gl_exit()
    {
    if (!gl_inicialized) return;
    wglMakeCurrent(NULL, NULL);     // release current rendering context
    wglDeleteContext(hrc);          // destroy rendering context
    gl_inicialized=0;
    }
//---------------------------------------------------------------------------
void gl_resize(int _xs,int _ys)
    {
    xs=_xs;
    ys=_ys;
    if (xs<=0) xs = 1;                  // Prevent a divide by zero
    if (ys<=0) ys = 1;
    if (!gl_inicialized) return;
    glViewport(0,0,xs,ys);              // Set Viewport to window dimensions
    glMatrixMode(GL_PROJECTION);        // operacie s projekcnou maticou
    glLoadIdentity();                   // jednotkova matica projekcie
    gluPerspective(30,float(xs)/float(ys),0.1,100.0); // matica=perspektiva,120 stupnov premieta z viewsize do 0.1
    glMatrixMode(GL_TEXTURE);           // operacie s texturovou maticou
    glLoadIdentity();                   // jednotkova matica textury
    glMatrixMode(GL_MODELVIEW);         // operacie s modelovou maticou
    glLoadIdentity();                   // jednotkova matica modelu (objektu)
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void glsl_init(char *vert,char *geom,char *frag)
    {
    const int _size=1024;
    GLint status,siz=0,i;
    const char * VS = vert;
    const char * GS = geom;
    const char * FS = frag;
    glsl_logs=0;
    if (prog_id<=0) prog_id=glCreateProgram();

    if (vert_id<=0) vert_id=glCreateShader(GL_VERTEX_SHADER); else glDetachShader(prog_id,vert_id);
    if (vert)
        {
        glShaderSource(vert_id, 1, &VS,NULL);
        glCompileShader(vert_id);
        glAttachShader(prog_id,vert_id);
        glGetShaderiv(vert_id,GL_COMPILE_STATUS,&status);
        const char t[]="[Vertex]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
        glGetShaderInfoLog(vert_id,_size,&siz,glsl_log+glsl_logs);
        glsl_logs+=siz;
        }
    if (geom_id<=0) geom_id=glCreateShader(GL_GEOMETRY_SHADER); else glDetachShader(prog_id,geom_id);
    if (geom)
        {
        glShaderSource(geom_id, 1, &GS,NULL);
        glCompileShader(geom_id);
        glAttachShader(prog_id,geom_id);
        glGetShaderiv(geom_id,GL_COMPILE_STATUS,&status);
        const char t[]="[Geometry]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
        glGetShaderInfoLog(geom_id,_size,&siz,glsl_log+glsl_logs);
        glsl_logs+=siz;
        }
    if (frag_id<=0) frag_id=glCreateShader(GL_FRAGMENT_SHADER); else glDetachShader(prog_id,frag_id);
    if (frag)
        {
        glShaderSource(frag_id, 1, &FS,NULL);
        glCompileShader(frag_id);
        glAttachShader(prog_id,frag_id);
        glGetShaderiv(frag_id,GL_COMPILE_STATUS,&status);
        const char t[]="[Fragment]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
        glGetShaderInfoLog(frag_id,_size,&siz,glsl_log+glsl_logs);
        glsl_logs+=siz;
        }
    glLinkProgram(prog_id);
    glGetProgramiv(prog_id,GL_LINK_STATUS,&status);
    const char t[]="[Program]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
    glGetProgramInfoLog(prog_id,_size,&siz,glsl_log+glsl_logs);
    glsl_logs+=siz;

    glReleaseShaderCompiler();
    glsl_log[glsl_logs]=0;
    }
//------------------------------------------------------------------------------
void glsl_exit()
    {
    glUseProgram(0);
    if (vert_id>0) { glDetachShader(prog_id,vert_id); glDeleteShader(vert_id); }
    if (geom_id>0) { glDetachShader(prog_id,geom_id); glDeleteShader(geom_id); }
    if (frag_id>0) { glDetachShader(prog_id,frag_id); glDeleteShader(frag_id); }
    if (prog_id>0) {                                  glDeleteShader(prog_id); }
    glsl_log[0]=0;
    }
//---------------------------------------------------------------------------
//------------------------------------------------------------------------------
void vao_init()
    {
    GLuint i;
    glGenVertexArrays(4,vao);
    glGenBuffers(4,vbo);
    glBindVertexArray(vao[0]);
    i=0; // vertex
    glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vao_pos),vao_pos,GL_STATIC_DRAW);
    glEnableVertexAttribArray(i);
    glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
    i=1; // indices
    #ifdef vao_indices
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vbo[i]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(vao_ix),vao_ix,GL_STATIC_DRAW);
    glEnableVertexAttribArray(i);
    glVertexAttribIPointer(i,4,GL_UNSIGNED_INT,0,0);
    #endif
    i=2; // normal
    #ifndef vao_indices
    glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vao_nor),vao_nor,GL_STATIC_DRAW);
    glEnableVertexAttribArray(i);
    glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
    #endif
    i=3; // color
    glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vao_col),vao_col,GL_STATIC_DRAW);
    glEnableVertexAttribArray(i);
    glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
    i=4; // textures
    glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vao_txr),vao_txr,GL_STATIC_DRAW);
    glEnableVertexAttribArray(i);
    glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,0,0);

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
    glDisableVertexAttribArray(4);
    }
//---------------------------------------------------------------------------
void vao_exit()
    {
    glDeleteVertexArrays(5,vao);
    glDeleteBuffers(5,vbo);
    }
//---------------------------------------------------------------------------
void vao_draw()
    {
    glBindVertexArray(vao[0]);
    #ifndef vao_indices
    glDrawArrays(GL_QUADS,0,sizeof(vao_pos)/sizeof(vao_pos[0]));                    // QUADS ... no indices
    #endif
    #ifdef vao_indices
    glDrawElements(GL_QUADS,sizeof(vao_ix)/sizeof(vao_ix[0]),GL_UNSIGNED_INT,0);    // indices (choose just one line not both !!!)
    #endif
    glBindVertexArray(0);
    }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

Of coarse you need to add textures to shaders and pass the sampler unit along with texture coordinates too. Also this will not work with indices enabled as the example was not build for that and I am too lazy to recode it. What is important here is this:

const GLfloat vao_txr[]=
    {
//  x    y      //ix
    (0.0+0.0)/7.0,(5.0+1.0)/7.0, //0
    (0.0+1.0)/7.0,(5.0+1.0)/7.0, //1
    (0.0+1.0)/7.0,(5.0+0.0)/7.0, //2
    (0.0+0.0)/7.0,(5.0+0.0)/7.0, //3

    (5.0+0.0)/7.0,(5.0+0.0)/7.0, //4
    (5.0+1.0)/7.0,(5.0+0.0)/7.0, //5
    (5.0+1.0)/7.0,(5.0+1.0)/7.0, //6
    (5.0+0.0)/7.0,(5.0+1.0)/7.0, //7

    #ifndef vaices
    (5.0+0.0)/7.0,(4.0+0.0)/7.0, //3
    (5.0+1.0)/7.0,(4.0+0.0)/7.0, //2
    (5.0+1.0)/7.0,(4.0+1.0)/7.0, //5
    (5.0+0.0)/7.0,(4.0+1.0)/7.0, //4

    (3.0+1.0)/7.0,(2.0+0.0)/7.0, //2
    (3.0+1.0)/7.0,(2.0+1.0)/7.0, //1
    (3.0+0.0)/7.0,(2.0+1.0)/7.0, //6
    (3.0+0.0)/7.0,(2.0+0.0)/7.0, //5

    (0.0+1.0)/7.0,(6.0+1.0)/7.0, //1
    (0.0+0.0)/7.0,(6.0+1.0)/7.0, //0
    (0.0+0.0)/7.0,(6.0+0.0)/7.0, //7
    (0.0+1.0)/7.0,(6.0+0.0)/7.0, //6

    (2.0+1.0)/7.0,(6.0+1.0)/7.0, //0
    (2.0+1.0)/7.0,(6.0+0.0)/7.0, //3
    (2.0+0.0)/7.0,(6.0+0.0)/7.0, //4
    (2.0+0.0)/7.0,(6.0+1.0)/7.0, //7
    #endif
    };

As you can see the cooridantes are in form of start_of_texture+texture_coordinate and I chose 6 different textures from the atlas for each face...

Here preview (disabled colors so texture colors are more visible):

preview

And for the completeness here the shaders (however your texturing works so no need to change yours):

// Fragment
#version 400 core
#extension GL_ARB_explicit_uniform_location : enable
layout(location =64) uniform vec3 lt_pnt_pos;// point light source position [GCS]
layout(location =67) uniform vec3 lt_pnt_col;// point light source color&strength
layout(location =70) uniform vec3 lt_amb_col;// ambient light source color&strength
layout(location =73) uniform sampler2D txr;
in vec3 pixel_pos;      // fragment position [GCS]
in vec3 pixel_col;      // fragment surface color
in vec3 pixel_nor;      // fragment surface normal [GCS]
in vec2 pixel_txr;      // fragment texture coord
out vec4 col;
void main()
    {
    float li;
    vec3 c,lt_dir;
    lt_dir=normalize(lt_pnt_pos-pixel_pos); // vector from fragment to point light source in [GCS]
    li=dot(pixel_nor,lt_dir);
    if (li<0.0) li=0.0;
    c =texture(txr,pixel_txr).rgb;
//  c*=pixel_col;
    c*=(lt_amb_col+(lt_pnt_col*li));
    col=vec4(c,1.0);
    }
// Vertex
#version 400 core
#extension GL_ARB_explicit_uniform_location : enable
layout(location = 0) in vec3 pos;
layout(location = 2) in vec3 nor;
layout(location = 3) in vec3 col;
layout(location = 4) in vec2 txr;
layout(location = 0) uniform mat4 m_model;  // model matrix
layout(location =16) uniform mat4 m_normal; // model matrix with origin=(0,0,0)
layout(location =32) uniform mat4 m_view;   // inverse of camera matrix
layout(location =48) uniform mat4 m_proj;   // projection matrix
out vec3 pixel_pos;     // fragment position [GCS]
out vec3 pixel_col;     // fragment surface color
out vec3 pixel_nor;     // fragment surface normal [GCS]
out vec2 pixel_txr;     // fragment texture coord
void main()
    {
    pixel_col=col;
    pixel_pos=(m_model*vec4(pos,1)).xyz;
    pixel_nor=(m_normal*vec4(nor,1)).xyz;
    pixel_txr=txr;
    gl_Position=m_proj*m_view*m_model*vec4(pos,1);
    }

And here the C++/VCL code for my window:

//---------------------------------------------------------------------------
#include <vcl.h>
#include <jpeg.hpp>
#pragma hdrstop
#include "Unit1.h"
#include "gl_simple.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
GLfloat lt_pnt_pos[3]={+2.5,+2.5,+2.5};
GLfloat lt_pnt_col[3]={0.8,0.8,0.8};
GLfloat lt_amb_col[3]={0.2,0.2,0.2};
GLuint  txrid=0;
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_CULL_FACE);

    // load values into shader
    GLint i,id;
    GLfloat m[16];
    glUseProgram(prog_id);
/*
    id=glGetUniformLocation(prog_id,"lt_pnt_pos"); glUniform3fv(id,1,lt_pnt_pos);
    id=glGetUniformLocation(prog_id,"lt_pnt_col"); glUniform3fv(id,1,lt_pnt_col);
    id=glGetUniformLocation(prog_id,"lt_amb_col"); glUniform3fv(id,1,lt_amb_col);
    glGetFloatv(GL_MODELVIEW_MATRIX,m);
    id=glGetUniformLocation(prog_id,"m_model"   ); glUniformMatrix4fv(id,1,GL_FALSE,m);
    m[12]=0.0; m[13]=0.0; m[14]=0.0;
    id=glGetUniformLocation(prog_id,"m_normal"  ); glUniformMatrix4fv(id,1,GL_FALSE,m);
    for (i=0;i<16;i++) m[i]=0.0; m[0]=1.0; m[5]=1.0; m[10]=1.0; m[15]=1.0;
    id=glGetUniformLocation(prog_id,"m_view"    ); glUniformMatrix4fv(id,1,GL_FALSE,m);
    glGetFloatv(GL_PROJECTION_MATRIX,m);
    id=glGetUniformLocation(prog_id,"m_proj"    ); glUniformMatrix4fv(id,1,GL_FALSE,m);
*/
    id=64; glUniform3fv(id,1,lt_pnt_pos);
    id=67; glUniform3fv(id,1,lt_pnt_col);
    id=70; glUniform3fv(id,1,lt_amb_col);
    id=73; glUniform1i(id,0);   // texture unit
    glGetFloatv(GL_MODELVIEW_MATRIX,m);
    id=0; glUniformMatrix4fv(id,1,GL_FALSE,m);
    m[12]=0.0; m[13]=0.0; m[14]=0.0;
    id=16; glUniformMatrix4fv(id,1,GL_FALSE,m);
    for (i=0;i<16;i++) m[i]=0.0; m[0]=1.0; m[5]=1.0; m[10]=1.0; m[15]=1.0;
    id=32; glUniformMatrix4fv(id,1,GL_FALSE,m);
    glGetFloatv(GL_PROJECTION_MATRIX,m);
    id=48; glUniformMatrix4fv(id,1,GL_FALSE,m);


    // draw VAO cube
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,txrid);
    vao_draw();
    glBindTexture(GL_TEXTURE_2D,0);
    glDisable(GL_TEXTURE_2D);
    // turn of shader
    glUseProgram(0);

    // render the cube in old style GL
    if (0)
        {
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
        glEnable(GL_COLOR_MATERIAL);
        #ifndef vao_indices
        glBegin(GL_QUADS);
        for (int i=0;i<6*4*3;i+=3)
            {
            glNormal3fv(vao_nor+i);
            glColor3fv (vao_col+i);
            glVertex3fv(vao_pos+i);
            }
        glEnd();
        #else
        int i,j,k;
        const GLfloat vao_nor[]=
            {
        //   nx   ny   nz
             0.0, 0.0,-1.0,
             0.0, 0.0,+1.0,
             0.0,-1.0, 0.0,
            +1.0, 0.0, 0.0,
             0.0,+1.0, 0.0,
            -1.0, 0.0, 0.0,
            };
        glBegin(GL_QUADS);
        for (j=0;j<6*4;j++)
            {
            i=vao_ix[j]; i+=i+i;
            k=j>>2; k+=k+k;
            glNormal3fv(vao_nor+k);
            glColor3fv (vao_col+i);
            glVertex3fv(vao_pos+i);
            }
        glEnd();
        #endif
        glDisable(GL_COLOR_MATERIAL);
        glDisable(GL_LIGHTING);
        glDisable(GL_LIGHT0);
        }


    // rotate the cube to see animation
    glMatrixMode(GL_MODELVIEW);
    glRotatef(1.0,0.0,1.0,0.0);
    glRotatef(1.0,1.0,0.0,0.0);

    // render point light source in [GCS]
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    GLfloat x,y,z,d=0.25;
    x=lt_pnt_pos[0];
    y=lt_pnt_pos[1];
    z=lt_pnt_pos[2];
    glBegin(GL_LINES);
    glColor3fv(lt_pnt_col);
    glVertex3f(x-d,y,z);
    glVertex3f(x+d,y,z);
    glVertex3f(x,y-d,z);
    glVertex3f(x,y+d,z);
    glVertex3f(x,y,z-d);
    glVertex3f(x,y,z+d);
    glEnd();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    gl_init(Handle);

    // load shaders
    int hnd,siz; char vertex[4096],fragment[4096];
    hnd=FileOpen("normal_shading.glsl_vert",fmOpenRead); siz=FileSeek(hnd,0,2); FileSeek(hnd,0,0); FileRead(hnd,vertex  ,siz); vertex  [siz]=0; FileClose(hnd);
    hnd=FileOpen("normal_shading.glsl_frag",fmOpenRead); siz=FileSeek(hnd,0,2); FileSeek(hnd,0,0); FileRead(hnd,fragment,siz); fragment[siz]=0; FileClose(hnd);
    glsl_init(vertex,NULL,fragment);
    hnd=FileCreate("GLSL.txt"); FileWrite(hnd,glsl_log,glsl_logs); FileClose(hnd);

    // load texture atlas
    Byte q;
    unsigned int *pp;
    int xs,ys,x,y,adr,*txr;
    union { unsigned int c32; Byte db[4]; } c;
    TJPEGImage *jpg=new TJPEGImage;
    Graphics::TBitmap *bmp=new Graphics::TBitmap;
    if (bmp)
        {
        if (jpg)
            {
            jpg->LoadFromFile("textures128x128.jpg");
            bmp->Assign(jpg);
            delete jpg;
            }
        glGenTextures(1,&txrid);
        bmp->HandleType=bmDIB;      // allow direct access to pixels
        bmp->PixelFormat=pf32bit;   // set pixel to 32bit so int is the same size as pixel
        xs=bmp->Width;              // resolution should be power of 2
        ys=bmp->Height;
        txr=new int[xs*ys];         // create linear framebuffer
        for(adr=0,y=0;y<ys;y++)
            {
            pp=(unsigned int*)bmp->ScanLine[y];
            for(x=0;x<xs;x++,adr++)
                {
                // rgb2bgr and copy bmp -> txr[]
                    c.c32=pp[x];
                q      =c.db[2];
                c.db[2]=c.db[0];
                c.db[0]=q;
                txr[adr]=c.c32;
                }
            }
        glEnable(GL_TEXTURE_2D);    // copy it to gfx card
        glBindTexture(GL_TEXTURE_2D,txrid);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0, GL_RGBA, GL_UNSIGNED_BYTE, txr);
        glDisable(GL_TEXTURE_2D);
        delete[] txr;
        delete bmp;
        }
    vao_init();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    glDeleteTextures(1,&txrid);
    gl_exit();
    glsl_exit();
    vao_exit();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
    {
    gl_resize(ClientWidth,ClientHeight);
    glMatrixMode(GL_PROJECTION);
    glTranslatef(0,0,-15.0);
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
    {
    GLfloat dz=2.0;
    if (WheelDelta<0) dz=-dz;
    glMatrixMode(GL_PROJECTION);
    glTranslatef(0,0,dz);
    gl_draw();
    }
//---------------------------------------------------------------------------

Again most of the code is not important for you look just for the code related to vao_ stuff.

Quotable answered 13/12, 2020 at 14:18 Comment(8)
can you please explain how i would use texture atlas to solve this problem? I would really appreciate it!Philippine
If it's not too much trouble i would also appreciate it if you explain with example this method too, "You need either separate faces with the same texture into separate VAO/VBOs (instead of having whole cube in single one)"Philippine
@Philippine what do you not understand ? it would be the same as you got now but you would need to have 6 VAOs (each containing just single face) instead of 1 (containing all 6 faces) and then 1. bind texture0, render VAO0 2. bind texture1, render VAO1 ... 6. bind texture5, render VAO5 ... so each of the tables would be disected into 6 ones ...Quotable
@Philippine there is also another option if you group all vertexes using the same texture then you do not need to disect the VAO/VBOs you just call the glDrawArrays with different first and count ... so bind texture0 call glDrawArrays(?,0*n,n) then bind texture1 call glDrawArrays(?,1*n,n) and so on ...where n is the number of vertexes per face so if using triangles then 6, if quads then 4 ...Quotable
so i would need to use glDrawArrays() six times?Philippine
@Philippine as many times as you got different textures.... using texture atlas you have just single texture so its fasterQuotable
I am having problems to compile it in linux ubuntu 22.04. It is for windows right cuz of vcl.h. Btw, I am looking for a full cpp linux example with bumpmaps shiny wet surfaces parallax and tessellation, any idea where I can find it? do you think I could create such question here?Delict
@AquariusPower What you need is any OpenGL example under linux supporting shaders and probably higher version of GL so look for OpenGL+GLEW ... Once that is working then just add the shader code (that is the same across OS, but you need to tweak them for each gfx vendor)... I do not code for linux (maybe 20 years) so I am not confident to make any example ... maybe some GLUT example will do (IIRC it creates window and events ...). Yeas you could create new question but its possible it would turn to seek SW/tutorial which is of topic if not written carefullyQuotable

© 2022 - 2024 — McMap. All rights reserved.