opengl 将等角立体图转换为等矩形立体图

holgip5t  于 2023-02-22  发布在  其他
关注(0)|答案(2)|浏览(145)

我正在用OpenGL制作一个复古风格的游戏,我想为它绘制我自己的立体图。下面是一个例子:

正如你所看到的,任何地方都没有透视变形;每个面都是完全等角的。2当用它作为立方体图时,结果是:

正如你所看到的,它看起来像长方体,一点也不像球形。我知道一个解决方案,就是把立方体图上的每个点重新Map到一个球体位置。我已经手动创建了一个球体网格,把立方体图纹理Map到它上面(然后渲染到一个环境贴图上),但是这很耗时也很复杂。
我寻求不同的解决方案:在我的片段着色器中,我希望将采样光线重Map到球体位置,而不是立方体位置。2这是我最初的片段着色器,没有任何改变:

#version 400 core

in vec3 cube_edge;

out vec3 color;

uniform samplerCube skybox_sampler;

void main(void) {
    color = texture(skybox_sampler, cube_edge).rgb;
}

我可以通过归一化cube_edge得到一条Map到球体的射线,但由于某种原因,这并没有改变任何东西。在稍微混乱了一下之后,我尝试了下面的Map,它几乎可以工作,但不完全是:

vec3 sphere_edge = vec3(cube_edge.x, normalize(cube_edge).y, cube_edge.z);

如您所见,某些面本质上变为球形,而顶面向内扭曲,而不是向外扭曲。
我也尝试了这个网站的结果:http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html,但是脸没有足够向外弯曲。
我已经坚持了这么久-如果你知道我可以改变我的立方体到球体Map在我的片段着色器,或者如果这是可能的,请让我知道!

aiazj4mn

aiazj4mn1#

正如你所看到的,任何地方都没有透视变形;每个面是完全等角的。
这个前提是不正确的,你手绘了一些图像;这并不意味着它们是等角的。
"等角立体图"(EAC)特指重新Map为by this formula的立体图(第2.4节):

u = 4/pi * atan(u)
v = 4/pi * atan(v)

我们首先要认识到,这个术语是误导性的,因为尽管EAC的目的是减少采样率的变化,但采样率并不是常数,事实上,球面任何部分的二维投影都不可能是真正等角的;这是一个数学事实。
尽管如此,我们可以尝试应用此修正。在GLSL片段着色器中实现为:

d /= max(abs(d.x), max(abs(d.y), abs(d.z));
d = atan(d)/atan(1);

给出以下结果:
第一节第一节第一节第一节第一次
将其与未校正的d进行比较:
第一节第二节第一节第三节第一节
正如您所看到的,EAC投影将中间的像素缩小了一点,并将它们扩展到角附近,以便它们覆盖更均匀的区域。然而,EAC在立方体的边缘附近并不是一个平滑的Map--也就是说,它可以使直线变尖--这似乎是您想要避免的伪像。
相反,看起来您需要围绕地平线的圆柱投影,这是平滑的。它可以如下实现:

d /= length(d.xy);
d.xy /= max(abs(d.x), abs(d.y));
d.xy = atan(d.xy)/atan(1);

它给出了如下结果:
一个四个一个一个一个五个一个
但是,没有一种方法可以将立方体的顶部/底部方形面拟合到圆柱体的圆形面上--这就是您在那里看到伪像的原因。
底线:你不能以一种视觉上令人愉悦的方式将你绘制的图像适合到球体上。你应该将你的精力重新集中在创作你的环境Map的替代方法上。我建议你尝试使用equidistant cylindrical projection作为地平线,在固定纬度之上/之下用纯色覆盖它,并且对不能在该投影中表示的对象使用布告牌。
例如,使用以下2D纹理:

和下面的公式:

float tau = 6.283185;
float u = atan(d.y, d.x);
float v = atan(d.z, length(d.xy));
OUT = texture(TEX, vec2(u/tau, 2*v/tau + 0.5));

我可以得到以下结果:
第一节第七节第一节第一节第八节第一节
我认为这会让你比任何基于立方体图的调整更进一步。

nwsw7zdq

nwsw7zdq2#

你的问题是放置环境的几何体太小了。你不是在看环境,而是在看你所坐的小立方体的内部。环境贴图应该表现得好像你总是在贴图的中心,而环境是无限远的。我建议在视见平截头体的远平面上绘制环境贴图。你可以通过设置剪辑空间位置的z分量等于顶点着色器中的w分量来实现。如果你设置zw,您可以保证位置的最终z值为1.0。这是远平面的z值。(你可以用Swizzling gl_Position = clipPos.xyww来实现)。绘制一个立方体并通过查找带有立方体内插顶点的贴图来包裹环境就足够了。在samplerCube的情况下,三维纹理坐标被当作一个方向矢量。2你可以用立方体的顶点坐标来查找纹理。
顶点着色器:

cube_edge = inVertex.xyz;

vec4 clipPos = projection * view * vec4(inVertex.xyz, 1.0);
gl_Position = clipPos.xyww;

片段着色器:

color = texture(skybox_sampler, cube_edge).rgb;

LearnOpenGL - Cubemap中也详细解释了该解决方案。

相关问题