IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> [原创]编写一个最简单的blender节点插件教程 -> 正文阅读

[游戏开发][原创]编写一个最简单的blender节点插件教程

其实节点插件跟普通插件的本质是一样的,只是它界面是节点而已.我这里简单介绍了如何用200行代码实现一个简单的自定义节点插件,把下面代码 另存为xx.py, 因为这里使用了中文变量,所以必须以utf-8格式保存文本.


bl_info = {
	"name": "nodes_example",#在插件面板显示的插件名
	"author": "imdjs",#作者名
	"version": (1,0),#本节点版本
	"blender": (2,93,0),#节点支持的blender版本
	"location": "Node Editor > nodes_example",
	"description": "本脚本仅供学习参考",
	"wiki_url":	 "http://",#可以添加 你的 网站链接
	"warning": "",
	"category": "Node"}

# ----导入必须的模块--------------------------
import bpy,os,sys,imp
from bpy.app.handlers import persistent
import nodeitems_utils
from nodeitems_utils import NodeCategory, NodeItem
from bpy.props import BoolProperty,IntProperty,StringProperty,FloatProperty,FloatVectorProperty,EnumProperty,PointerProperty
from bpy.types import NodeTree, Node,NodeSocket

#----------------------------------------------------
# pathTestNODE = os.path.dirname(__file__) #本py文件所在目录 
# TEST_NODE=os.path.basename(pathTestNODE)  #Node_imdjs
#----刷新手柄  handler---------------------------------------------------
@persistent
def 刷新手柄函数(scene):
	for nt in bpy.data.node_groups:
		if(nt.bl_idname=="Node_imdjs"):
			for n in nt.nodes:
				#print("N==",n.name)
				if (n.bl_idname =="TEST_NodeStartPre"):#如果是开始节点
					n.升级节点函数(scene)#升级开始节点


# 主节点树类型---------------------------------------------
class Node_imdjs(NodeTree):
	bl_idname = "Node_imdjs"
	bl_label = 'Node_imdjs'
	bl_icon = 'MONKEY'
	
#  ---节点的接口,输入输出接口都可以用这个-------------------------------------
class TEST_NodeSocket(NodeSocket):
	bl_idname = "TEST_NodeSocket"
	bl_label = "输出输入"

	ip开始帧 :IntProperty() 

	def draw(self, context, layout, node, text):
		layout.label(text=text)

	def draw_color(self, context, node):
		return (1.0, 1.0, 0.0, 1.0)
#bpy.utils.register_class(TEST_NodeSocket);


#主节点树定义,可以是任何名称/
class TEST_NODES():
	@classmethod
	def poll(cls, ntree):
		return (ntree.bl_idname == Node_imdjs.bl_idname)
		
#连接物体的 入口节点///	 
class object_TEST_NODES(Node,TEST_NODES):
	bl_idname = "TEST_NodeObject"
	bl_label = "物体"

	spObject:StringProperty(name='object',description='选择一个物体',default='',maxlen=0,subtype='NONE',update=None,get=None,set=None);
	#--------------------------------------------------------------
	def init(self,context):
		self.outputs.new(TEST_NodeSocket.bl_idname,name="输出",identifier = "out_put")
	#-------------------------------------------------------------
	def draw_buttons(self,context,layout):
		layout.prop_search(self, "spObject", context.scene, "objects", text="物体们", icon = "OBJECT_DATA");
#开始节点//
#每个节点树都要增加这个开始节点.
class 开始节点TEST_NODES(Node,TEST_NODES):
	bl_idname = "TEST_NodeStartPre"
	bl_label = "开始节点"
	bl_width_default=200;##定义节点默认宽度
	bl_width_min=200;#定义节点最小宽度
	bl_width_max=500;#定义节点最大宽度
	
	ip开始帧 :IntProperty()
	spInfo:StringProperty(name='',description='',default='')   
	#----画节点界面--------------------------------------------------------
	def init(self,context):
		self.inputs.new(TEST_NodeSocket.bl_idname,name="输入",identifier = "in_put")
		self.outputs.new(TEST_NodeSocket.bl_idname,name="输出",identifier = "out_put")
		self.ip开始帧 = 1

	#======================================================
	def 升级节点函数(self,scene):
		#----如果有输入节点链接-----------------------------------------------
		if(self.inputs["输入"].links):
			self.outputs["输出"].ip开始帧 = self.ip开始帧
			nInput=self.inputs["输入"].links[0].from_node
			#print("GROUP==",nInput.name);
			if(not nInput):
				self.report({"ERROR"},"NO  输入 NODE!!!");#"INFO" "ERROR" "DEBUG" "WARNING"
				return ;
			
			nOutput=self.outputs["输出"].links[0].to_node
			if(nOutput):
				o=scene.objects[nInput.spObject]
				nOutput.升级节点函数(scene,o)
			
	#----画节点里的按钮------------------------------------------------
	def draw_buttons(self,context,layout):
		layout.prop(self, "ip开始帧", text = "开始帧",slider=False);
		OP=layout.operator(operator=DebugTestNodes.bl_idname,text='debug',text_ctxt='',translate=True,icon='NONE',emboss=True,icon_value=0);OP.spThisNode=self.name;#self.spInfo=OP.spInfo;
		
		uil=layout.row(align=False);
		uil.prop(self,"spInfo",text = "Info",icon="NONE",slider=False,emboss=True)
		uil.enabled=False;
		
#====Debug 调试节点,===========================================
class DebugTestNodes(bpy.types.Operator):
	bl_idname = "op.update_node_debug";
	bl_label = "刷新物体";
	bl_description = "debug节点,尝试执行节点以检查它是否有问题";
	spThisNode:StringProperty(name='',description='',default='',maxlen=0,subtype='NONE',update=None,get=None,set=None);
	#spInfo=StringProperty(name='',description='',default='')	 
	
	def execute(self, context):
		scene=context.scene;
		if(self.spThisNode!=None):
			Lnt=[nt for nt in bpy.data.node_groups if(nt.bl_idname=="Node_imdjs")];
			for nt in Lnt:
				for n in nt.nodes:
					if (n.bl_idname =="TEST_NodeStartPre" and n.name==self.spThisNode):			   
						n.升级节点函数(scene);
						n.spInfo="ok"
						return {"FINISHED"};
		n.spInfo="没有开始节点!!!"
		return {"FINISHED"};  


		
#功能节点,在这里可以写任何想实现的功能/
class TEST_NODES_FUNCION(Node, TEST_NODES):
	bl_idname = "TEST_NodeFuncion"
	bl_label = '移动物体'
	bl_icon = 'MONKEY'
	
	fvpp:FloatVectorProperty(size=3, default=(1.0, 1.0, 1.0));
	#====画节点界面============================================
	def init(self, context):
		self.inputs.new(TEST_NodeSocket.bl_idname,"输入")

		self.inputs.new("NodeSocketInt","TIME")
		self.outputs.new(TEST_NodeSocket.bl_idname,"输出")

	#======================================================
	def 升级节点函数(self,scene,o): #每帧刷新一次
		fStartTime=self.inputs["输入"].ip开始帧 = self.inputs["输入"].links[0].from_socket.ip开始帧+1#前面的时刻传给自己 
		#----看输入接口是否有节点----------------------
		for s in ["TIME"]:
			if (len(self.inputs[s].links) > 0):#有链接
				nFront = self.inputs[s].links[0].from_node
				self.inputs[s].default_value = self.inputs[s].links[0].from_socket.default_value#把对方的值 赋予自己

		#----如果在本节点时间内--------------------------
		nsNext=self.outputs["输出"]
		iTime_this=self.inputs["TIME"].default_value
		if(iTime_this==0 and  iTime_this!=100000):
			iTime_this=100000
		nsNext.ip开始帧 = fStartTime + iTime_this#决定 本节点结束时间
		iFrame=scene.frame_current
		if (iFrame>fStartTime and iFrame<=nsNext.ip开始帧 ):#在本节点时间内就...
			#o.location=(o.location.x+0.02)**0.5,(o.location.y+0.02)**0.2,(o.location.z+0.02)**0.1;
			#----●这里可以写上你想实现的任何功能●--------------------------
			o.location=o.location.x+0.02,o.location.y+0.02,o.location.z+0.01;
			self.fvpp=o.location;#显示坐标
			刷新界面函数("NODE_EDITOR","WINDOW");
		#----如果有下一个节点 并且时间已过本节点时间  就升级它------------------
		if(len(nsNext.links) > 0):
			if (iFrame>= nsNext.ip开始帧):
				for link in nsNext.links:
					link.to_node.升级节点函数(scene,o)

	#===按钮界面========================================
	def draw_buttons(self, context, layout):
		layout.prop(self,"fvpp",text = "坐标",icon="NONE",slider=False,emboss=True)

#每修改了物体位置 都要刷新一下界面/
def 刷新界面函数(area,region):
	screen=bpy.context.screen;
	if(area):
		for a in screen.areas:
			if(a.type==area):#EMPTY", "VIEW_3D", "TIMELINE", "GRAPH_EDITOR", "DOPESHEET_EDITOR", "NLA_EDITOR", "IMAGE_EDITOR", "SEQUENCE_EDITOR", "CLIP_EDITOR", "TEXT_EDITOR", "NODE_EDITOR", "LOGIC_EDITOR", "PROPERTIES", "OUTLINER", "USER_PREFERENCES", "INFO", "FILE_BROWSER", "CONSOLE"
				#a.tag_redraw();#■■这个能刷新所有 region画面
				if(region):
					for r in a.regions:#WINDOW", "HEADER", "CHANNELS", "TEMPORARY", "UI", "TOOLS", "TOOL_PROPS", "PREVIEW
						if(r.type==region):
							r.tag_redraw();
							break;
					break;
					
#====增加节点面板与条目============================================
class TEST_NodeCategory(NodeCategory):
	@classmethod
	def poll(cls, context):
		return (context.space_data.tree_type == Node_imdjs.bl_idname);
		
TEST_node_list = [
									TEST_NodeCategory("TEST_NodeCategory2", "开始",
									items=[NodeItem(开始节点TEST_NODES.bl_idname),
													 NodeItem(TEST_NODES_FUNCION.bl_idname) ]),
									TEST_NodeCategory("TEST_NodeCategory1", "物体输入",
									items=[NodeItem(object_TEST_NODES.bl_idname) ])
									]	

# 注册插件函数---------------------------------------------------
def 注册类(LL类,b打印=False):
	for L类 in LL类:
		for 类 in L类:
			if(b打印):print("注册类==",类);
			try:
				bpy.utils.register_class(类);
			except:
				print("!!!不能注册类 ==",类);
				
def 注销类(LL类,b打印=False):
	for L类 in LL类:
		for 类 in L类:
			if(b打印):print("注销类==",类);
			try:
				bpy.utils.unregister_class(类);
			except:
				print("!!!不能注销类==",类);
				

			
#----注册插件------------------------------------
def register():
	注册类([(Node_imdjs,TEST_NodeSocket,TEST_NODES,object_TEST_NODES,开始节点TEST_NODES,DebugTestNodes,TEST_NODES_FUNCION,TEST_NodeCategory)],True);

	nodeitems_utils.register_node_categories("Node_imdjs", TEST_node_list)
	bpy.app.handlers.frame_change_pre.append(刷新手柄函数)#添加一个刷新手柄



def unregister():
	nodeitems_utils.unregister_node_categories("Node_imdjs")
	注销类([(Node_imdjs,TEST_NodeSocket,TEST_NODES,object_TEST_NODES,开始节点TEST_NODES,DebugTestNodes,TEST_NODES_FUNCION,TEST_NodeCategory)]);
	try:
		bpy.app.handlers.frame_change_pre.remove(刷新手柄函数)
	except:pass;
	

	
#//
if (__name__ == "__main__"):
	register()
	
	

#end//




在节点面板勾选刚才注册这个节点插件

?

在节点编辑界面新建节点树并连接好三个基本节点:

?

?

播放就可以实现猴头的简单移动.

这里只是一个简单的功能,但你可以增加任何想要的功能或任何节点.

基本上代码的注释已经说明了每个节点的作用,写自己的节点所需要做的就是增加自己的节点功能与节点类型,节点与普通插件的区别只是界面上的,就算不用节点界面也可以实现每帧刷新功能.例如一些模拟类型的插件.

下面是gif 演示:

?

https://postimg.cc/gallery/50b0NMM

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-13 09:34:32  更:2021-09-13 09:37:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 19:23:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码