[Blender Python] Stellen Sie einen Ereignis-Timer ein, um den Bildschirm 60 Mal pro Sekunde zu aktualisieren

Blender aktualisiert den Bildschirm grundsätzlich entsprechend der Eingabe, aber manchmal möchten Sie, dass der Bildschirm automatisch aktualisiert wird, ohne etwas einzugeben. Ich denke, dort ist. Verwenden Sie in diesem Fall den Ereignis-Timer.

Es ist schwer zu verstehen, wenn man nur den Bildschirm aktualisiert, also habe ich das Bild zufällig verschoben.

Stichprobe

gl_benchmark.py


# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# Blender2.77a

import time
import random

import bpy
import bgl
import blf


image_file_path = "C:/Works/blender_rogo.png "

class GL_Texture():
    def __init__(self, file_path):
        self.image = None
        self.width = 0
        self.height = 0
        
        self.load_image(file_path)
    
    def load_image(self, file_path):
        try:
            self.image = bpy.data.images.load(file_path)
        except Exception as e:
            print(e)
        
        if self.image:
            self.width, self.height = self.image.size
            self.image.gl_load(0, bgl.GL_NEAREST, bgl.GL_NEAREST)
    
    def remove(self):
        if self.image:
            try:
                self.image.user_clear()
                self.image.gl_free()
                self.image.buffers_free()
                bpy.data.images.remove(self.image)
            except Exception as e:
                print(e)
    
    def bind(self):
        if self.image.bindcode[0]:
            bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.image.bindcode[0])
        else:
            self.image.gl_load(0, bgl.GL_NEAREST, bgl.GL_NEAREST)
            print("reload gl texture")


class Sprite():
    def __init__(self, x, y, move_x, move_y):
        self.x = x
        self.y = y
        self.move_x = move_x
        self.move_y = move_y


class GL_BenchMark():
    def __init__(self):
        self.texture = GL_Texture(image_file_path)
        
        self.fps = 0
        self.fps_count = 0
        self.fps_time = time.time()
        self.fps_one_second = self.fps_time
        
        self.view3d_width = 100.0
        self.view3d_height = 100.0
        
        self.sprite_list = []
        self.sprite_add(100)
    
    def draw(self, context):
        for region in context.area.regions:
            if region.type == "WINDOW":
                self.view3d_width = region.width
                self.view3d_height = region.height
            
        # calc
        self.fps_time = time.time()
        self.fps_count += 1
        if (self.fps_time-self.fps_one_second) >= 1.0:
            self.fps = self.fps_count
            self.fps_count = 0
            self.fps_one_second = self.fps_time
        
        for sp in self.sprite_list:
            sp.x += sp.move_x
            if sp.x < 0.0 or self.view3d_width < sp.x:
                sp.move_x *= -1
                sp.x += sp.move_x
        
            sp.y += sp.move_y
            if sp.y < 0.0 or self.view3d_height < sp.y:
                sp.move_y *= -1
                sp.y += sp.move_y
        
        # draw
        bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
        bgl.glEnable(bgl.GL_BLEND)
        bgl.glEnable(bgl.GL_TEXTURE_2D)
        
        self.texture.bind()
        for sp in self.sprite_list:
            w = self.texture.width
            h = self.texture.height
            bgl.glBegin(bgl.GL_QUADS)
            bgl.glTexCoord2f(0.0, 0.0)
            bgl.glVertex2f(sp.x, sp.y)
            bgl.glTexCoord2f(1.0, 0.0)
            bgl.glVertex2f(sp.x+w, sp.y)
            bgl.glTexCoord2f(1.0, 1.0)
            bgl.glVertex2f(sp.x+w, sp.y+h)
            bgl.glTexCoord2f(0.0, 1.0)
            bgl.glVertex2f(sp.x, sp.y+h)
            bgl.glEnd()
        
        bgl.glDisable(bgl.GL_TEXTURE_2D)
        bgl.glDisable(bgl.GL_BLEND)
        
        # text draw
        font_id = 0
        blf.enable(font_id, blf.SHADOW)
        blf.shadow(font_id, 5, 0.0, 0.0, 0.0, 1.0)
        
        blf.position(font_id, 5, 5, 0)
        blf.size(font_id, 25, 72)
        blf.draw(font_id, "FPS:{}".format(self.fps))
        
        blf.position(font_id, 5, 30, 0)
        blf.size(font_id, 25, 72)
        blf.draw(font_id, "count:{}".format(len(self.sprite_list)))
        
        blf.disable(font_id, blf.SHADOW)
    
    def remove(self):
        self.texture.remove()
    
    def sprite_add(self, count):
        for i in range(count):
            x = random.uniform(1.0, self.view3d_width-1.0)
            y = random.uniform(1.0, self.view3d_height-1.0)
            vx = random.uniform(-2.0, 2.0)
            vy = random.uniform(-2.0, 2.0)
            
            self.sprite_list.append(Sprite(x, y, vx, vy))
    
    def sprite_remove(self, count):
        if len(self.sprite_list) > count:
            for i in range(count):
                self.sprite_list.pop()
    
    def event(self, context, event):
        if event.type == 'UP_ARROW' and event.value == 'PRESS':
            self.sprite_add(100)
            return {'RUNNING_MODAL'}
            
        if event.type == 'DOWN_ARROW' and event.value == 'PRESS':
            self.sprite_remove(100)
            return {'RUNNING_MODAL'}
        
        return {'PASS_THROUGH'}


class GL_BenchMark_Operator(bpy.types.Operator):
    bl_idname = "view3d.gl_bechmark_operator"
    bl_label = "View3D OpenGL Bechmark"
    
    _handle_draw = None
    is_enabled = False
    _timer = None
    _gl_benchmark = None
    
    @staticmethod
    def draw_callback_px(self, context):
        GL_BenchMark_Operator._gl_benchmark.draw(context)
    
    @staticmethod
    def handle_add(self, context):
        GL_BenchMark_Operator._handle_draw = bpy.types.SpaceView3D.draw_handler_add(
                self.draw_callback_px, (self, context), 'WINDOW', 'POST_PIXEL')
        GL_BenchMark_Operator._timer = context.window_manager.event_timer_add(
                1.0/60.0, context.window)
    
    @staticmethod
    def handle_remove(context):
        if GL_BenchMark_Operator._handle_draw is not None:
            context.window_manager.event_timer_remove(GL_BenchMark_Operator._timer)
            bpy.types.SpaceView3D.draw_handler_remove(GL_BenchMark_Operator._handle_draw, 'WINDOW')
            GL_BenchMark_Operator._timer = None
            GL_BenchMark_Operator._handle_draw = None
            GL_BenchMark_Operator.is_enabled = False
    
    @classmethod
    def poll(cls, context):
        return context.area.type == 'VIEW_3D'
    
    def modal(self, context, event):
        if context.area:
            context.area.tag_redraw()
        
        if GL_BenchMark_Operator.is_enabled == False:
            return {'CANCELLED'}
        
        if event.type == 'TIMER':
            return {'PASS_THROUGH'}
        
        return GL_BenchMark_Operator._gl_benchmark.event(context, event)
    
    def invoke(self, context, event):
        if context.area.type == 'VIEW_3D':
            if GL_BenchMark_Operator.is_enabled:
                self.cancel(context)
                return {'FINISHED'}
            else:
                GL_BenchMark_Operator._gl_benchmark = GL_BenchMark()
                GL_BenchMark_Operator.handle_add(self, context)
                GL_BenchMark_Operator.is_enabled = True
                
                context.area.tag_redraw()
                context.window_manager.modal_handler_add(self)
                return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}
    
    def cancel(self, context):
        GL_BenchMark_Operator.handle_remove(context)
        
        if GL_BenchMark_Operator._gl_benchmark is not None:
            GL_BenchMark_Operator._gl_benchmark.remove()
            GL_BenchMark_Operator._gl_benchmark = None


class GL_Benchmark_panel(bpy.types.Panel):
    bl_label = "GL Benchmark"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    
    def draw(self, context):
        layout = self.layout
        if GL_BenchMark_Operator.is_enabled:
            layout.operator("view3d.gl_bechmark_operator", "Stop", icon="PAUSE")
        else:
            layout.operator("view3d.gl_bechmark_operator", "Start", icon="PLAY")


def register():
    bpy.utils.register_class(GL_BenchMark_Operator)
    bpy.utils.register_class(GL_Benchmark_panel)

def unregister():
    bpy.utils.unregister_class(GL_Benchmark_panel)
    bpy.utils.unregister_class(GL_BenchMark_Operator)

if __name__ == "__main__":
    register()

Kopieren Sie es und fügen Sie es in den Texteditor von Blender ein.

Auch diesmal wird dies von der Bilddatei verwendet. Wenn Sie kein passendes Bild zur Hand haben, verwenden Sie es bitte. blender_rogo.png

Schreiben Sie für image_file_path oben den tatsächlichen Dateipfad.

Ausführungsergebnis

Zunächst wird im Eigenschaftenfenster der 3D-Ansicht eine Schaltfläche angezeigt. Drücken Sie sie also. 2016-05-04_19h51_33.png

Dann wird es so. 2016-05-04_19h55_01.png Die Anzahl der Bilder, die zählen, wird angezeigt. Es zeigt auch FPS an.

Sie können die Anzahl der angezeigten Bilder mit den Auf- und Ab-Tasten auf der Tastatur erhöhen oder verringern. Bitte verwenden Sie es als einfache Benchmark.

Erläuterung

    GL_BenchMark_Operator._timer = context.window_manager.event_timer_add(
            1.0/60.0, context.window)

Der Ereignis-Timer ist eingestellt. Da es in Sekunden angegeben zu sein scheint, setzen Sie 1 Sekunde geteilt durch 60. Es scheint, dass sie Ereignisse in diesem Intervall senden werden.

Der Rest ist fast der gleiche wie beim letzten Mal.

Schließlich

Ich habe versucht, es wie einen Benchmark zu machen, aber wie wäre es damit? In meiner Umgebung konnte ich stabil 60 FPS bis zu etwa 2600 ausgeben.

Es könnte eine gute Idee sein, dies zu verwenden, um so etwas wie ein Spiel zu erstellen. Übrigens kann Sound von "aud" verwendet werden.

Recommended Posts

[Blender Python] Stellen Sie einen Ereignis-Timer ein, um den Bildschirm 60 Mal pro Sekunde zu aktualisieren
[Python] Ich habe versucht, den kollektiven Typ (Satz) auf leicht verständliche Weise zusammenzufassen.
Ein Artikel, der die Fallstricke von Python zusammenfasst
Wie Sie das aktuelle Verzeichnis in Python in Blender kennen
Der erste Schritt, um Blender von Python verfügbar zu machen
[Blender] So legen Sie die Auswahlelemente von EnumProperty dynamisch fest
[Einführung in die Udemy Python3 + -Anwendung] 30. Verwendung des Sets
Wie man mit Pythons Selen in Sekundenschnelle kratzt