Search code examples
c++opengltexturesskybox

Transfer GL_TEXTURE_2D Image to GL_TEXTURE_CUBE_MAP


I am attempting to implement a Skybox into my C++ OpenGL project, and I want to use 6 x preloaded GL_TEXTURE_2D's retrieved from my TextureLibrary which loads all textures into the application as GL_TEXTURE_2D.

The issue I am running into is that I cannot use a GL_TEXTURE_2D for each face of a GL_TEXTURE_CUBE_MAP (that I know of). I have tried a variety of different approaches, however it appears that I cannot refer to or copy the image data from a GL_TEXTURE_2D to a GL_TEXTURE_CUBE_MAP face such as GL_TEXTURE_CUBE_MAP_POSITIVE_X on the GPU side.

To get this working currently the texture is being loaded on the CPU into my TextureLibrary as a GL_TEXTURE_2D, then it is being loaded again on the CPU in my Skybox class as a target of a GL_CUBE_MAP face, just as a temporary and inefficient way around this issue.

Is there any way to have the face of a GL_CUBE_MAP refer to or copy the data of a GL_TEXTURE_2D?

I plan to utilise these textures as GL_TEXTURE_2D's throughout the application in the future so I want to have them loaded on the CPU side once into my TextureLibrary, and only when they are used by a Skybox, the data is referenced or copied on the GPU side into a GL_TEXTURE_CUBE_MAP.

Alternatively, I could scrap the idea of using a GL_TEXTURE_CUBE_MAP, and pass my skybox shader 6 x Sampler2D's; however, I would like to know if there is any way I can do this per the above - OR any other ideas.


Solution

  • You can try this:

    //generate cubemap texture object name
    glGenTextures(1, &my_cube_map_texture);
    //make it a cubemap texture
    glBindTexture(GL_TEXTURE_CUBE_MAP, my_cube_map_texture);
    
    //for each cubemap face
    for (int i=0; i < 6; ++i) {
    
        //create face
        //where i
        //0: GL_TEXTURE_CUBE_MAP_POSITIVE_X
        //1: GL_TEXTURE_CUBE_MAP_NEGATIVE_X
        //2: GL_TEXTURE_CUBE_MAP_POSITIVE_Y
        //3: GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
        //4: GL_TEXTURE_CUBE_MAP_POSITIVE_Z
        //5: GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
        glTexImage2D(
            GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, //target
            0,                //level
            iformat,          //internalformat
            width,            //width
            height,           //height
            0,                //border
            format,           //data format
            GL_UNSIGNED_BYTE, //data type
            NULL              //no copy, allocate only
        );
    
        //copy data from existent 2d texture into the specific face
        glCopyImageSubData(
            my_texture_2d[i],    //srcName
            GL_TEXTURE_2D,       //srcTarget
            0,                   //srcLevel
            0,                   //srcX
            0,                   //srcY
            0,                   //srcZ
            my_cube_map_texture, //dstName
            GL_TEXTURE_CUBE_MAP, //dstTarget
            0,                   //dstLevel
            0,                   //dstX
            0,                   //dstY
            i,                   //dstZ
            width,               //srcWidth
            height,              //srcHeight
            1                    //srcDepth
        );
    
    }
    

    Prerequisites:

    • OpenGL 4.3+
    • the textures have to be square images (width == height)
    • the cubemap faces must have all the same sizes, therefore the textures have to be of the same size
    • the format must match, otherwise copy will produce error

    Reference:


    There is an alternative solution, follow the links for more information:


    If everything else fails:

    • bind a buffer to GL_PIXEL_PACK_BUFFER target
    • copy texture data into buffer via glGetTexImage
    • bind buffer to GL_PIXEL_UNPACK_BUFFER target
    • create cubemap face

    No client memory involved, all on the GPU side.