[Blender Python] Définissez un minuteur d'événements pour actualiser l'écran 60 fois par seconde

Blender met essentiellement à jour l'écran en fonction de l'entrée, mais il y a des moments où vous voulez que l'écran soit mis à jour automatiquement sans rien saisir. Je pense que oui. Dans un tel cas, utilisez le minuteur d'événements.

C'est difficile à comprendre simplement en mettant à jour l'écran, j'ai donc déplacé l'image au hasard.

échantillon

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()

Copiez et collez dans l'éditeur de texte de Blender.

Cette fois également, le fichier image l'utilise. Si vous ne disposez pas d'une image appropriée, veuillez l'utiliser. blender_rogo.png

Pour ʻimage_file_path` en haut, écrivez le chemin réel du fichier.

Résultat d'exécution

Tout d'abord, un bouton apparaîtra dans le panneau Propriétés de la vue 3D, alors appuyez dessus. 2016-05-04_19h51_33.png

Alors ça devient comme ça. 2016-05-04_19h55_01.png Le nombre d'images comptées s'affiche. Il affiche également FPS.

Vous pouvez augmenter ou diminuer le nombre d'images affichées à l'aide des touches haut et bas du clavier. Veuillez l'utiliser comme une simple référence.

La description

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

Le minuteur d'événement est réglé. Comme il semble être spécifié en secondes, définissez 1 seconde divisée par 60. Il semble qu'ils enverront des événements à cet intervalle.

Le reste est presque le même que la dernière fois.

finalement

J'ai essayé d'en faire une référence, mais qu'en est-il? Dans mon environnement, j'ai pu produire de manière stable 60 FPS jusqu'à environ 2600.

Ce pourrait être une bonne idée de l'utiliser pour créer quelque chose comme un jeu. Par ailleurs, le son peut être utilisé à partir de ʻaud`.

Recommended Posts

[Blender Python] Définissez un minuteur d'événements pour actualiser l'écran 60 fois par seconde
[Python] J'ai essayé de résumer le type collectif (ensemble) d'une manière facile à comprendre.
Un article résumant les pièges accro au python
Comment connaître le répertoire actuel en Python dans Blender
La première étape pour obtenir Blender disponible à partir de Python
[Blender] Comment définir dynamiquement les sélections EnumProperty
[Introduction à Udemy Python3 + Application] 30. Comment utiliser l'ensemble
Comment gratter en quelques secondes avec le sélénium de Python