Если вы хотите проецировать 2D-текстур на 2-мерную плоскость, как если бы это был 3D-цилиндр, вам необходимо преобразовать координату текстуры с помощью функции arcus (asin
или acos
) во фрагментном шейдере.
Координаты текстуры в диапазоне [0, 1] должны быть связаны с углом на окружности в диапазоне [-90°, 90 °] с помощью функции asin
.Этот угол может быть линейно сопоставлен с новой текстурной координатой в диапазоне [0, 1].
Вход для функции - это угол, а возвращаемое значение - это расстояние:
float u = asin( vTexCoord.x*2.0-1.0 ) / 3.141593 + 0.5;
Вершинный шейдер :
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
:
В проекции на плоскость 2D верх и низ цилиндра представляет собой эллипс , который можно выразить как:
float b = 0.3;
float y = b * sqrt(1.0 - x*x)
Проекция текстуры должна быть сжата сверху и снизу, чтобы сформировать эллиптическую форму:
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;
Узнать разницу между результатами безэллиптическое искажение и код, который используетэллиптическое искажение:
Фрагментный шейдер, который сочетает в себе отображение координат текстуры 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 );
}
Совокупный результат: