2017-12-25 5 views
2

128個のパーティクルをレンダリングするときにプログラムが遅くなるのはなぜですか? 30fps以下で十分ではないと思います。128個のパーティクルをレンダリングしているときに、pygletプログラムが遅くなるのはなぜですか?

すべて私は128個の粒子をレンダリングし、それらにいくつかの基本的な重力を与えているん

on_draw機能

def on_draw(self, time=None): 
    glClearColor(0.0, 0.0, 0.0, 1.0) 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 
    glLoadIdentity() 

    self.particles.append(Particle()) 
    for particle in self.particles: 
     particle.draw() 

     if particle.is_dead: 
      self.particles.remove(particle) 

粒子クラス

class Particle: 

    def __init__(self, **kwargs): 
     self.acceleration = Vector2(0, 0.05) 
     self.velocity = Vector2(random.uniform(-1, 1), random.uniform(-1, 0)) 
     self.position = Vector2() 
     self.time_to_live = 255 

     self.numpoints = 50 

     self._vertices = [] 

     for i in range(self.numpoints): 
      angle = math.radians(float(i)/self.numpoints * 360.0) 
      x = 10 * math.cos(angle) + self.velocity[0] + 300 
      y = 10 * math.sin(angle) + self.velocity[1] + 400 
      self._vertices += [x, y] 

    def update(self, time=None): 
     self.velocity += self.acceleration 
     self.position -= self.velocity 
     self.time_to_live -= 2 

    def draw(self): 
     glEnable(GL_BLEND) 
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 
     glPushMatrix() 
     glTranslatef(self.position[0], self.position[1], 0) 
     pyglet.graphics.draw(self.numpoints, GL_TRIANGLE_FAN, ('v2f', self._vertices), ('c4B', self.color)) 
     glPopMatrix() 

     self.update() 

    @property 
    def is_dead(self): 
     if self.time_to_live <= 0: 
      return True 
     return False 

    @property 
    def color(self): 
     return tuple(color for i in range(self.numpoints) for color in (255, 255, 255, self.time_to_live)) 
+2

いくつかのこと:間違った種類のOpenGLを使い始めました。 "modern OpenGL"を検索し、最初からやり直してください。あなたのコードは、あらゆる種類の古いOpenGLナンセンスで盛り込まれています。 'Particle'のインスタンス上で' draw'を呼び出すたびに、GL状態を重複して更新します。ブレンド状態 - 外側のレンダリングループにその要素を引き出します。それ以外にも、あなたの問題を引き起こすものはそれほど明白ではありませんが、1995年からGPUを使用していない限り、純粋にCPUバウンドになっている可能性が非常に高いです(いくつかの色付きポイントはGL実装やGPUに日々)。 – thokra

答えて

2

それはだから、私はGL_TRIANGLE_FANの使用方法について過度に満足していませんバッチレンダリングを使用すると、奇妙な形が多く発生しました。したがって、代わりにGL_TRIANGLESに移動し、GLに傾いている代わりにオブジェクトにすべてのポイントを追加して、あなたのために形状を閉じることを検討してください。

そのように、あなたは簡単にレンダリングのバッチ処理を行うに上に移動することができます

import pyglet 
from pyglet.gl import * 
from collections import OrderedDict 
from time import time, sleep 
from math import * 
from random import randint 

key = pyglet.window.key 

class CustomGroup(pyglet.graphics.Group): 
    def set_state(self): 
     #pyglet.gl.glLineWidth(5) 
     #glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) 
     #glColor4f(1, 0, 0, 1) #FFFFFF 
     #glLineWidth(1) 
     #glEnable(texture.target) 
     #glBindTexture(texture.target, texture.id) 
     pass 

    def unset_state(self): 
     glLineWidth(1) 
     #glDisable(texture.target) 

class Particle(): 
    def __init__(self, x, y, batch, particles): 
     self.batch = batch 
     self.particles = particles 
     self.group = CustomGroup() 

     self.add_point(x, y) 

    def add_point(self, x, y): 

     colors =()#255,0,0 

     sides = 50 
     radius = 25 

     deg = 360/sides 
     points =()#x, y # Starting point is x, y? 

     prev = None 
     for i in range(sides): 

      n = ((deg*i)/180)*pi # Convert degrees to radians 
      point = int(radius * cos(n)) + x, int(radius * sin(n)) + y 

      if prev: 
       points += x, y 
       points += prev 
       points += point 
       colors += (255, i*int(255/sides), 0)*3 # Add a color pair for each point (r,g,b) * points[3 points added] 

      prev = point 

     points += x, y 
     points += prev 
     points += points[2:4] 
     colors += (255, 0, 255)*3 

     self.particles[len(self.particles)] = self.batch.add(int(len(points)/2), pyglet.gl.GL_TRIANGLES, self.group, ('v2i/stream', points), ('c3B', colors)) 

class main(pyglet.window.Window): 
    def __init__ (self, demo=False): 
     super(main, self).__init__(800, 600, fullscreen = False, vsync = True) 
     #print(self.context.config.sample_buffers) 
     self.x, self.y = 0, 0 

     self.sprites = OrderedDict() 
     self.batches = OrderedDict() 
     self.batches['default'] = pyglet.graphics.Batch() 
     self.active_batch = 'default' 

     for i in range(1000): 
      self.sprites[len(self.sprites)] = Particle(randint(0, 800), randint(0, 600), self.batches[self.active_batch], self.sprites) 

     self.alive = True 

     self.fps = 0 
     self.last_fps = time() 
     self.fps_label = pyglet.text.Label(str(self.fps) + ' fps', font_size=12, x=3, y=self.height-15) 

    def on_draw(self): 
     self.render() 

    def on_close(self): 
     self.alive = 0 

    def on_key_press(self, symbol, modifiers): 
     if symbol == key.ESCAPE: # [ESC] 
      self.alive = 0 

    def render(self): 
     self.clear() 
     #self.bg.draw() 

     self.batches[self.active_batch].draw() 

     self.fps += 1 
     if time()-self.last_fps > 1: 
      self.fps_label.text = str(self.fps) + ' fps' 
      self.fps = 0 
      self.last_fps = time() 

     self.fps_label.draw() 
     self.flip() 

    def run(self): 
     while self.alive == 1: 
      self.render() 

      # -----------> This is key <---------- 
      # This is what replaces pyglet.app.run() 
      # but is required for the GUI to not freeze 
      # 
      event = self.dispatch_events() 

if __name__ == '__main__': 
    x = main(demo=True) 
    x.run() 

ベアを念頭に置いて、私のnVidiaの1070年に、私は気にしないで、このコードのうち、およそ35fpsを得ることができました吹く。しかし、それは1000オブジェクト *両側、与えるか、または取る。

self.batch.add(int(len(points)/2), pyglet.gl.GL_TRIANGLES, self.group, ('v2i/stream', points), ('c3B', colors)) 

とあなたのドローループで、あなたがやる:

self.batch.draw() 

代わりの各粒子オブジェクトのParticle.draw()を呼び出す

私は何を変更したことは、本質的にこれです。
これは、オブジェクトによってオブジェクトをどのようにレンダリングするかをグラフィックスカードに伝えるのではなく、すべてのオブジェクトを1つの巨大なバッチでグラフィックスカードに送るということです。

@thokraが指摘したように、あなたのコードはGPU集約型よりCPU集約型です。
うまくいけば、これで修正されるか、いくつかの参考になります。

このコードのほとんどは、私はしばらく前に私の良き友人で行ったLANプロジェクトから取っている:私は主に、すべてのコードを持っていなかったので

メインループ。私はあなたの問題を自分のコードに適用し、ちょっと微調整して "解決"しました。また、必要に応じて、そのgithubプロジェクトのアイデアを盗んで助けてくれることを願っています。明けましておめでとうございます!

+0

ああ、粒子の位置を更新する必要がある場合は、 'self.particles [index] .vertices'の各座標を変更するだけです。そこで更新すると、その位置はリアルタイムで更新されます。 – Torxed

+1

それは素晴らしいです!私はOpenGLをもっと深く理解する必要があります。ありがとう、幸せな新年! –

関連する問題