欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用maya的api创建自定义的节点Creating Custom Locator

程序员文章站 2022-07-12 13:47:20
...

原文地址 http://www.fevrierdorian.com/blog/post/2010/02/12/Creating-custom-locator-with-Maya-s-Python-API

用maya的api创建自定义的节点Creating Custom Locator这个帖子是这个帖子的中文翻译。 希望这个教程对你有帮助。

正如 我之前提到的,我开始使用Maya API Python绑定。所以我看了一下Rob Bateman的的源码(一年前我觉得很难理解),然后把它们 "翻译 "成了Python…所以我创建了一个带有自定义定位器的小脚本。这显然不是世界上最简单的东西,多亏了其他教程,已经集成到Maya中的Python "插件 "和我做的OpenGL教程,我确实有了一些基础),但一旦代码运行起来,修改它来制作自己的定位器是相当有趣的。

所以,在菜单上我们有:

  • OpenGL (那么,你还怎么画你的定位器呢? 用maya的api创建自定义的节点Creating Custom Locator )
  • 颜色的变化作为定位器选择状态的函数。

虽然不多,但你会发现这已经够用了!

脚本是没有意义的,是给新手看的!

不!如果你这么想,那你就什么都没看懂。这两者是密切相关的。如果我选择了定位器这个例子,不仅仅是因为它的 “酷”,还因为它是一个只有用API才能做的事情的例子…

但API并不是万能的! 用maya的api创建自定义的节点Creating Custom Locator

毫无疑问,你已经知道,Maya界面完全是用MEL编写的,它允许脚本作者为自己的脚本快速创建一个GUI。不是所有的软件包都提供这种功能(有人说过XSI吗),而Maya是为数不多的几个拥有这种功能的软件包之一。

大多数的Maya函数调用也是脚本化的。这意味着你可以 "批处理 "你的操作(当你有50个场景要打开来改变一个属性的值时,你就不会笑得那么厉害了!

我只能请大家阅读我的导师的帖子关于这个问题的帖子(显示C++相当于MEL的代码)。

最后说一句话。Python是一门脚本语言! 即使它可以被解释器 “预编译”,但它仍然是脚本。

话虽如此,但我认为这个论点有点无济于事,因为即使你用Maya API Python绑定的脚本,一旦了解了基础知识,你就会意识到,一段C++代码和Python中的等效代码在语法上的差异是十分小的。

下面是一个变量声明的小例子。

C++

MFnPlugin fnPlugin(obj)

Python

fnPlugin = OpenMayaMPx.MFnPlugin(obj)

我认为C++仍然是最容易使用的,我认为(我不是因为这个例子而这么说的,而是从更广泛的角度来说),这似乎是符合逻辑的,因为它是历史上使用的实现,再加上它仍然是一种相当接近机器的语言。

那么,这一切都取决于你是否想要快速发展。编译后的代码(C++)显然会更快(约10次),但我猜想,如果你想快的话,要么你不擅长,你写的代码很烂,这让你除了求助于低级语言来提速之外,没有其他的解决办法,要么你是一个 "真正的 "开发者…如果是这样的话,我不明白你在周日的博客上做什么,你是在做什么?我!!)。

管他呢,总有一天我要在MEL、pythonForMel、C++和pythonForMayaApi之间做一个桥梁!

代码基础知识

在我们开始写定位器之前,我们需要基础代码。我们开始吧!

import sys
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.OpenMayaRender as OpenMayaRender
 
nodeTypeName = "myCustomLocator"
nodeTypeId = OpenMaya.MTypeId(0x87079)
 
glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer()
glFT = glRenderer.glFunctionTable()
 
class myNode(OpenMayaMPx.MPxLocatorNode):
	def __init__(self):
		OpenMayaMPx.MPxLocatorNode.__init__(self)
 
 
def nodeCreator():
	return OpenMayaMPx.asMPxPtr(myNode())
 
def nodeInitializer():
	return OpenMaya.MStatus.kSuccess
 
def initializePlugin(obj):
	plugin = OpenMayaMPx.MFnPlugin(obj)
	try:
		plugin.registerNode(nodeTypeName, nodeTypeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kLocatorNode)
	except:
		sys.stderr.write( "Failed to register node: %s" % nodeTypeName)
 
def uninitializePlugin(obj):
	plugin = OpenMayaMPx.MFnPlugin(obj)
	try:
		plugin.deregisterNode(nodeTypeId)
	except:
		sys.stderr.write( "Failed to deregister node: %s" % nodeTypeName)

砰!我们现在不是装得很聪明了吧?(我第一次也没装聪明!)

对了,其实也不是很复杂。解释一下:

import sys
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.OpenMayaRender as OpenMayaRender

这里我们要导入主要的模块。第一个(“sys”)是系统模块,我们将用它来编写插件的初始化错误信息(仅此而已)。

接下来的三个是Maya API Python模块。为了明确它们的用途,我们把它们分成了几个模块:

  • OpenMaya是与节点和命令定义相关的类以及将它们 "组装 "成插件的模块。
  • OpenMayaMPx是一个Python特有的模块。它包含Maya的代理(或MPx类)绑定。
  • OpenMayaRender是与渲染(硬件或软件)相关的类的模块。
nodeTypeName = "myCustomLocator"

这个变量(我在一开始就声明了)将被用来给你想创建的节点类型起一个名字。

nodeTypeId = OpenMaya.MTypeId(0x87079)

这个变量(我在一开始也声明了它)将被用来给我们的节点类型赋予一个ID(标识符)。

glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer()

这是它变得复杂的地方(尤其是对我来说),文档中没有提到这个命令(尽管它出现在C++的示例代码中)。正是由于这个命令,我们才能够 "绘制 "我们的定位器(使用OpenGL命令)。

glFT = glRenderer.glFunctionTable()

glFunctionTable() 方法返回一个指针到包含 Maya 处理的所有 OpenGL 指令的对象。

现在,我们真正进入了OpenGL(好吧,也许还不完全是,您将看到)

OpenGL, some informations

什么是OpenGL?(Wiki) 总结一下,就是与显卡沟通的一种方式。它涉及到一些简单的命令,比如显示点、线、三角形、四边形、纹理等。

在我们继续往下说之前,我们要先了解一下这一切是如何运作的。如果你想 "画出 "定位器,你必须知道如何使用这支笔来完成它。

由于一段代码比长篇大论更有价值,下面是如何在OpenGL中 "画 "出一条线(这是一个C语言源码。对于Maya来说,我们会发现,有两三样东西是你必须要先知道的)

glBegin(GL_LINES)
glVertex3f(0.0, -0.5, 0.0)
glVertex3f(0.0, 0.5, 0.0)
glEnd()

这种技术是 "基本(basic)"或 "即时模式(immediate mode)"技术。

glBegin(GL_LINES)

这个命令可以让我们 “进入原始绘图模式”(在三维空间中),我们把铅笔对着纸,如果你喜欢的话。参数(GL_LINES)让我们可以说下面的命令将如何解释,在这里进行内联。每隔两个顶点,我们再写一行。每一对顶点写一行。

glVertex3f(0.0, -0.5, 0.0)
glVertex3f(0.0, 0.5, 0.0)

这两条命令是将顶点 "放置 "在空间中的命令。这条命令是glVertex,数字是参数的数量(这里是三个:x、y、z),最后一个字母是数据类型(这里的 "f "表示float。)

基本上,我们在空间中放置两个顶点。考虑到我们已经把自己放到了 "直线绘制 "模式下(每个顶点对),我们只是画了一条线。

glEnd()

而这只是一种与显卡 “关闭通讯”,返回主程序的方式。

正如你所看到的,OpenGL并不是那么难的事情! 我也是这样理解的,是处理器计算每个图像中所有顶点的位置(好吧,这是老方法;还有其他的方法,尤其是静态对象,它是存储在显卡内存中,由一条指令调用的静态对象。话虽如此,但很大一部分工作是由处理器来完成的)

有了这些,你就差不多可以画出自己的定位器了。我只剩下一点要解决的问题了。

OpenGL, the Maya version!

事实上,我给大家看的代码是一个C语言程序。下面我就给大家解释一下Maya特有的几个OpenGL的一些特殊性。

出于对互操作性的考虑(我想还有其他原因),Maya有自己的OpenGL实现。因此,当我们希望在视口中绘制时,我们并不直接使用Windows或Mac的实现,而实际上是Maya自己的实现。(在C++中也可以这样做,这样就可以省去Maya的封装器,但你必须在代码中处理好互操作性。在Python中应该也可以这样做,但我还没有尝试过)。这在代码中没有什么变化,但常量(例如GL_LINES)有另一个名字。

正如 Maya API 文档中所写的那样:

The naming convention used in this file is to take the regular GL* definitions and add a “M” prefix

这个文件中使用的命名方法是: 在这个文件中使用的命名惯例是采用常规的 GL* 定义,并添加一个 "M "前缀。

翻译: “我们在所有的OpenGL常数前面加了一个’M’”。

所以Maya不会理解GL_LINES,只能理解OpenMayaRender.MGL_LINES

下面是我们如何用OpenGL在Maya中写出一条线:

glFT.glBegin(OpenMayaRender.MGL_LINES)
glFT.glVertex3f(0.0, -0.5, 0.0)
glFT.glVertex3f(0.0, 0.5, 0.0)
glFT.glEnd()

所以没有太大的区别了^^.任何一个有经验的OpenGL用户应该都可以闭着眼睛完成!

So shall we write this locator then?

不,还不行!还有很多东西要学! 在对OpenGL的小介绍之后,让我们回到我们的Python脚本上。

为了能够绘制出定位器,我们必须要派生出 "draw "函数(是的,因为Maya允许你派生函数…不是每个人都能说得这么多,嗯,XSI? ) 这个函数是用来…使用OpenGL函数绘制自定义几何图形的。

下面是 "draw "方法的基本代码。:

def draw(self, view, path, style, status):
 
	view.beginGL()
 
	view.endGL()

beginGL()和endGL()函数使我们可以(嗯,这是我的解释)告诉Maya,我们要在它们之间使用OpenGL命令。根据文档,如果没有把它们包含在正确的地方,程序将超过分配的内存,因此程序将崩溃。

我刻意将几个函数暂时忘掉,我们以后再看。

Go Pawaaaah!

所以我们现在的代码是这样的:

import sys
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.OpenMayaRender as OpenMayaRender
 
nodeTypeName = "myCustomLocator"
nodeTypeId = OpenMaya.MTypeId(0x87079)
 
glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer()
glFT = glRenderer.glFunctionTable()
 
class myNode(OpenMayaMPx.MPxLocatorNode):
	def __init__(self):
		OpenMayaMPx.MPxLocatorNode.__init__(self)
 
	def draw(self, view, path, style, status):
 
		view.beginGL()
 
		glFT.glBegin(OpenMayaRender.MGL_LINES)
		glFT.glVertex3f(0.0, -0.5, 0.0)
		glFT.glVertex3f(0.0, 0.5, 0.0)
		glFT.glEnd()
 
		view.endGL()
 
 
def nodeCreator():
	return OpenMayaMPx.asMPxPtr(myNode())
 
def nodeInitializer():
	return OpenMaya.MStatus.kSuccess
 
def initializePlugin(obj):
	plugin = OpenMayaMPx.MFnPlugin(obj)
	try:
		plugin.registerNode(nodeTypeName, nodeTypeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kLocatorNode)
	except:
		sys.stderr.write( "Failed to register node: %s" % nodeTypeName)
 
def uninitializePlugin(obj):
	plugin = OpenMayaMPx.MFnPlugin(obj)
	try:
		plugin.deregisterNode(nodeTypeId)
	except:
		sys.stderr.write( "Failed to deregister node: %s" % nodeTypeName)

You can download it here:

CustomLocatorNode001.7z

Load it (as a plug-in), and enter:

createNode myCustomLocator;

用maya的api创建自定义的节点Creating Custom Locator

我们刚刚做了第一个定位器! 有了这个,我们已经可以做一些事情了…如果你给它点random,就可以得到这个:

import random

glFT.glBegin(OpenMayaRender.MGL_LINES)
glFT.glVertex3f(random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5))
glFT.glVertex3f(random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5))
glFT.glEnd()

Le code: CustomLocatorNode002.7z

You’ll have a wicked locator! ^^

Right, it’s all very well making lines but that’s not all there is to it… I suggest we do… a quad! !

glFT.glBegin(OpenMayaRender.MGL_LINES)
glFT.glVertex3f(0.0, -0.5, 0.0)
glFT.glVertex3f(0.0, 0.5, 0.0)
glFT.glEnd()
 
glFT.glBegin(OpenMayaRender.MGL_QUADS)
glFT.glVertex3f(-0.5, 0.0, -0.5)
glFT.glVertex3f(0.5, 0.0, -0.5)
glFT.glVertex3f(0.5, 0.0, 0.5)
glFT.glVertex3f(-0.5, 0.0, 0.5)
glFT.glEnd()

The code: CustomLocatorNode003.7z

Paf le code!

用maya的api创建自定义的节点Creating Custom Locator

Paf le locator! 用maya的api创建自定义的节点Creating Custom Locator

好吧,虽然有点浮夸,但我们要改变一下! 我们要改变颜色,增加透明度。

首先是颜色。默认情况下,Maya使用的是界面颜色(未选中时为蓝色,选中时为绿色,"模板化 "时为粉色等),要改变颜色,只需添加命令glColor3f()

glFT.glBegin(OpenMayaRender.MGL_LINES)
glFT.glVertex3f(0.0, -0.5, 0.0)
glFT.glVertex3f(0.0, 0.5, 0.0)
glFT.glEnd()
 
glFT.glColor3f(1, 0, 0)	#on change la couleur
 
glFT.glBegin(OpenMayaRender.MGL_QUADS)
glFT.glVertex3f(-0.5, 0.0, -0.5)
glFT.glVertex3f(0.5, 0.0, -0.5)
glFT.glVertex3f(0.5, 0.0, 0.5)
glFT.glVertex3f(-0.5, 0.0, 0.5)
glFT.glEnd()

The code: CustomLocatorNode004.7z

Re-Paf le code!

用maya的api创建自定义的节点Creating Custom Locator

Re-Paf le locator! 用maya的api创建自定义的节点Creating Custom Locator

还是一样的浮夸,呵呵。你会注意到,只有线条的颜色会随着选择状态而改变。为了让我们的定位器更 "轻盈 "一些,我们要给我们的四边形添加透明度。

The Alpha

我们要 "启用 "OpenGL的一个功能。GL_BLEND (别忘了在最后禁用它):

#We activate feature
glFT.glEnable(OpenMayaRender.MGL_BLEND)
 
glFT.glBegin(OpenMayaRender.MGL_LINES)
glFT.glVertex3f(0.0, -0.5, 0.0)
glFT.glVertex3f(0.0, 0.5, 0.0)
glFT.glEnd()
 
glFT.glColor3f(1, 0, 0)	#Change color
 
glFT.glBegin(OpenMayaRender.MGL_QUADS)
glFT.glVertex3f(-0.5, 0.0, -0.5)
glFT.glVertex3f(0.5, 0.0, -0.5)
glFT.glVertex3f(0.5, 0.0, 0.5)
glFT.glVertex3f(-0.5, 0.0, 0.5)
glFT.glEnd()
 
#Don't forget to unactivate in the end!
glFT.glDisable(OpenMayaRender.MGL_BLEND)

当这个功能被启用后,OpenGL会根据最终的系数(Alpha)将给定的颜色与生成的颜色(背景)混合在一起。所以我们必须在颜色中添加最后一个组件 :

glFT.glEnable(OpenMayaRender.MGL_BLEND)
 
glFT.glBegin(OpenMayaRender.MGL_LINES)
glFT.glVertex3f(0.0, -0.5, 0.0)
glFT.glVertex3f(0.0, 0.5, 0.0)
glFT.glEnd()
 
glFT.glColor4f(1, 0, 0, 0.5)	#Change color and add alpha
 
glFT.glBegin(OpenMayaRender.MGL_QUADS)
glFT.glVertex3f(-0.5, 0.0, -0.5)
glFT.glVertex3f(0.5, 0.0, -0.5)
glFT.glVertex3f(0.5, 0.0, 0.5)
glFT.glVertex3f(-0.5, 0.0, 0.5)
glFT.glEnd()
 
glFT.glDisable(OpenMayaRender.MGL_BLEND)

Le code: CustomLocatorNode005.7z

用maya的api创建自定义的节点Creating Custom Locator

我们来到了最后一部分:选择状态.

Selection

事实上,我们可以根据定位器的选择状态来改变我们的定位器的各个方面。在这里,我们要改变… 的颜色!(很有创意… -_-)

首先,一个 "绘制 "对象有几种 “状态”(列在M3dView:::DisplayStatus中)。下面我给大家举出两个主要的状态,也就是我们要使用的状态。

  • kActive ->活动的(选定的)对象。(小心点,这个很棘手!)
  • kLead -> 最后一个被选中的对象。
  • kDormant -> 非活动对象。

所以,让我们来解释一下其中的细微差别:

在Maya中,当你选择了一个对象,它就变成了绿色。而当你在选择中添加另一个对象时,第二个对象会变成绿色,而前一个对象会变成白色。事实上,绿色对象是 “in DisplayStatus” kLead,而白色对象是在kActive中。这里有一张图片来解释(或者提醒你?)这个原理。

用maya的api创建自定义的节点Creating Custom Locator

所以我们要把颜色作为选择状态的函数来改变。

如上图所示,派生函数是draw,我们用来知道定位器的状态的参数是 “status”。而没有什么比使用这一切更简单了:

import maya.OpenMayaUI as OpenMayaUI # on top

if status == OpenMayaUI.M3dView.kLead:
	glFT.glColor4f(1, 0, 0, 0.3)	#rouge
if status == OpenMayaUI.M3dView.kActive:
	glFT.glColor4f(1, 1, 0, 0.4)	#jaune
if status == OpenMayaUI.M3dView.kDormant:
	glFT.glColor4f(1, 0, 1, 0.5)	#mauve

CustomLocatorNode006.7z

用maya的api创建自定义的节点Creating Custom Locator

用maya的api创建自定义的节点Creating Custom Locator

用maya的api创建自定义的节点Creating Custom Locator

好吧,虽然不是那么漂亮,但很好用… 用maya的api创建自定义的节点Creating Custom Locator

我希望这篇教程能让你对Python Maya API的几个方面有所了解… 不过请注意,我没有选择最简单的东西开始(如果你对API一无所知的话…否则,我觉得很简单),但有了这个,你已经有了第一个工具包,可以让你迈出第一步… !