Pyglet.Как динамически менять картинку (анимацию) для вершин.OpenGL - PullRequest
0 голосов
/ 16 октября 2018

Среда:

Python: 3.6.6
версия pyglet: 1.3.2

База кода:

abstract_model.py

import pyglet


def get_texture_group(file, order_group_index):
    texture = pyglet.image.load(file).texture
    order_group = pyglet.graphics.OrderedGroup(order_group_index)
    return pyglet.graphics.TextureGroup(texture, order_group)


class AbstractModel(object):

    def _create_as_vertex(self):
        v_x = self.cell_data.get("x") * 32
        v_y = self.cell_data.get("y") * -1 * 32

        texture_group = self.map_type_iamge.get(self.cell_data.get("t"))
        x_offset = self.x_offset * self.scale

        x, y, z = v_x + x_offset, v_y, self.z
        x_ = (texture_group.texture.width * self.scale + x_offset + v_x)
        y_ = (texture_group.texture.height * self.scale + v_y)

        tex_coords = ('t2f', (0, 0, 1, 0, 1, 1, 0, 1))

        self.vertices = self.batch.add(
            4, pyglet.gl.GL_QUADS,
            texture_group,
            ('v3f', (x, y, z,
                     x_, y, z,
                     x_, y_, z,
                     x, y_, z)),
            tex_coords)

    def _animate(self, dt):
        # lets assume that I have list of pyglet.graphics.TextureGroup
        # and they should somehow be drawn one after other
        print("I need change image. dt=", dt, self)
        pyglet.clock.schedule_once(self._animate, 1)

ground3d.py

import os
import pyglet

import settings
from models import abstract_model


GROUND_DIR = os.path.join(settings.STATIC_DIR, "ground")

order_group_index = 0

map_type_iamge = {
    1: abstract_model.get_texture_group(os.path.join(GROUND_DIR, "w1.png"), order_group_index),
    2: abstract_model.get_texture_group(os.path.join(GROUND_DIR, "t1.png"), order_group_index),
    1001: abstract_model.get_texture_group(os.path.join(GROUND_DIR, "t1_direction.png"), order_group_index),
}


class Ground3D(abstract_model.AbstractModel):

    def __init__(self, cell_data, batch):

        self.batch = batch
        self.cell_data = cell_data
        self.map_type_iamge = map_type_iamge
        self.scale = 1
        self.x_offset = 0
        self.z = 0
        self.entity = None

        self._create_as_vertex()
        pyglet.clock.schedule_once(self._animate, 1)

Объяснение:

У меня есть модели (для примера просто плоский прямоугольник), которые должны быть размещены в 3 измерениях.И эти модели должны быть анимированы, как picture_1, после второго picture_2, ... и т. Д.
Как я понял из моего предыдущего вопроса использование pyglet.sprite.Sprite() в 3D-пакете не очень хорошая идея.

Вопрос:

Как я могу изменить рисунки (используя TextureGroup или любые другие подходы) на self.vertices?

Или какие массивы / классы я использую для его реализации,Я не могу найти примеров для такого (как для моего простого видения) обычного случая, как анимация для некоторых плоских моделей в 3-х измерениях.

Есть много примеров о вращении / перемещении / изменении размера vertices, но как построить правильный вопрос (это аспект анимации) для получения ответа в Google - я не знаю.

PS : Если вы, читатель , есть какие-либо полезные ссылки на эту тему (для pyglet или просто для OpenGL) Я был бы очень признателен, чтобы вы поделились этой ссылкой (ями) в комментарии.

1 Ответ

0 голосов
/ 22 октября 2018

Координаты текстуры.

У вас должен быть один атлас текстуры для всех кадров всех разных анимированных вещей.

Желательно, чтобы у всех была одинаковая скорость анимации и одинаковое количество кадров.все время.

Допустим, есть два спрайта, которые имеют 2 кадра для всей анимации, и они хранятся в текстурном атласе 64x64.(РЕДАКТИРОВАТЬ: извините за неоднозначность, 64x64 PIXELS, просто потому, что это может означать, что у нас есть атлас плиток 64x64, то же самое везде, где я упоминаю об этом)

Теперь вам нужно иметь глобальный таймер с глобальным значением, которое указываеттекущий кадр анимации , а не игровой кадр.Он не должен зависеть от частоты кадров.

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

current_frame = (current_frame + 1) % animation_length

Поскольку у нас есть 2 кадрав этом примере это будет выглядеть так:

# init
animation_length = 2
current_frame = 0

# updates:
current_frame = (0 + 1) % 2 # 1 % 2 -> 1
current_frame = (1 + 1) % 2 # 2 % 2 -> 0
...

Теперь вам нужно обновлять UV всех ваших спрайтов только при изменении кадра.

UV начинается слева направо и идетот 0 до 1 (насколько я помню, ради этого примера они делают, тссс).

Так как у нас есть 2 кадра каждый, мы можем вычислить «плитки» в координатах UV следующим образом:

tile_width = 1.0 / frames # 2 frames each, width will be 0.5
tile_height = 1.0 / sprites # 2 sprites each, height will be 0.5 too, perfect

Теперь в первом кадре вы генерируете свой UV как нормальный, вы просто берете вертикальный идентификатор или что-то в этом роде и используете tile_height * sprite_id, чтобы получить текущую V координату, и ваш U вычисляетсянапример, tile_width * current_frame.

Это предполагает, что у вас уже есть пакетная обработка спрайтов, поэтому вы проверяете каждый спрайт при обновлении и в основном просто пересчитываете новые UV с новым кадром, то есть все спрайты меняют свой кадр на следующий.один, ууу!

Если вы хотите иметь системы, независимые друг от друга, скажем, очень медленную анимацию для одних и более быструю для других, вам потребуются разные партии спрайтов или надлежащий расчет, откуда и где вам нужно обновить UV в вершине.буферный массив.Все остальное точно так же, за исключением того, что теперь current_frame не будет глобальным, а скорее будет содержаться, предпочтительно в каком-то списке или отдельном объекте, который управляет таймерами для анимации.

Вам не нужно ничего менять в своих шейдерах,им просто нужны правильные UV для кадров, и вы настроены.

Кстати, это очень просто, вы можете применить некоторую логику самостоятельно, чтобы вместо этого вы могли иметь сетку 16x16 из 32x32 пикселей в вашей текстуре, каждыйВ линейке спрайтов, имеющих 4 разные анимации, это могут быть либо состояния спрайта (атака, бег и т. д.), но то, как вы это сделаете, полностью зависит от вас, и самое главное - заставить его работать.Goodluck.

Но если вы сделаете это так, как я сказал, то состояние будет другим целым числом, а UV для состояния, при условии, что все состояния имеют одинаковую ширину, будет выглядеть так:

state_width = 1 / states
tile_width = 1 / (states * frames_per_state)
U = state_width * current_state + tile_width * current_frame

Теперь возникает одна проблема: игрок может запустить анимацию с последнего кадра атаки.

Это нормально, у сущностей с действиями должны быть отдельные таймеры, как я описал выше, для тонны спрайтов, которыепросто фон, как трава.Теперь, когда вы разделите его, у вас может быть правильный способ сбросить текущего кадра на 0 при назначении нового состояния.

Если ваши объекты являются объектами, вы можете написать надлежащие методы, которые пересчитываютУФ каждый раз, когда вы перестраиваете пакет спрайтов, используя эти спрайты, а затем сами таймеры могут содержаться в объектах.

Нам нужно что-то нарисовать?Проверьте состояние анимации, оно изменилось, нет?Отправьте UV, которые были рассчитаны ранее, в противном случае, подождите немного, нам нужно пересчитать, только затем добавить их в VBO, и, в общем, отрендерить вашу вещь, в конце концов, это будет выглядеть так, как будто у вас есть анимация, хотя на самом деле этопросто простая, но отличная УФ-манипуляция.

Goodluck.

...