Open2
Blenderスクリプトでモデルの軽量化を自動化
Decimateをする。
def decimate(ratio):
bpy.ops.object.modifier_add(type='DECIMATE')
decim = bpy.context.object.modifiers["Decimate"]
decim.ratio = ratio
Merge By Distanceに相当するものが直接は見つからなかったが、Mesh Operatorを見ていたらbpy.ops.mesh.remove_doubles()
なるものが。説明を見るとそれっぽいので、これを使うことにした。ただし、thresholdの単位はmではなさそうなので動作させながら適当な値を地道に検証していく必要があった。
なお、Mesh Operatorを使用する前には以下を実行して、デフォルトのObject ModeからEdit Modeへと変更しないと、「blender contect is incorrect」と怒られてしまう。
bpy.ops.object.mode_set(mode = "EDIT")
使い方の方はこれでかなりいい感じ
import bpy
def decimate(ratio):
bpy.ops.object.modifier_add(type='DECIMATE')
decim = bpy.context.object.modifiers["Decimate"]
decim.ratio = ratio
## manipulation of duplicated object
bpy.ops.object.duplicate()
decimate(0.05)
bpy.ops.object.modifier_apply(modifier="Decimate")
# Editモードにする
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.remove_doubles(threshold = 0.02)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(type = 'FACE')
bpy.ops.mesh.select_interior_faces()
bpy.ops.mesh.delete(type='FACE')
bpy.ops.object.mode_set(mode='OBJECT')
ob = bpy.context.active_object
# Get material
mat = bpy.data.materials.get("Material")
if mat is None:
# create material
mat = bpy.data.materials.new(name="Material")
mat.use_nodes = True
bsdf = mat.node_tree.nodes["Principled BSDF"]
texImage = mat.node_tree.nodes.new('ShaderNodeTexImage')
texImage.image = bpy.data.images.new(name="Image Texture", width=2048, height=2048)
mat.node_tree.links.new(bsdf.inputs['Base Color'], texImage.outputs['Color'])
# Assign it to object
if ob.data.materials:
# assign to 1st material slot
ob.data.materials[0] = mat
else:
# no slots
ob.data.materials.append(mat)
↑このサイトのこのへんが役立ちそう
def execute(self, context):
# ベイクの設定
render = context.scene.render
render.engine = "CYCLES"
render.bake.use_pass_direct = False
render.bake.use_pass_indirect = False
render.bake.use_pass_color = True
render.bake.use_selected_to_active = False
obj = context.active_object
tt = ["Base Color", "Roughness", "Normal"]
dct = {t: [lst, None] for t in tt if (lst := list(get_node_data(obj, t)))}
for target, lsts in dct.items():
lsts[1] = bake_target(context, target, lsts[0])
for target, lsts in dct.items():
for nd in lsts[0]:
nodes = nd.node_tree.nodes
# 画像テクスチャノード作成
image_node = nodes.new(type="ShaderNodeTexImage")
image_node.image = lsts[1]
# ベイク画像に変更
if target == "Normal":
image_node.image.colorspace_settings.name = "Non-Color"
nmlmp_node = nodes.get("Normal Map") or nodes.new(type="ShaderNodeNormalMap")
nd.node_tree.links.new(image_node.outputs["Color"], nmlmp_node.inputs["Color"])
nd.node_tree.links.new(nmlmp_node.outputs[target], nd.bsdf.inputs[target])
else:
nd.node_tree.links.new(image_node.outputs["Color"], nd.bsdf.inputs[target])
self.report({"INFO"}, "Done" if dct else "Nothing")
return {"FINISHED"}
import bpy
import time
def decimate(ratio):
bpy.ops.object.modifier_add(type='DECIMATE')
decim = bpy.context.object.modifiers["Decimate"]
decim.ratio = ratio
## manipulation of duplicated object
bpy.ops.object.duplicate()
decimate(0.05)
bpy.ops.object.modifier_apply(modifier="Decimate")
# Editモードにする
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.remove_doubles(threshold = 0.02)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(type = 'FACE')
bpy.ops.mesh.select_interior_faces()
bpy.ops.mesh.delete(type='FACE')
bpy.ops.object.mode_set(mode='OBJECT')
ob = bpy.context.active_object
# Get material
mat = bpy.data.materials.get("Material")
if mat is None:
# create material
mat = bpy.data.materials.new(name="Material")
mat.use_nodes = True
bsdf = mat.node_tree.nodes["Principled BSDF"]
texImage = mat.node_tree.nodes.new('ShaderNodeTexImage')
texImage.image = bpy.data.images.new(name="ImageTexture"+str(time.time()), width=2048, height=2048)
mat.node_tree.links.new(bsdf.inputs['Base Color'], texImage.outputs['Color'])
# Assign it to object
if ob.data.materials:
# assign to 1st material slot
ob.data.materials[0] = mat
else:
# no slots
ob.data.materials.append(mat)
## Bakeまで自動化しようと思ったけど諦めた
## Get the active object and selected object
#active_obj = bpy.context.view_layer.objects.active
#selected_objs = bpy.context.selected_objects
## Set render settings
#render = bpy.context.scene.render
#render.engine = "CYCLES"
#render.bake.use_pass_direct = False
#render.bake.use_pass_indirect = False
#render.bake.use_pass_color = True
#render.bake.use_selected_to_active = True
## Set the device and feature set
#bpy.context.scene.cycles.device = "GPU"
## Loop through selected objects and bake their textures onto the active object
#for obj in selected_objs:
# if obj != active_obj and obj.type == 'MESH':
## bpy.context.view_layer.objects.active = obj
# bpy.ops.object.bake(type='DIFFUSE')