문제 설명
큐브맵을 2D 텍스처로 투영 (Project cubemap to 2D texture)
다음과 같이 전체를 2D 텍스처에 투영하여 큐브맵으로 렌더링 기능을 디버그하고 싶습니다.
텍스처 셰이더에서 렌더링할 때 UV 텍스처 좌표만 사용할 수 있습니다((0,0) ~ (1,1) 범위). 단일 드로우 콜에서 큐브맵을 화면에 어떻게 투영할 수 있습니까?
참조 솔루션
방법 1:
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:
방법 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):
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:
(by Bruno Sena、Spektre、Nikolaj)