[Blender Python] Zeigen Sie Bilder in 3D-Ansicht mit OpenGL (bgl) an.

zunaechst

Wenn Sie ein Add-On für Blender schreiben, möchten Sie hier häufig Bilder verwenden. Ich denke, dort ist. Wenn Sie OpenGL (bgl) von Blender verwenden, können Sie es anzeigen. Probieren Sie es also aus.

Es gibt zwei Möglichkeiten, das Bild zu lesen, also werde ich jede schreiben.

Bei Verwendung von bpy.data.images.load ()

Stichprobe

gl_texture_test.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 bpy
import bgl


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 GL_Texture_test_Operator(bpy.types.Operator):
    bl_idname = "view3d.gl_texture_test_operator"
    bl_label = "View3D GL_Texture draw test"
    
    _handle_draw = None
    is_enabled = False
    _my_texture = None
    
    @staticmethod
    def draw_callback_px(self, context):
        bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
        bgl.glEnable(bgl.GL_BLEND)
        bgl.glEnable(bgl.GL_TEXTURE_2D)
        
        tex = GL_Texture_test_Operator._my_texture
        w = tex.width
        h =tex.height
        tex.bind()
        bgl.glBegin(bgl.GL_QUADS)
        bgl.glTexCoord2f(0.0, 0.0)
        bgl.glVertex2f(0.0, 0.0)
        bgl.glTexCoord2f(1.0, 0.0)
        bgl.glVertex2f(0.0+w, 0.0)
        bgl.glTexCoord2f(1.0, 1.0)
        bgl.glVertex2f(0.0+w, 0.0+h)
        bgl.glTexCoord2f(0.0, 1.0)
        bgl.glVertex2f(0.0, 0.0+h)
        bgl.glEnd()
        
        bgl.glDisable(bgl.GL_TEXTURE_2D)
        bgl.glDisable(bgl.GL_BLEND)
    
    @staticmethod
    def handle_add(self, context):
        GL_Texture_test_Operator._handle_draw = bpy.types.SpaceView3D.draw_handler_add(
                self.draw_callback_px, (self, context), 'WINDOW', 'POST_PIXEL')
    
    @staticmethod
    def handle_remove():
        if GL_Texture_test_Operator._handle_draw is not None:
            bpy.types.SpaceView3D.draw_handler_remove(GL_Texture_test_Operator._handle_draw, 'WINDOW')
            GL_Texture_test_Operator._handle_draw = None
            GL_Texture_test_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()
        return {'PASS_THROUGH'}
    
    def invoke(self, context, event):
        if context.area.type == 'VIEW_3D':
            if GL_Texture_test_Operator.is_enabled:
                self.cancel(context)
                return {'FINISHED'}
            else:
                GL_Texture_test_Operator._my_texture = GL_Texture(image_file_path)
                GL_Texture_test_Operator.handle_add(self, context)
                GL_Texture_test_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_Texture_test_Operator.handle_remove()
        
        if GL_Texture_test_Operator._my_texture is not None:
            GL_Texture_test_Operator._my_texture.remove()
            GL_Texture_test_Operator._my_texture = None


class GL_Texture_test_panel(bpy.types.Panel):
    bl_label = "GL Texture test"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    
    def draw(self, context):
        layout = self.layout
        if GL_Texture_test_Operator.is_enabled:
            layout.operator("view3d.gl_texture_test_operator", "Stop", icon="PAUSE")
        else:
            layout.operator("view3d.gl_texture_test_operator", "Start", icon="PLAY")


def register():
    bpy.utils.register_class(GL_Texture_test_Operator)
    bpy.utils.register_class(GL_Texture_test_panel)

def unregister():
    bpy.utils.unregister_class(GL_Texture_test_panel)
    bpy.utils.unregister_class(GL_Texture_test_Operator)

if __name__ == "__main__":
    register()

Kopieren Sie es, fügen Sie es in den Texteditor von Blender ein und führen Sie es aus. Geben Sie oben für image_file_path den Pfad des tatsächlich verwendeten Bildes ein.

blender_rogo.png Ich habe das Blender-Logo entsprechend gezeichnet. Verwenden Sie diese Option, damit das Bild angezeigt wird. Wenn Sie kein passendes Bild haben, verwenden Sie es bitte.

Ausführungsergebnis

Wenn Sie es ausführen, wird zuerst eine Schaltfläche im Eigenschaftenfenster angezeigt. Drücken Sie also darauf. 2016-05-02_20h19_42.png

Dann 2016-05-02_20h24_01.png

Erläuterung

Die Pfadprüfung der zu verwendenden Bilddatei entfällt. Sie sollten es überprüfen, wenn Sie es tatsächlich verwenden.

self.image.gl_load(0, bgl.GL_NEAREST, bgl.GL_NEAREST) Ich denke, dass die Bilddaten in den Speicher von OpenGL gesendet werden. Ich denke, die beiden Argumente rechts sind die Speichermethode beim Skalieren.

self.image.bindcode[0] Die Textur-ID wird hier nach gl_load () eingegeben. Es war vorher keine Liste, aber aus irgendeinem Grund wurde sie in eine Liste geändert. Ich weiß nicht, welche Daten außer 0 enthalten sind.

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

Für diesen Teil wird der Texturspeicher einige Minuten nach seiner Ausführung automatisch freigegeben, sodass die Textur erneut geladen wird. Blender scheint den Speicher von selbst freizugeben.

Der Zeichnungsteil ist derselbe wie OpenGL.

Das Gute an dieser Methode

»Es ist sowieso einfach.

Wo ich finde, ist es nicht so gut

Beim Einlesen von Bilddaten in einen Puffer und beim Registrieren

Beispiel einer GL_Texture-Klasse

Schreiben Sie die GL_Texture-Klasse aus dem obigen Beispiel neu und führen Sie sie aus.

GL_Texturklasse


class GL_Texture():
    def __init__(self, file_path):
        self.texture_id = 0
        self.width = 0
        self.height = 0
        
        self.load_8bit_bitmap(file_path)
    
    def load_8bit_bitmap(self, file_path):
        f = None
        bitmap_data = None
        gl_buffer = None
        
        try:
            f = open(file_path, 'rb')
            file_header = f.read(14)
            info_header = f.read(40)
            self.width = struct.unpack("<i", info_header[4:8])[0]
            self.height = struct.unpack("<i", info_header[8:12])[0]
            
            palette = []
            for i in range(256):
                rgbr = f.read(4)
                palette.append(struct.unpack("BBBB", rgbr)[0:3])
            
            gl_buffer = bgl.Buffer(bgl.GL_BYTE, self.width*self.height*4)
            for i in range(self.width*self.height):
                data = f.read(1)
                index = struct.unpack("B", data)[0]
                bgr = palette[index]
                gl_buffer[i*4] = bgr[2]
                gl_buffer[i*4+1] = bgr[1]
                gl_buffer[i*4+2] = bgr[0]
                
                if index == 0:
                    gl_buffer[i*4+3] = 0
                else:
                    gl_buffer[i*4+3] = 255
            
            f.close()
        except Exception as e:
            if f is not None:
                f.close()
            print(e)
            return False
            
        # set opengl
        textures = bgl.Buffer(bgl.GL_INT, 1)
        bgl.glGenTextures(1, textures)
        self.texture_id = textures[0]
        
        bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.texture_id)
        
        bgl.glPixelStorei(bgl.GL_UNPACK_ALIGNMENT, 4)
        bgl.glTexImage2D(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA,
                self.width, self.height, 0, bgl.GL_RGBA,
                bgl.GL_UNSIGNED_BYTE, gl_buffer)
        
        bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_NEAREST)
        bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_NEAREST)
        
    def remove(self):
        if self.texture_id:
            textures = bgl.Buffer(bgl.GL_INT, 1)
            textures[0] = self.texture_id
            bgl.glBindTexture(bgl.GL_TEXTURE_2D, 0)
            bgl.glDeleteTextures(1, textures)
            self.texture_id = 0
    
    def bind(self):
        bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.texture_id)

Hinweis. Es können nur Bitmap-Dateien im 8-Bit-Format geladen werden. Index 0 ist transparent. Es scheint, dass Sie die Bitmap-Datei nicht hochladen können. Bereiten Sie sie daher bitte selbst vor.

Erläuterung

Es geht darum, eine Datei zu öffnen, in einem Puffer zu erweitern und in OpenGL zu registrieren.

Wenn Sie in bgl einen Puffer als Argument übergeben möchten, müssen Sie die Buffer-Klasse verwenden. Ich denke, das ist der Unterschied zu gewöhnlichem OpenGL.

Da der Dateiprüfungsprozess weggelassen wird, überprüfen Sie bitte verschiedene Dinge, wenn Sie ihn tatsächlich verwenden.

Das Gute an dieser Methode

Wo ich finde, ist es nicht so gut

Schließlich

Persönlich empfehle ich die Verwendung von "bpy.data.images.load ()", da dies immer einfacher ist. Es wird schnell geladen. Die Bilddatei wird auch während der Ausführung in Blender geladen. Selbst wenn Sie sie so speichern, wie sie ist, wird sie nicht gespeichert, wenn die Anzahl der Benutzer 0 beträgt, sodass Sie sich keine Sorgen machen müssen.

Recommended Posts

[Blender Python] Zeigen Sie Bilder in 3D-Ansicht mit OpenGL (bgl) an.
Zeigen Sie Bilder in OpenCV von Python mit einer externen USB-Kamera auf Ihrem MacBook an
Speichern Sie Bilder mit Python3-Anforderungen
PIL-Bilder auf Jupyter anzeigen
Verwenden Sie Python auf Raspberry Pi 3, um "Temperatur (mit A / D-Wandler)" zu erkennen!
Online-Übertragung mit Python
Hinweise zur Verwendung von MeCab aus Python
Installieren Sie Pytorch unter Blender 2.90 Python unter Windows
Generieren mehrsprachiger Textbilder mit Python
Studie über die Miete in Tokio mit Python (3-2)
Hinweise zur Installation von Python mit PyEnv
Zeigen Sie Stapelspuren mit [Python] inspect an
Hinweise zur Verwendung von rstrip mit Python.
Installieren Sie Python unter CentOS mit Pyenv
Studie über die Miete in Tokio mit Python (3-3)
Installieren Sie Python unter CentOS mit pyenv
Erkennen Sie analoge Signale mit dem A / D-Wandler mithilfe von Python auf Raspberry Pi 3!
Lassen Sie uns eine 3D-Animation nur mit Python erstellen, ohne Blender zu verwenden! [FBX SDK Python]
Teilen der Wasserkammmethode im 3D-Bild mit ImageJ
Hinweise zur Verwendung von OpenCV mit Windows 10 Python 3.8.3.
Führen Sie Python-Code unter C ++ aus (mit Boost.Python).
Erkennen Sie "Helligkeit" mit Python auf Raspberry Pi 3!
Installieren Sie die Python-Bibliothek auf Lambda mit [/ tmp]
Lassen Sie einen Servomotor mit Python auf Raspberry Pi 3 laufen
Studie über die Miete in Tokio mit Python (3-1 von 3)
[Python] Fortschrittsanzeige nach Fortschrittsbalken mit tqdm
Ermitteln Sie die Temperatur mit Python auf Raspberry Pi 3!
Anzeigen von Zugverzögerungsinformationen in der GUI mithilfe von Python