# blender编程
参考文章:
# 配置环境
blender本身提供一个简单IDE,但是输入切换有些别扭,还是使用Visual Studio Code比较好。这个时候就需要安装一些插件。
安装插件Blender Development和Blender Python Code Templates。
下载fake-bpy-module (opens new window)模块并安装,这样就有自动补全了。
"blender.executables":[ { "path": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Blender", "name": "", "isDebug": false, } ], "python.autoComplete.extraPaths": [ "D:\\ProjectFiles\\blender\\fake-bpy-module", ],
1
2
3
4
5
6
7
8
9
10
除此之外,blender自身需要开启Blender Preferences->Interface->Display:
- Developer Extras
- Python Tooltips
# 安装第三方库
肯定会有一些需求来装python的第三方库。此时需要:
- 去pip installation (opens new window)下载get-pip.py并运行该脚本:
.\python.exe .\get-pip.py
- 去scripts目录下载第三方库:
.\pip3.exe install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple
- 在Blender里面引用第三方库:
import cv2
# 坐标系
参考资料:
如果是2d,那么一般x为右方,y轴为上方。
如果是3d,那么有两种坐标系:
X轴向右,Y轴向上,Z轴向 由屏幕指向我们,叫做右手坐标系
X轴向右,Y轴向上,Z轴向 由我们指向屏幕,叫做左手坐标系
blender里面z为上,-y轴为前方,x轴为右方。为右手坐标系。
UE里面z为上,x为前方,y为右方。为左手坐标系。
Unity里面y为上,z为前方,x为右方。为左手坐标系。
3dMax里面z为上,x为前方,y为右方。为右手坐标系。
Maya里面y为上,z为前后,x为左右。默认为右手坐标系。
模型从blender里面导出ue4里面,如果以y轴为前方导出,则y需要乘以-1为ue4的y的值。
# 重要模块
blender按模块划分为下面几个模块:
# bpy.context
bpy.context可以理解为blender当前可被获取的区域的集合。
- bpy.context.object为当前鼠标选择的对象。
- 他们的值为bpy.data.objects中的某个对象。
- 该对象为只读数据。
# bpy.data
bpy.data用来获取blender的内部数据。
- bpy.data.objects为当前场景中的所有对象。
- bpy.data.objects可通过场景中的名字索引,也可以根据数字索引。
# bpy.msgbus
消息系统可用来在blender的数据块通过bpy.data改变时接收通知。
- 消息系统是通过RNA系统的更新来触发的,这意味着下面两个操作是会触发的:
- 通过python的api改变,比如some_object.location.x += 3。
- 通过slider,fields和用户界面的button。
- 而下面的操作是不会触发的:
- 在3D视角里移动对象。
- 通过动画系统来实现的改变。
# bpy.ops
给python提供调用操作的入口,这些操作可能用c,python以及一些宏来写的。
只有关键的参数才会被用来传送给操作属性。
这些操作并不会返回你期望的值,他们可能会返回一个集合{'RUNNING_MODAL', 'CANCELLED', 'FINISHED', 'PASS_THROUGH'}。通常只会返回{'FINISHED'} and {'CANCELLED'}。
在一个错误的上下文调用操作会返回RuntimeError,会有一个poll()方法来阻止这个问题。
if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='EDIT')
1
2注意bpy.ops只是python的一个获取路径,它的操作id是后面开始的,比如bpy.ops.mesh.subdivide它的操作id是mesh.subdivide。
# bpy.types
包含了blender里的所有对象类型。
# bpy.utils
这个模块包含了blender的工具函数,这些工具函数没有涉及到blender的内部数据。
# bpy.path
这个模块类似于os.path,包含了blender里要处理的各种路径的工具函数。
# bpy.app
这个模块包含了blender运行期间未改变的值。
# bpy.props
这个模块包含了扩展blender内部数据的一些属性。这些函数会被用来赋值blender内部注册类的属性。
- 传给这些函数的参数必须以关键词的形式传入。
# 其他操作
如果一个类我们想获取它的方法,可以使用dir()方法来获取。
# 示例
# 插入关键帧
import bpy # 导入bpy模块
import random #导入随机模块
startFrame = 1 #设置起始帧
endFrame = 601 #设置结束帧
scene = bpy.context.scene #获得场景缩写
obj = bpy.context.object #获得当前所选的对象 # Reference to selected object
for frame_nr in range(startFrame,endFrame): #进入从起始帧到结束帧到循环
# set current frame 设置当前关键帧
scene.frame_set(frame_nr)
# print(frame_nr) 调试信息,打印当前帧
ploc = obj.location #获得之前的对象的位置
xpos = ploc[0] #获得x坐标
ypos = ploc[1] #获得y坐标
zpos = ploc[2] #获得z坐标
zpos = zpos + ( random.random()) # 赋值新的z坐标
obj.location = (xpos, ypos, zpos) #将新的三纬度坐标应用到对象上
obj.keyframe_insert(data_path="location", index=-1) #为新的位置插入关键帧 其中data_path可通过鼠标右键copy data path来获取。假如index为0,为只记录x。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 生成数字模型
import bpy
import csv
num=1
startNum=111501
endNum=116500
with open(r"D:\blender\loc.csv") as f:
filecontent = csv.reader(f)
for row in filecontent:
#for i in range(31500,41500):
#row = next(filecontent)
if num < startNum:
num+=1
continue
if num > endNum:
break
bpy.ops.object.text_add(enter_editmode=False, align='WORLD', location=(float(row[0])/100, float(row[1])/-100, 0), scale=(1, 1, 1))
bpy.context.object.data.resolution_u = 2
bpy.context.object.data.align_x = 'CENTER'
bpy.context.object.data.align_y = 'CENTER'
bpy.context.object.data.body=row[2]
#bpy.context.object.data.extrude = 0.1
bpy.context.object.data.size = 2.5
bpy.ops.object.convert(target='MESH')
bpy.context.object.name="point"+str(num)
num+=1
levelNumTemp = float(row[2])//5
levelNum = int(levelNumTemp)
if levelNum<0:
bpy.ops.object.move_to_collection(collection_index=6)
else:
if levelNum<4:
levelNum+=1
bpy.ops.object.move_to_collection(collection_index=levelNum)
else:
bpy.ops.object.move_to_collection(collection_index=5)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
下面是另一种生成数字模型的方法,暂未使用,后面有机会可以用下看看效率:
import bpy
font_curve = bpy.data.curves.new(type="FONT", name="Font Curve")
font_curve.body = "my text"
font_obj = bpy.data.objects.new(name="Font Object", object_data=font_curve)
bpy.context.scene.collection.objects.link(font_obj)
2
3
4
5
6
# 检测场景
检测当前场景中以point开头命名的物体数量是否符合条件
import bpy
num=0
startNum=291501
endNum=296500
if len(bpy.data.objects) != 5000:
print("场景中物体数量不对!")
else:
for i in range(startNum,endNum+1):
if bpy.data.objects[num].name != ("point"+str(i)):
print("point"+str(i)+" not exist")
break
else:
num+=1
print("point"+str(i)+" is ok!")
print("check point total num:"+str(num));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 删除一些物体
import bpy
num=0
startNum=291501
endNum=296500
for i in range(startNum,endNum+1):
if bpy.data.objects[num].name == ("point"+str(i)):
print("point"+str(i)+" delete")
bpy.data.objects.remove(bpy.data.objects[num],do_unlink=True)
2
3
4
5
6
7
8
9
10
# 合并blender文件
import bpy
import os
workpath=r"D:\blender\okay"
num=0
for root, dirs, files in os.walk(workpath, topdown=False):
for name in files:
num+=1
currentfile = os.path.join(root, name)
print("deal files:"+currentfile)
for i in range(0,6):
print("deal collection:"+str(i))
bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection.children[i]
bpy.ops.wm.append(directory=currentfile + "/Collection/", files=[{'name':"Collection "+str(i+1)}],instance_collections=False)
print(num)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16