Если вы хотите проецировать 2D-текстур на 2-мерную плоскость, как если бы это был 3D-цилиндр, вам необходимо преобразовать координату текстуры с помощью функции arcus (asin
или acos
) во фрагментном шейдере.
Координаты текстуры в диапазоне [0, 1] должны быть связаны с углом на окружности в диапазоне [-90°, 90 °] с помощью функции asin
.Этот угол может быть линейно сопоставлен с новой текстурной координатой в диапазоне [0, 1].
![](https://i.stack.imgur.com/4VE0t.png)
Вход для функции - это угол, а возвращаемое значение - это расстояние:
float u = asin( vTexCoord.x*2.0-1.0 ) / 3.141593 + 0.5;
![](https://i.stack.imgur.com/QWpG5.png)
Вершинный шейдер :
attribute vec3 a_position;
varying vec2 vTexCoord;
void main()
{
vTexCoord = (a_position.xy + 1) / 2;
gl_Position = vec4(a_position, 1);
}
Фрагментный шейдер :
precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoord;
void main()
{
float u = asin( vTexCoord.x*2.0-1.0 ) / 3.141593 + 0.5;
float v = vTexCoord.y;
vec4 color = texture2D(sTexture, vec2(u, v));
gl_FragColor = color;
}
Смотрите разницумежду результатом исходного кода и кодом, который использует отображение asin
:
![](https://i.stack.imgur.com/tS70o.png)
В проекции на плоскость 2D верх и низ цилиндра представляет собой эллипс , который можно выразить как:
![](https://i.stack.imgur.com/zyKmY.png)
float b = 0.3;
float y = b * sqrt(1.0 - x*x)
Проекция текстуры должна быть сжата сверху и снизу, чтобы сформировать эллиптическую форму:
![](https://i.stack.imgur.com/sJaqz.png)
float v_scale = (1.0 + b) / (1.0 + y);
float v = (pos.y * v_scale) * 0.5 + 0.5;
Обрезанную область необходимо отбросить с помощью ключевого слова discard
в фрагментном шейдере :
if ( v < 0.0 || v > 1.0 )
discard;
Узнать разницу между результатами безэллиптическое искажение и код, который используетэллиптическое искажение:
![](https://i.stack.imgur.com/uY0Cr.png)
Фрагментный шейдер, который сочетает в себе отображение координат текстуры asin
иэллиптическое искажение:
Фрагмент шейдера:
precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoord;
void main()
{
vec2 pos = vTexCoord.xy * 2.0 - 1.0;
float b = 0.3;
float v_scale = (1.0 + b) / (1.0 + b * sqrt(1.0 - pos.x*pos.x));
float u = asin( pos.x ) / 3.1415 + 0.5;
float v = (pos.y * v_scale) * 0.5 + 0.5;
if ( v < 0.0 || v > 1.0 )
discard;
vec3 texColor = texture2D( u_texture, vec2(u, v) ).rgb;
gl_FragColor = vec4( texColor.rgb, 1.0 );
}
Совокупный результат:
![](https://i.stack.imgur.com/acSZH.png)