Last active
October 22, 2022 13:06
-
-
Save ZuishoMyelin/b929700837d1a7798147cdbd4ed8e1d4 to your computer and use it in GitHub Desktop.
※現状テクスチャの埋め込みは出来ますがdefファイルは反映されません プリファレンス->アドオンからpythonファイルを登録、blendファイル保存後、ファイル->エクスポートから実行
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
import os | |
import shutil | |
import glob | |
# A_N_DISCARDシェーダーのハッシュ値 | |
A_N_DISCARD_SHADER_ID = '' | |
bl_info = { | |
"name": "Blend2Bakin", | |
"author": "ZUISHO Myelin", | |
"version": (1, 0), | |
"blender": (3, 2, 2), | |
"location": "File > Export", | |
"description": "export to bakin", | |
"warning": "", | |
"support": "TESTING", | |
"wiki_url": "", | |
"tracker_url": "", | |
"category": "" | |
} | |
class SAMPLE_OT_Blend2Bakin(bpy.types.Operator): | |
bl_idname = "file.blend2bakin" | |
bl_label = "BlendToBakin" | |
bl_description = "bakin向けのモデルをエクスポートします" | |
bl_options = {'REGISTER', 'UNDO'} | |
# @brief GUIでメッセージを表示する | |
# @param [in] message メッセージ本文 | |
# @param [in] tilte メッセージボックスのタイトル | |
# @param [in] icon 使用するアイコン | |
def ShowMessageBox(self, message = "", title = "Message Box", icon = 'INFO'): | |
def draw(self, context): | |
self.layout.label(text=message) | |
bpy.context.window_manager.popup_menu(draw, title = title, icon = icon) | |
# @brief RPGBakinのマテリアル設定ファイルを生成する | |
# @param [in] filepath 保存先のパス | |
def MakeBakinDefFile(self, filepath, filename): | |
with open(filepath + filename, mode='w') as f: | |
# 全てのメッシュオブジェクトを取得 | |
for mesh_ob in [ob for ob in bpy.data.objects if ob.type == "MESH"]: | |
# 全てのマテリアルを取得 | |
for mat_slot in set(mesh_ob.material_slots): | |
if not mat_slot.material: | |
continue | |
if not mat_slot.material.node_tree: | |
continue | |
# 全てのテクスチャを取得 | |
tex_nodes = [n for n in mat_slot.material.node_tree.nodes if n.type == "TEX_IMAGE"] | |
# 共通 | |
f.write("mtl " + str(mat_slot.material.name) + "\n") | |
# map_notex | |
if len(tex_nodes) == 0: | |
f.write("shader map_notex\n") | |
# a_n_discard | |
else: | |
f.write("shader a_n_discard " + A_N_DISCARD_SHADER_ID + "\n") | |
# マテリアルをPrincipled BSDFに差し替え(※fbxにテクスチャを埋め込むため) | |
mat = bpy.data.materials.new(str(mat_slot.material.name)) | |
mat.use_nodes = True | |
bsdf = mat.node_tree.nodes["Principled BSDF"] | |
# メインテクスチャ | |
texImage1 = mat.node_tree.nodes.new('ShaderNodeTexImage') | |
texImage1.image = tex_nodes[0].image | |
texImage1.image.filepath = filepath + "texture/" + str(tex_nodes[0].image.name) + ".png" | |
texImage1.image.file_format = 'PNG' | |
texImage1.image.save() | |
mat.node_tree.links.new(bsdf.inputs['Base Color'], texImage1.outputs['Color']) | |
# ノーマルマップ | |
if len(tex_nodes) >= 3: | |
texImage2 = mat.node_tree.nodes.new('ShaderNodeTexImage') | |
texImage2.image = tex_nodes[2].image | |
texImage2.image.filepath = filepath + "texture/" + str(tex_nodes[2].image.name) + ".png" | |
texImage2.image.file_format = 'PNG' | |
texImage2.image.save() | |
mat.node_tree.links.new(bsdf.inputs['Normal'], texImage2.outputs['Color']) | |
mat_slot.material = mat | |
# 共通 | |
f.write("emissiveBlink false\n") | |
f.write("emissiveBlinkSpeed 0.000000\n") | |
f.write("emissiveLinkBuildingLight false\n") | |
f.write("uscrollanim false\n") | |
f.write("vscrollanim false\n") | |
f.write("scrollanimspeed 0.000000 0.000000\n") | |
f.write("uvstepanim false\n") | |
f.write("uvstepanimparam 1 1 0 1.000000\n") | |
f.write("sortindex 0\n") | |
f.write("castshadow true\n") | |
f.write("cull back\n") | |
f.write("uvofs 0.000000 0.000000\n") | |
f.write("uvscl 1.000000 1.000000\n") | |
# map_notex | |
if len(tex_nodes) == 0: | |
f.write("color 1.000000 1.000000 1.000000\n") | |
f.write("roughness 0.900000\n") | |
f.write("metallic 0.000000\n") | |
f.write("specular 0.000000\n") | |
continue | |
# a_n_discard | |
else: | |
f.write("AMap " + str(tex_nodes[0].image.name) + ".png\n") | |
if len(tex_nodes) >= 3: | |
f.write("NMap " + str(tex_nodes[2].image.name) + ".png\n") | |
f.write("color 1.000000 1.000000 1.000000\n") | |
f.write("normalscl 1.000000\n") | |
# 共通 | |
f.write("roughness 0.900000\n") | |
f.write("metallic 0.000000\n") | |
f.write("specular 0.000000\n") | |
f.write("discard_threshold 0.900000\n") | |
f.write("\n") | |
# テキストファイルから文字列を読み込む | |
with open(filepath + filename, 'r', encoding='utf-8') as a_file: | |
txt = a_file.read() | |
# 読み込んだ文字列のCR(\r)を削除する。 | |
txt = txt.replace('\r', '') | |
# ファイルをバイナリモードで開く | |
with open(filepath + filename, 'wb') as a_file: | |
# 文字列をバイト列にして保存する | |
a_file.write(txt.encode('utf-8')) | |
def execute(self, context): | |
# 全てのオブジェクトを選択する | |
bpy.ops.object.select_all(action='SELECT') | |
# blendファイルのパス | |
blend_dirpath = os.path.dirname(bpy.data.filepath).replace("\\", "/") | |
# blendファイルのファイル名 | |
blend_filename = os.path.basename(bpy.data.filepath)[:-6] | |
# 保存先ディレクトリのパス | |
export_dirpath = blend_dirpath + "/" + blend_filename | |
# 未保存の場合は処理を終了する | |
if not blend_dirpath: | |
self.ShowMessageBox("please save project file") | |
return | |
# 保存先ディレクトリの作成 | |
try: | |
os.mkdir(export_dirpath) | |
except FileNotFoundError as e: | |
print(e) | |
self.ShowMessageBox(e) | |
return | |
# テクスチャの保存先ディレクトリの作成 | |
try: | |
os.mkdir(export_dirpath + "/texture") | |
except FileNotFoundError as e: | |
print(e) | |
self.ShowMessageBox(e) | |
return | |
# RPGBakinの設定ファイルを出力 | |
try: | |
self.MakeBakinDefFile(export_dirpath + "/", blend_filename + ".def") | |
except FileNotFoundError as e: | |
print(e) | |
self.ShowMessageBox(e) | |
return | |
# テクスチャをアンパック | |
# bpy.ops.file.unpack_all(method='WRITE_LOCAL') | |
# shutil.move(blend_dirpath + "/textures", export_dirpath + "/texture") # bakinとの紐づけ用 | |
# for i in glob.glob(export_dirpath + "/texture/*"): | |
# shutil.copy(str(i), export_dirpath) # fbxとの紐づけ用 | |
# fbxエクスポート | |
bpy.ops.export_scene.fbx( | |
filepath= export_dirpath + "/" + blend_filename + ".fbx", | |
check_existing=True, | |
filter_glob="*.fbx", | |
use_selection=True, | |
use_active_collection=False, | |
global_scale=1.00, | |
apply_unit_scale=True, | |
apply_scale_options='FBX_SCALE_NONE', | |
bake_space_transform=False, | |
object_types={'EMPTY', 'ARMATURE', 'MESH'}, | |
use_mesh_modifiers=False, | |
use_mesh_modifiers_render=True, | |
mesh_smooth_type='OFF', | |
use_subsurf=False, | |
use_mesh_edges=False, | |
use_tspace=True, | |
use_custom_props=False, | |
add_leaf_bones=True, | |
primary_bone_axis='Y', | |
secondary_bone_axis='X', | |
use_armature_deform_only=False, | |
armature_nodetype='NULL', | |
bake_anim=True, | |
bake_anim_use_all_bones=True, | |
bake_anim_use_nla_strips=True, | |
bake_anim_use_all_actions=True, | |
bake_anim_force_startend_keying=True, | |
bake_anim_step=1.0, | |
bake_anim_simplify_factor=1.0, | |
path_mode='RELATIVE', | |
embed_textures=False, | |
batch_mode='OFF', | |
use_batch_own_dir=True, | |
use_metadata=True, | |
axis_forward='-Z', | |
axis_up='Y' | |
) | |
return {'FINISHED'} | |
def menu_fn(self, context): | |
self.layout.separator() | |
self.layout.operator(SAMPLE_OT_Blend2Bakin.bl_idname) | |
classes = [ | |
SAMPLE_OT_Blend2Bakin, | |
] | |
def register(): | |
for c in classes: | |
bpy.utils.register_class(c) | |
bpy.types.TOPBAR_MT_file_export.append(menu_fn) | |
def unregister(): | |
bpy.types.TOPBAR_MT_file_export.remove(menu_fn) | |
for c in classes: | |
bpy.utils.unregister_class(c) | |
if __name__ == "__main__": | |
register() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment