Применение части текстуры (спрайт-листа / карты текстуры) к точечному спрайту в iOS OpenGL ES 2.0 - PullRequest
11 голосов
/ 08 марта 2012

Кажется, это должно быть легко, но у меня много трудностей с использованием части текстуры с точечным спрайтом. Я много гуглял и выискивал разные ответы, но ни один из них не касался конкретной проблемы, с которой я столкнулся.

Что я выучил до сих пор:

  1. Основы точечного спрайтового рисования
  2. Как работать с точечными спрайтами, которые отображаются сплошными квадратами
  3. Как изменить ориентацию точечного спрайта
  4. Как использовать несколько текстур с точечным спрайтом , приближаясь сюда ..
  5. Эта точка спрайтов + листы спрайтов уже была сделана ранее, но возможна только в OpenGL ES 2.0 (не 1.0)

Вот диаграмма того, чего я пытаюсь достичь

Point sprite diagram

Где я нахожусь:

  • У меня есть набор спрайтов рабочих точек, использующих одно и то же квадратное изображение. Например: изображение круга размером 16x16 отлично работает.
  • У меня есть метод Objective-C, который генерирует изображение 600x600, содержащее спрайт-лист с несколькими изображениями. Я убедился, что это работает, применяя все изображение спрайт-листа к четырехугольнику, нарисованному с помощью GL_TRIANGLES.
  • Я успешно использовал вышеописанный метод для рисования частей листа спрайта на четырехугольниках. Я просто не могу заставить его работать с точечными спрайтами.
  • В настоящее время я генерирую текстурные координаты, указывающие на центр спрайта на листе спрайта, на который я нацеливаюсь. Например: используя изображение внизу; звезда: 0,166,0,5; облако: 0,5,0,5; сердце: 0,833,0,5.

Код:

Вершинный шейдер

uniform mat4 Projection;
uniform mat4 Modelview;
uniform float PointSize;

attribute vec4 Position;
attribute vec2 TextureCoordIn;

varying vec2 TextureCoord;

void main(void)
{
    gl_Position = Projection * Modelview * Position;
    TextureCoord = TextureCoordIn;
    gl_PointSize = PointSize;
}

Фрагмент шейдера

varying mediump vec2 TextureCoord;
uniform sampler2D Sampler;

void main(void)
{
    // Using my TextureCoord just draws a grey square, so
    // I'm likely generating texture coords that texture2D doesn't like.
    gl_FragColor = texture2D(Sampler, TextureCoord);

    // Using gl_PointCoord just draws my whole sprite map
    // gl_FragColor = texture2D(Sampler, gl_PointCoord);
}

На чем я застрял:

  1. Я не понимаю, как использовать переменную gl_PointCoord в фрагментном шейдере. Что изначально содержит gl_PointCoord? Зачем? Где он получает свои данные?
  2. Я не понимаю, какие координаты текстуры передать. Например, как точечный спрайт выбирает, какую часть моего листа спрайта использовать на основе координат текстуры? Я привык рисовать четырехугольники, которые фактически имеют 4 набора текстурных координат (по одному на каждую вершину), как это отличается (ясно, что это так)?

Ответы [ 2 ]

10 голосов
/ 21 марта 2012

Мой коллега помог с ответом.Оказывается, хитрость заключается в том, чтобы использовать как размер точки (в единицах OpenGL), так и размер спрайта (в единицах текстуры, (0..1)) в сочетании с небольшой векторной математикой для визуализации только частиспрайт-лист на каждую точку.

Vertex Shader

uniform mat4 Projection;
uniform mat4 Modelview;
// The radius of the point in OpenGL units, eg: "20.0"
uniform float PointSize;
// The size of the sprite being rendered. My sprites are square
// so I'm just passing in a float.  For non-square sprites pass in
// the width and height as a vec2.
uniform float TextureCoordPointSize;

attribute vec4 Position;
attribute vec4 ObjectCenter;
// The top left corner of a given sprite in the sprite-sheet
attribute vec2 TextureCoordIn;

varying vec2 TextureCoord;
varying vec2 TextureSize;

void main(void)
{
    gl_Position = Projection * Modelview * Position;
    TextureCoord = TextureCoordIn;
    TextureSize = vec2(TextureCoordPointSize, TextureCoordPointSize);

    // This is optional, it is a quick and dirty way to make the points stay the same
    // size on the screen regardless of distance.
    gl_PointSize = PointSize / Position.w;
}

Фрагментный шейдер

varying mediump vec2 TextureCoord;
varying mediump vec2 TextureSize;
uniform sampler2D Sampler;

void main(void)
{
    // This is where the magic happens.  Combine all three factors to render
    // just a portion of the sprite-sheet for this point
    mediump vec2 realTexCoord = TextureCoord + (gl_PointCoord * TextureSize);
    mediump vec4 fragColor = texture2D(Sampler, realTexCoord);

    // Optional, emulate GL_ALPHA_TEST to use transparent images with
    // point sprites without worrying about z-order.
    // see: http://stackoverflow.com/a/5985195/806988
    if(fragColor.a == 0.0){
        discard;
    }

    gl_FragColor = fragColor;
}
4 голосов
/ 08 марта 2012

Точечные спрайты состоят из одной позиции. Поэтому любые «изменяющиеся» значения на самом деле не будут изменяться , потому что между ними нечего интерполировать.

gl_PointCoord - это значение vec2, где значения XY находятся в диапазоне [0, 1]. Они представляют местоположение на точке. (0, 0) - нижний левый угол точки, а (1, 1) - верхний правый.

Итак, вы хотите отобразить (0, 0) в левом нижнем углу вашего спрайта и (1, 1) в правом верхнем. Для этого вам нужно знать определенные вещи: размер спрайтов (при условии, что они все одинакового размера), размер текстуры (потому что функции выборки текстуры принимают нормализованные координаты текстуры, а не местоположения в пикселях) и который спрайт в данный момент отображается.

Последний может быть установлен с помощью varying. Это может быть просто значение, которое передается в виде данных на каждую вершину в varying в вершинном шейдере.

Вы используете это плюс размер спрайтов, чтобы определить, где в текстуре вы хотите получить данные для этого спрайта. Когда у вас есть тексельские координаты, которые вы хотите использовать, вы делите их на размер текстуры, чтобы получить нормализованные координаты текстуры.

В любом случае точечные спрайты, несмотря на название, на самом деле не предназначены для рендеринга sprite . Для этого было бы проще использовать четырехугольники / треугольники, поскольку вы можете быть более уверенными в том, какие именно позиции есть у всех.

...