繁体   English   中英

Pyglet。 如何动态更改顶点的图片(动画)。 OpenGL的

[英]Pyglet. How to change picture(animate) for vertices dynamically. OpenGL

环境:

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,在第二张图片之后,......等等。
正如我从上一个问题中所理解的那样,在3D批处理中使用pyglet.sprite.Sprite()并不是一个好主意。

题:

我如何在self.vertices上更改图片(使用TextureGroup或任何其他方法)?

或者我使用哪些arroach /类来实现它。 我找不到任何这样的例子(对于我的简单视觉)通常情况作为三维平面模型的动画。

关于vertices旋转/移动/调整大小有很多例子,但是如何建立一个正确的问题(动画方面)来获得谷歌的答案 - 我不知道。

PS :如果你, 读者 ,对这个主题有任何有用的链接(对于pyglet或仅用于OpenGL),我将非常感谢你在评论中分享这个链接。

纹理坐标。

对于所有动画的所有帧,你应该有一个纹理图集。

优选地,一切都应该具有相同的动画速度和相同的帧数。

假设有两个精灵,整个动画有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”:

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正常,你只需要垂直ID或其他东西,并使用tile_height * sprite_id来获得当前的V坐标,你的U计算像tile_width * current_frame

这假设你已经有sprite批处理所以你所做的就是在更新时查看每个sprite,基本上只需用新帧重新计算新的UV,这意味着所有的精灵都会将它们的帧更改为下一个!

如果你想拥有一个独立于彼此的系统,比如说某些系统的动画非常慢,而对其他系统来说更快,那么你需要不同的精灵批量或正确计算你需要在哪里更新顶点缓冲区数组中的UV。 其他所有内容都完全相同,除非现在current_frame不是全局的,而是包含在内,优先包含在管理动画定时器的某个列表或单独对象中。

您不需要在着色器中更改任何内容,只需要对框架使用正确的UV,就可以进行设置。

顺便说一句,这是非常基本的,你可以自己应用一些逻辑,所以你可以在纹理中使用16x16网格的32x32像素,每行精灵有4种不同的动画,这些可以是精灵的状态(攻击,运行等) ),但你如何做到完全取决于你,最重要的是,让它发挥作用。 祝好运。

但是,如果按照我说的方式进行,那么状态将是另一个整数,UV为状态,假设所有状态具有完全相同的宽度,它将是这样的:

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

现在,出现了一个问题,玩家可以在最后一个攻击框架开始他的动画。

这是正常的,有行动的实体应该都有个别的计时器,我上面描述的,是大量的精灵,只是背景,如草。 现在,当您将其分割时,您可以通过适当的方式在分配新状态时当前帧重置为0。

如果你的实体是对象,你可以编写适当的方法,每次使用这些精灵重建精灵批处理时重新计算UV,然后定时器本身就可以包含在对象中。

我们需要画一些东西吗? 检查动画状态,改变了吗,没有? 发送之前计算过的UV,否则,稍等一下,我们需要重新计算,然后再将它们添加到VBO,好吧,渲染你的东西,最后,它会显得好像你有动画,即使真的,它是只是一个简单但很棒的UV操作。

祝好运。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM