問題描述
將立方體貼圖投影到 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)