4

I'd like to debug my render to cubemap function by projecting the whole thing to a 2D texture just like this one:

On my render from texture shader I've only got the UV texture coordinates available (ranging from (0,0) to (1,1)). How can I project the cubemap to the screen in a single draw call?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Bruno Sena
  • 43
  • 1
  • 4
  • The previous answer is correct , However In my case(commercial),straight projection is not a valid choice . Getting 2D texture from cubemap needs some methods such as blur to render a realistic scene. [CMFT](https://github.com/dariomanesku/cmftStudio) is recommended. – LiShaoyuan Apr 16 '19 at 13:29

2 Answers2

4

You can do this by rendering 6 quads and using 3D texture coords (s,t,p) pointing to each vertex of the cube so 8 variations of ( +/-1,+/-1,+/-1 ).

The UV 2D coords (s,t) like 4 variations of (0/1,0/1) are not usable for whole CUBE_MAP only for its individual sides.

Look for txr_skybox in here

on how CUBE_MAP is used in fragment shader.

PS in OpenGL the texture coords are called s,t,p,q instead of u,v,w,...

Here related QA:

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Thank you! I'll try it. Wasn't aware of the convention on texture coordinate names – Bruno Sena Jan 09 '19 at 18:32
  • @BrunoSena older GL used `s,t,r,q` but in GLSL it was conflicting with `r,g,b` so they rename it to `s,t,p,q` ... however I was trying to do this few ours ago and it looks like my current GL implementation has problems with using 2D QUADs will look into it deeper if not working you can still use 3D cube without projection ... There is also possibility of binding the plane instead of cube map for each side separately .... – Spektre Jan 09 '19 at 20:27
2

My answer is essentially the same as the one accepted one, but I have used this very technique to debug my depth-cubemap (used for shadowcasting) in my current project, so I thought I would include a working sample of the fragment shader code I used.

Unfolding cubemap

This is supposed to be rendered to a rectangle on top of the screen with aspect ratio 3/4 directly on the screen and with s,t going from (0,0) in the lower-left corner to (1,1) at the upper-right corner.

Note that in this case, the cubemap I use is inverted, that is objects to the +(x,y,z) side of the cubemap origen is rendered to -(x,y,z), and the direction I choose as up for the top/bottom quads are completely arbitrary; so to get this example to work you may need to change some signs or swap s and t some times, also note that I here only read one channel, as it is debth map:

Fragment shader code for a quad-map as the one in the question:

//Should work in most other versions
#version 400 core

uniform samplerCube dynamic_texture;

out vec4 out_color;
in vec2 ST;

void main()
{
    //In this example i use a debthmap with only 1 channel, but the projection should work with a colored cubemap to, just replace this with a vec3 or vec4    
    float debth=0;
    vec2 localST=ST;
    
    
    
    
    //Scale Tex coordinates such that each quad has local coordinates from 0,0 to 1,1
    localST.t = mod(localST.t*3,1);
    localST.s = mod(localST.s*4,1);
    

    //Due to the way my debth-cubemap is rendered, objects to the -x,y,z side is projected to the positive x,y,z side

    
    //Inside where tob/bottom is to be drawn?
    if (ST.s*4>1 && ST.s*4<2)
    {
        //Bottom (-y) quad
        if (ST.t*3.f < 1)
        {
            vec3 dir=vec3(localST.s*2-1,1,localST.t*2-1);//Get lower y texture, which is projected to the +y part of my cubemap
            
            debth = texture( dynamic_texture, dir ).r;
        }
        //top (+y) quad
        else if (ST.t*3.f > 2)
        {
            vec3 dir=vec3(localST.s*2-1,-1,-localST.t*2+1);//Due to the (arbitrary) way I choose as up in my debth-viewmatrix, i her emultiply the latter coordinate with -1
            
            debth = texture( dynamic_texture, dir ).r;
        }
        else//Front (-z) quad
        {
            vec3 dir=vec3(localST.s*2-1,-localST.t*2+1,1);
            
            debth = texture( dynamic_texture, dir ).r;
            
        }

    
    }
    //If not, only these ranges should be drawn
    else if (ST.t*3.f > 1 && ST.t*3 < 2)
    {
        if (ST.x*4.f < 1)//left (-x) quad
        {
            vec3 dir=vec3(-1,-localST.t*2+1,localST.s*2-1);
            
            debth = texture( dynamic_texture, dir ).r;
                    
        }
        else if (ST.x*4.f < 3)//right (+x) quad (front was done above)
        {
            vec3 dir=vec3(1,-localST.t*2+1,-localST.s*2+1);
            
            debth = texture( dynamic_texture, dir ).r;
                    
        }
        else //back (+z) quad 
        {
            vec3 dir=vec3(-localST.s*2+1,-localST.t*2+1,-1);
            
            debth = texture( dynamic_texture, dir ).r;
                    
        }

        
    }
    else//Tob/bottom, but outside where we need to put something
    {
        discard;//No need to add fancy semi transparant borders for quads, this is just for debugging purpose after all
    }
    
    out_color = vec4(vec3(debth),1);
}

Here is a screenshot of this technique used to render my depth-map in the lower-right corner of the screen (rendering with a point-light source placed at the very center of an empty room with no other objects than the walls and the player character):

Looking at a wall, with the player's shadow visible

Equirectangular projection

I must, however, say that I prefer using an equirectangular projection for debugging cubemaps, as it doesn't have any holes in it; and, luckily, these are even easier to make than unfolded cubemaps, just use a fragment shader like this (still with s,t going from (0,0) to (1,1) from lower-left to upper-right corner), but this time with aspect ratio 1/2:

//Should work in most other versions
#version 400 core

uniform samplerCube dynamic_texture;

out vec4 out_color;
in vec2 ST;

void main()
{
    float phi=ST.s*3.1415*2;
    float theta=(-ST.t+0.5)*3.1415;
    
    
    vec3 dir = vec3(cos(phi)*cos(theta),sin(theta),sin(phi)*cos(theta));

    //In this example i use a debthmap with only 1 channel, but the projection should work with a colored cubemap to
    float debth = texture( dynamic_texture, dir ).r;
    out_color = vec4(vec3(debth),1);
}

Here is a screenshot where an equirectangular projection is used to display my depth-map in the lower-right corner:

Equirectangula

Community
  • 1
  • 1
Nikolaj
  • 1,137
  • 10
  • 22