2009-10-14 2 views
3

Представьте себе следующую ситуацию: у вас есть набор символов справки RPG в формате PNG и вы хотите использовать их в приложении OpenGL.Spritesheets OpenGL - новичкам нужно руководствоваться

Отдельные символы (обычно) размером от 16 до 24 пикселей (то есть 24 пиксела высотой) и могут иметь любую ширину и высоту, не оставляя отступы. Вроде как это:

Terra, from Final Fantasy VI http://helmet.kafuka.org/terra.net/nomura/Terra.png

У меня уже есть код, чтобы определить целое на основе прямоугольника отсечения заданного индекса и размера кадра:

int framesPerRow = sheet.Width/cellWidth; 
int framesPerColumn = sheet.Height/cellHeight; 
framesTotal = framesPerRow * framesPerColumn; 
int left = frameIndex % framesPerRow; 
int top = frameIndex/framesPerRow; 
//Clipping rect's width and height are obviously cellWidth and cellHeight. 

Выполнение этого кода с frameIndex = 11, cellWidth = 16, cellHeight = 24 возвратит cliprect (32, 24)-(48, 48) предполагая, что это правая/нижняя противоположность ширине/высоте.

Фактический вопрос

Теперь, учитывая прямоугольник отсечения и X/Y координат поместить спрайт на, как я рисую это в OpenGL? Предпочтительно иметь нулевую координату в верхнем верхнем.

+0

Возникает вопрос, как извлечь и отобрать конкретный спрайт? Непонятно, что вы подразумеваете под ничью. –

+0

Если вы делаете это на телефоне, вы можете ограничить opengl, где текстуры должны быть мощностью 2. Вы также можете сэкономить место, имея отдельную верхнюю/нижнюю половину каждого символьного изображения - это похоже на вас есть много поз, где только голова/ноги различаются. –

+0

Dana: в значительной степени это, да. mgb: Я не делаю этого по телефону. – Kawa

ответ

6

Вы должны начать думать в «пространстве текстур», где координаты находятся в диапазоне [0, 1].

Так что если у вас есть спрайт лист:

class SpriteSheet { 
    int spriteWidth, spriteHeight; 
    int texWidth, texHeight; 

    int tex; 

public: 
    SpriteSheet(int t, int tW, int tH, int sW, int sH) 
    : tex(t), texWidth(tW), texHeight(tH), spriteWidth(sW), spriteHeight(sH) 
    {} 

    void drawSprite(float posX, float posY, int frameIndex); 
}; 

Все, что вам нужно сделать, это представить оба вершин и текстурных вершин в OpenGL:

void SpriteSheet::drawSprite(float posX, float posY, int frameIndex) { 
     const float verts[] = { 
      posX, posY, 
      posX + spriteWidth, posY, 
      posX + spriteWidth, posY + spriteHeight, 
      posX, posY + spriteHeight 
     }; 
     const float tw = float(spriteWidth)/texWidth; 
     const float th = float(spriteHeight)/texHeight; 
     const int numPerRow = texWidth/spriteWidth; 
     const float tx = (frameIndex % numPerRow) * tw; 
     const float ty = (frameIndex/numPerRow + 1) * th; 
     const float texVerts[] = { 
      tx, ty, 
      tx + tw, ty, 
      tx + tw, ty + th, 
      tx, ty + th 
     }; 

     // ... Bind the texture, enable the proper arrays 

     glVertexPointer(2, GL_FLOAT, verts); 
     glTextureVertexPointer(2, GL_FLOAT, texVerts); 
     glDrawArrays(GL_TRI_STRIP, 0, 4); 
    } 

}; 
+0

Я принял этот ответ и заменил массивы glBegin, glTexCoord2f/glVertex2f и glEnd вызовы. Все перевернуто, включая сам спрайт, который Терра смеется, но сейчас очень близко ... – Kawa

+0

Координаты теперь перевернуты. Спрайт рисуется, как и должно быть! – Kawa

+1

Один мужчина вверх ногами - это правая сторона другого человека. :-) Рад, что вы получили его так, как вам нравится. –

0

Я предполагаю, что вы изучаете OpenGL, и только нужно заставить это работать как-то. Если вам нужна необработанная скорость, есть шейдеры и вершинные буферы и всевозможные аккуратные и сложные вещи.

Самый простой способ - загрузить PNG в текстуру (при условии, что у вас есть возможность загружать изображения в память, вам нужен htat), а затем нарисуйте его с помощью квадрата, задающего соответствующие координаты текстуры (они идут от 0 до 1 с координатами с плавающей точкой, поэтому вам нужно разделить по ширине или высоте текстуры соответственно).

Используйте glBegin (GL_QUADS), glTexcoord2f(), glVertex2f(), glEnd() для простейшего (но не самого быстрого) способа рисования.

Для создания нулевого верхнего левого угла используйте gluOrtho(), чтобы настроить матрицу вида иначе, чем обычный GL (найдите документы для этой функции, установите верхнюю часть на 0 и снизу на 1 или screen_height, если вам нужны целые координаты) или просто измените свой цикл рисования и просто сделайте glVertex2f (x/screen_width, 1-y/screen_height).

Есть более быстрые и быстрые способы сделать это, но это, вероятно, один из самых простых, если вы изучаете необработанный OpenGL с нуля.

0

предложение, если я май. Я использую SDL для загрузки своих текстур, так что я сделал это: 1. Я загрузил текстуру 2. Я определил, как разделить спрайт на отдельные спрайты. 3. Я разделил их на отдельные поверхности. 4. Я делаю текстуру для каждого (у меня есть класс спрайтов для управления ими). 5. Освободите поверхности. Это занимает больше времени (очевидно) при загрузке, но платит позже. Таким образом, это намного проще (и быстрее), так как вам нужно только вычислить индекс текстуры, который вы хотите отобразить, а затем отобразить. Затем вы можете масштабировать/переводить его по своему усмотрению и вызывать список отображения, чтобы отображать его по своему желанию. Или вы можете сделать это в ближайшем режиме, либо работает :)

+1

Использование одной поверхности/текстуры для каждого кадра является плохой идеей. Переключение текстур - очень дорогостоящая операция. Обычно мы очень стараемся объединить столько текстур в одно, сколько можем. – Andreas

6

Решение франков уже очень хорошее.

Просто (очень важно) sidenote, так как некоторые из комментариев предлагаются иначе.

Пожалуйста, никогда не используйте glBegin/glEnd. Никогда не говорите кому-то, чтобы использовать его.

Единственный раз, когда вы используете glBegin/glEnd в своей первой программе OpenGL.

Массивы не намного сложнее справиться, но ...

  • ... они быстрее.
  • ... они по-прежнему будут работать с новыми версиями OpenGL.
  • ... они будут работать с GLES.
  • ... Загрузка их из файлов намного проще.