Blender+Python=Happyなページを目標に日々精進のページ。


「はじめてのBlender」にもbl2unitxt3d.pyが収録されてるのを長らくこちらに記載していませんでした。
blender.jpの管理人でもある山崎 聡さん(yamyamさん)が書いた、「はじめてのBlender」は絶賛発売中(増刷されてます)
工学社のページ

bl2unitxt3d.py


blenderのテキストオブジェクトって表示・レンダリングは日本語なんかも表示できるのに、ASCII以外の文字を編集しようとするとエラーかその文字が消えちゃうかめちゃくちゃになってしまう。Blender上で編集は無理。

だけど、毎回外部ファイルを開きにいく、そのファイルの文字コードをいちいちUTF-8かどうか判別しとかなきゃいけない、で、そのファイルを編集するのは外部アプリケーション。

タダでさえ面倒くさいのにテキスト修正のたびに操作を毎回blenderから他アプリに移らなきゃならない。

テキストオブジェクトに入力されたUTF-8の文字列を引っぱって来れないか?

以上のようなことが作ったきっかけです。

※まだちょっとおかしな部分がいくつかあります…。

他機種(OS)、他言語でのテストをしてください


他の機種(OS)、Linuxやマックを使っていて、中国語やその他のマルチバイト・ワイドキャラクタな言語も使ってBlenderで制作活動にいそしんでいるあなた、このスクリプトをテストしてくださいませんか?

bl2unitxt3d_Vine Vine Linux 4.0で動作確認が出来ましたので、導入手順を。
bl2unitxt3d_tour1 実際に使うとなるとこんな感じ(工事中)。

lab1092のブログにコメントとして書いていただくとありがたいです。
できればその際
・OS
・Blenderのバージョン
・Pythonのバージョン
を書いていただけるとありがたいです

動作実績

使ってみて、「動いた」との報告が現在6件。ありがとうございます。引き続き報告してくださる方募集中!!

[0.09]
・Seikenさん(XP/2.43/2.4)
・Padosさん(2k/2.42a/2.4.3)

[0.09b]
・Muraさん(多分XP/2.46)
・720さん@2ch(?????) - Blender part19
・Benkeiさん(多分XP/2.46)
・864さん - Blender part20
日本語が使える bl2unitxt3d.py というスクリプトが公開されています。
詳しいことは、Blender bl2unitxt3d.py で検索を。
ちょっと試してみました。
ttp://blender2ch.hp.infoseek.co.jp/cgi-bin/bbs39v23/bbsdata/122-0.gif


インストールとか


とりあえず以下のリンクからダウンロードして、後はあなたの直感とドキュメントをもとに設定してください。

Ver0.09b
Pythonスクリプトソース
http://www.rock.sannet.ne.jp/lab1092/data/bl2unitx...

Ver0.01
PDFドキュメント
http://www.rock.sannet.ne.jp/lab1092/data/bl2unitx...
ZIP圧縮形式アーカイブ
http://www.rock.sannet.ne.jp/lab1092/data/bl2unitx...

問題点


・導入が面倒
・中途半端なまま放置。オブジェクト名を取ってきていない。
・やはりもうすこし分かりやすいマニュアル、手順書が必要?

関連


addJPKana.pyIMEが無くても負けません :-)

ソースファイル


以下ソースファイル。(これが最新という保証はありません)


#!BPY
# coding: utf-8
"""
Name: 'Change text object with UTF-8'
Blender: 240
Group: 'Object'
Tooltip: 'Change or create text with Tkinter'
"""

__author__ = "Manda"
__url__ = ("Author's homepage, http://www.rock.sannet.ne.jp/lab1092/")
__version__ = "0.09b"
__bpydoc__ = """\
This script create/change a Text object .
You can edit that string easier than before you did.
- How to  use -  select one text object or select nothing , and run this.
(This script requires python 2.4 & Tkinter)
"""


# --------------------------------------------------------------------------

import sys
import os
import Blender 
from Blender import Curve, Object, Scene, Text3d , Text
import Tkinter as Tk
import tkMessageBox as M
import tkFileDialog as D
import ScrolledText as S

# Const ------------------------------------------------------

# Module name , Version...
MODULENAME = 'bl2unitxt3d.py'
VERSION = '0.09b'
VERSIONSTRING = MODULENAME +' Ver.'+ VERSION
HELPTITLE = MODULENAME + '(HELP)'


# Help Message
HELPMESSAGE = """\
[bl2unitxt3d.py] for Windows/PC-UNIX/(MacOS X)
This BPy script is an input helper for text object.
It get the text from Text3D object, and put it into Tk-textbox(edit area).
You can edit those string. Also you can use IME to input
asian language such as Japanese(If Tk supported it).

It depends on Blender & Python Version;
  Blender 2.40 or later
  Python 2.4 or later 
and UTF8 support (On PC-UNIX,you'll need GNOME or KDE desktop on X11)

Happy blending!!
    - 2007.04 manda -
"""
USAGE = """\
[Usage]
Change the text (Selected Text3d object,You can use Unicode text.) 
1.Select a Text3d object.
  (When select nothing,it create text object)
2.Run this script :-)
3.Input/Edit the textbox.
4.select "Apply changes/create text"
--
(Don't forget to load the font... )
"""

CAUTION = """\
-----
[CAUTION] : Default encoding setting is not 'utf-8'
If you don't set this yet,write follow 2 lines;
1: import sys
2: sys.setdefaultencoding("utf-8")
and save "sitecustomize.py"
( C:/Python24/Lib/site-packages/
  or /usr/lib/Python2.4/Lib/site-packages/ )
-----
"""

NOTICE = """\
Create/Apply the text, You have to select correct font.
( ex. C:/Windows/Fonts/arialuni.ttc
      C:/Windows/Fonts/meiryo.ttc
      C:/Windows/Fonts/meiryo.ttc
      C:/WINNT/Fonts/msgothic.ttc)
      /usr/X11R6/lib/X11/fonts/sazanami-gothic.ttf )
"""

TXTWIDTH = 60
TXTHEIGHT = 20

DEFAULTOBJNAME = 'Text'
DEFAULTTXTNAME = 'myText'

## Class  ------------------------------------------------ 


###
# Logging buffer


class Logbuf:
    buf = []

    def init(self):
        self.buf = []

    def append(self,s):
        self.buf.append(s)

    def getlog(self):
        wbuf=u""
        for line in self.buf:
            wbuf = wbuf + line + "\n"
        return(wbuf)

    def __init__(self):
        self.init()



###
# Textinfo : Text infomation

class Textinfo:

    def init(self):
        self.text = u""
        self.pos = None
        self.objname = None
        self.crvname = None
        self.mode = None
        self.stat = None
        self.putlog = None

    def gettext(self):
        return(self.text)

    def settext(self,intext):
        self.text = intext

    def setinfo(self,intext,inobjname,incrvname):
        self.text = intext
        self.objname = inobjname
        self.crvname = incrvname

    def getreport(self):
	buf=Logbuf()
        buf.append("[Report infomation]: -%s-" % self.objname)
        buf.append("  Object name : %s" %  self.objname)
        buf.append("  Curve name  : %s" %  self.crvname)

	if self.pos != None:
            x = self.pos[0]
            y = self.pos[1]
            z = self.pos[2]
            buf.append("  Location    : (x,y,z) = (" 
                       + str(x) + ","  + str(y) +"," + str(z) + ")")
        else:
            buf.append("  Location    : (x,y,z) = None") 

        outheader = "---[Text begin]---"
        outtext=self.text
        outfooter = "---[Text end]---"
        try:
            testtext=self.text.encode(sys.stdout.encoding)
        except:
            outheader = "---[Convert error?]---"
            outtext = "UnicodeDecodeError\n"
            outtext += ("Console encoding is [%s].\n" % sys.stdout.encoding)
            outtext += "Is it right?\n"
            outtext += "If you  specified non-support character, never mind!!\n"
            outtext += "(Load correct font , you may see the Texd3D Object that you want.)"
            outfooter = "---[To console output]---"

        buf.append(outheader)
        if self.text: buf.append(outtext)
        buf.append(outfooter)

        buf.append("[Report end]: -%s-" % self.objname)
        return(buf.getlog())


    def __init__(self):
        self.init()

###
# App : Tk - window


class App(Tk.Frame):
    name = ""
    text = ""
    stat = None
    mode = 0

    def init(self):
        self.master.title("Text3d object")
        self.cb1 = Tk.IntVar()
        self.lt1 = Tk.StringVar()
        self.lt2 = Tk.StringVar()
        self.lt3 = Tk.StringVar()
        self.lt1.set("mystring1")
        self.lt2.set("mystring2")
        self.lt3.set(NOTICE)
        self.cb1.set(0)

        ### Menu
        menu_bar = Tk.Menu(self, tearoff=0)
        # File
        menu_file = Tk.Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label="File(F)", menu=menu_file,  underline=5)
        menu_file.add_command(label="New/Clear Text(N)", command=self.new_memo, underline=4, accelerator = 'Ctrl-N')
        menu_file.add_command(label="Reload Text", command=self.reload_memo)
        menu_file.add_separator()
        # menu_file.add_command(label="Open(O)", command=self.open_memo, underline=5, accelerator = 'Ctrl-O')
        # menu_file.add_command(label="Save(S)", command=self.save_memo, underline=5, accelerator = 'Ctrl-S')
        # menu_file.add_command(label="Save as...", command=self.saveas_memo)
        # menu_file.add_separator()
        menu_file.add_command(label="CreateText/Apply Changes", command=self.applytext)
        menu_file.add_separator()
        menu_file.add_command(label=u"Cancel/Exit(Q)", command=self.exit, underline=3)

        # Edit
        menu_edit = Tk.Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label='Edit(E)', menu=menu_edit, underline=3)
        menu_edit.add_command(label='Select All(A)', command=self.select_all, underline=6, accelerator = 'Ctrl-A')
        menu_edit.add_command(label='Cut(X)', command=self.cut, underline=5,
                      accelerator = os.name=='posix' and 'Ctrl-W' or 'Ctrl-X')
        menu_edit.add_command(label='Copy(C)', command=self.copy, underline=4,
                      accelerator = os.name=='posix' and 'Alt-W' or 'Ctrl-C')
        menu_edit.add_command(label='Paste(V)', command=self.paste, underline=5, 
                      accelerator = os.name=='posix' and 'Ctrl-Y' or 'Ctrl-V')

        # # Config
        # menu_config = Tk.Menu(menu_bar, tearoff=0)
        # menu_bar.add_cascade(label='Config', menu=menu_config, underline=3)
        # menu_edit.add_command(label='Select All(A)', command=self.select_all, underline=6)
        #
        # # Check buttons
        #
        # menu_check_buttons = Tk.Menu(menu_bar, tearoff=0)
        # menu_config.add_cascade(label='Logging', menu=menu_check_buttons, underline=3)
        # self.chkwin=Tk.IntVar()
        # self.chkcon=Tk.IntVar()
        # menu_check_buttons.add_command(label='UnSelect', command=self.select_all, underline=6)
        # menu_check_buttons.add_separator()
        # menu_check_buttons.add_checkbutton(label='TextWindow', variable=self.chkwin)
        # menu_check_buttons.add_checkbutton(label='Console', variable=self.chkcon)


        #Help
        menu_help = Tk.Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label='Help(H)', menu=menu_help, underline=5)
        menu_help.add_command(label='Help', command=self.print_help)
        menu_help.add_separator()
        menu_help.add_command(label='Usage', command=self.print_info)
        menu_help.add_command(label='Version', command=self.print_version)

        # short-cuts
        # self.master.bind('<Control-KeyPress-o>', self.open_memo)
        # self.master.bind('<Control-KeyPress-s>', self.save_memo)
        self.master.bind('<Control-KeyPress-q>', self.exit)
        self.master.bind('<Control-KeyPress-a>', self.select_all)

        if os.name == 'posix':
            self.master.bind('<Alt-KeyPress-w>', self.copy)

        # add menu bar
        try:
            self.master.config(menu=menu_bar)     # this required to show the menu bar
        except AttributeError:
            self.master.Tk.call(master, "config", "-menu", menu_bar)


        self.a = Tk.Label(self, textvariable=self.lt1)
        self.b = Tk.Label(self, textvariable=self.lt2)
        self.d = Tk.Text(self,width=60,height=5)
        e = Tk.Button(text="Usage")
        e.config(command=self.cmd_clicked_showinfo)
        f = Tk.Button(text="Cancel")
        f.config(command=self.cmd_clicked_cancel)
        g = Tk.Button(text="Apply")
        g.config(command=self.cmd_clicked_apply)

        self.txt = S.ScrolledText(self, font=('Helvetica', '10'),width=TXTWIDTH,height=TXTHEIGHT)

        self.a.pack(side=Tk.TOP, padx=5, pady=0)
        self.b.pack(side=Tk.TOP, padx=5, pady=0)
        self.txt.pack(side=Tk.TOP, padx=5, pady=5)
        g.pack(side=Tk.RIGHT, padx=5, pady=5)
        f.pack(side=Tk.RIGHT, padx=5, pady=5)
        e.pack(side=Tk.RIGHT, padx=5, pady=5)

        self.txt.focus_set()
        self.pack()

    def new_memo(self, event=None):
        self.file_name=None
        self.txt.delete('0.0', Tk.END)

    def reload_memo(self, event=None):
        self.file_name=None
        self.txt.delete('0.0', Tk.END)
        self.txt.insert(Tk.END, self.text)

    def open_memo(self, event=None):
        fname = D.askopenfilename(filetypes =[('all files', '*.*')])
                                   
        if fname:
            self.txt.delete('0.0', Tk.END)
            f=file(fname)
            self.txt.insert(Tk.END, f.read()) 
            f.close()
            self.file_name = fname


    def save(self, f):
        f.write(self.txt.get('0.0', Tk.END)) 
        f.close()
            
    def save_memo(self, event=None):
        if self.file_name:
            self.save(file(self.file_name, 'w'))
        else:
            self.saveas_memo()

    def saveas_memo(self):
        fname = D.asksaveasfilename(filetypes =[('all files', '*.*')])
        if fname:
            self.save(file(fname, 'w'))
            self.file_name=fname
            self.master.title(fname)


    def select_all(self, event=None):
        self.txt.tag_add(Tk.SEL, '0.0', Tk.END+'-1c')
        self.txt.mark_set(Tk.INSERT, '0.0')
        self.txt.see(Tk.INSERT)

    def cut(self, event=None):
        if self.txt.tag_ranges(Tk.SEL):
            self.copy()
            self.txt.delete(Tk.SEL_FIRST, Tk.SEL_LAST)

    def copy(self, event=None): 
        if self.txt.tag_ranges(Tk.SEL):
            text = self.txt.get(Tk.SEL_FIRST, Tk.SEL_LAST)  
            self.clipboard_clear()
            self.clipboard_append(text)

    def paste(self, event=None):
        text = self.selection_get(selection='CLIPBOARD')
        if text:
            self.txt.insert(Tk.INSERT, text)
            self.txt.tag_remove(Tk.SEL, '0.0', Tk.END) 
            self.txt.see(Tk.INSERT)

    def clearlogmode(self,event=None):
            self.logwin=0
            self.logcon=0

    def applytext(self):
        self.text = self.txt.get("0.0",Tk.END+'-1c')
        
        if self.mode == 1:
            title = "Create changes"
            apply = NOTICE
        elif self.mode == 2:
            title = "Apply changes"
            apply = "Apply changes."
        else:
            title = "Odd mode"
            apply = "Internal error.Check code...."

        M.showinfo(title,apply)
        self.stat = self.mode
        self.master.destroy()

    def print_help(self, event=None):
        M.showinfo(title=HELPTITLE,message=HELPMESSAGE)

    def print_info(self, event=None):
        M.showinfo(title='Info',message=USAGE)

    def print_version(self, event=None):
        M.showinfo(title='Version',message=VERSIONSTRING)

    def exit(self, event=None):
        M.showinfo("Cancelled","Operation is canecelled.")
        self.stat = None
        self.master.destroy()

    def cmd_clicked_showinfo(self):
        M.showinfo("Usage",USAGE)

    def cmd_clicked_cancel(self):
        M.showinfo("Cancelled","Operation is canecelled.")
        self.stat = None
        self.master.destroy()

    def cmd_clicked_apply(self):
        self.applytext()

    def __init__(self, master=None):
        Tk.Frame.__init__(self, master)
        self.pack(); self.init()

    def mainloop(self,tinf):

        if tinf.objname:
            name = tinf.objname
            self.mode = 2
        else:
            name = "*None*"
            self.mode = 1

        self.text = tinf.text
        self.stat = None
        if self.mode == 1:
            self.lt1.set("Create Text Object")
        if self.mode == 2:
            self.lt1.set("Change Text ")

        self.lt2.set("Objectname:" + name)
#        print "Objectname:" + self.name

        self.reload_memo()
        Tk.Frame.mainloop(self)


###
# Open Tk window 

def putwindow_bl(tinf):

    app = App()
    app.mainloop(tinf)
    tinf.text = app.text
    return(app.stat)

###
# Create Text3D

def objcreates():

    tinf = Textinfo()

    buf.append("No text object selected, create text object")
    rslt = putwindow_bl(tinf)
    if rslt != None:
        txt = Text3d.New(DEFAULTTXTNAME)
        cur = Scene.GetCurrent()
        obj = Object.New(DEFAULTOBJNAME)
        obj.link(txt)
        cur.link(obj)
        obj.makeDisplayList()
        tinf.objname=obj.getName()
        tinf.crvname=txt.getName()
        txt.setText(tinf.text)

        tinf.pos = list(Blender.Window.GetCursorPos())

        print tinf.pos

        obj.setLocation(tinf.pos)
        obj.makeDisplayList()
        obj.select(1)
        print tinf.getreport()
        print "!!New Object was created."
    else:
        print "Operation was canceled."


###
# Change text for Text3D

def objchangetext(obj):

    tinf = Textinfo()

    mode = 2;
    tinf.objname = obj.getName()
    d = obj.getData()
    tinf.location = obj.getLocation() 
    tinf.text = d.getText()
    buf.append(tinf.getreport())
    # call Tk window
    rslt = putwindow_bl(tinf)
    if rslt != None:
        d.setText(tinf.text)
        obj.makeDisplayList()
        print tinf.getreport()
    else:
        buf.append("Operation was canceled.")


def reportthisenv():
    return('Gotcha!!')

###
# Main 

if __name__ == "__main__":


    mode = None

    #logbuffer start
    buf = Logbuf()
    buf.append("[bl2unitxt3d]Start.")

    # Encoding must be 'UTF-8'
    if sys.getdefaultencoding() != 'utf-8':
        # print caution to console directory :-<
        print CAUTION

    # you must edit mode to viewmode
    editmode = Blender.Window.EditMode()
    if editmode:
        Blender.Draw.PupMenu("[editmode] you must change to viewmode")
    else:
        objects = Blender.Object.GetSelected()
        hastextobj = len(objects)

        if hastextobj == 0:
            # create the text
            objcreates()
        elif hastextobj == 1:
            # change the text
            obj = objects[0]
            if obj.getType() == 'Text':
                objchangetext(obj)
            else:
                Blender.Draw.PupMenu("One object selected, but this is not text object.")
        else:
            Blender.Draw.PupMenu("Please select *one* Text3D object.")
            #print "-error-"

#
    Blender.Redraw()
#
# To apply text object in blender window;
# Select the text object in 3d window,
# Push [Tab] key one or two time.
# And Choose a "correct" font at [font panel]
#
# end.

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

メニューバーA

Next comes OSAKA!!!

Blender party @OSAKA,Japan 2009
bpoj2009

Blender party @Tokyo,Japan 2009
bptj2009

Eventsupport blog(Della Nagoya)
bpnj2008 - blog

Nagoya
NAGOYA2008本編

どなたでも編集できます