——————>
人总是会被很多事物影响,在周围有太多太多与自己毫无关系的世界在左右,以至于使自己找一些借口去这些世界浪费时间。
浪费时间原因有二,一个是无聊,二个是累了。其实人本身是比较难以真正疲劳的,大多数感觉疲劳的原因是自己做某件事情花费了太多精力,以至于自己身体出现了一些变化而不知。很多时候精神上的疲劳都是由于忽略了身体的变化导致,所以最好的休息方式就是不让自己想任何事情,或者只专注于自己身体内在的信息。
所谓无聊就是自己精神力太充沛了,需要找个专注的事情去做,以至于会去玩游戏,看电影,逛街之类 ,精神的空虚就是要找自己感兴趣的事情去做,就算每天仅仅完成一点,都是可以的。
——————>
要写一个shape可是一个比较复杂的工程了。
以前我们都是用function set来创建shape node,这是把大部分工作都交给maya去完成了。但是shape毕竟是maya的很基础的部分,稍微研究一下也是很有好处的。
——————>
先要知道我们写这个shape node需要的母类:
1.MPxComponentShape
Component helper class for surface shapes.
MPxComponentShape allows the implementation of new user defined shapes using components. User defined shapes are dependency nodes (and DAG nodes) which contain overridable drawing, selection, and component methods.
2.MPxSurfaceShapeUI
drawing and selection for user defined shapes
The base class for the UI portion of all user defined shapes.
3.MPxGeometryIterator
This is the base class for user defined geometry iterators. Geometry iterator allow iterating over components in geometry in a geometry independent manner. This base class defines the interface to be used by maya when a generic component iteration is required.
——————>
然后看看这三个类的作用以及如何配合使用。当然,我现在先勾勒一个大致的框架:
我们要做一个shape,它需要显示,这个需要在屏幕里面画一些图形,图形的生成和刷新方面一定有类来负责
当画出来之后,我们需要操作,这个图形要根据我们的manipulator来做出不一样的显示,manipulator与shape node之间如何交互?这是一个方面。
我们的shape node 是由vertex组成的,多个vertex组成了face和edge,这些在maya里面都是内部object,说得形象一点,是component node,我们要如何得到这些component node?并且manipulator如何得到以及操控这些manipulator的数据呢?
好了,带着这些问题,来看看maya给的例子!
——————>MPxSurfaceShapeUI
看到这个母类的说明,我觉得应该从这里开始
API上说:
Drawing is a two step process. In the first, the geometry and materials are evaluated and all of the information necessary for drawing is placed onto a queue.
这句话对应的类中的方法是:
[in] info the drawing state information
[in] objectAndActiveOnly This parameter is used to determine if draw requests for components need to be supplied. If false, some or all components are active and draw requests must be built for all components.
[in] queue the drawing queue to place the draw request on
知道了这个之后,就要知道,到底那个类或者是哪个方法里面会来调用这个方法!
Drawing occurs whenever the camera changes or the view has to be refreshed. When this happens, the MPxSurfaceShapeUI::getDrawRequest function is called. This is Maya’s way of asking the shape what it needs to draw. Inside this function you should query the drawing state, using MDrawInfo, and then construct a draw request (MDrawRequest) to place on the queue.
这里说,maya会自动调用这个getDrawRequests方法,那么,maya是如何知道这个方法的呢,看看我们如何将我们写的派生类让maya知道!
看着maya给出的说明:
Registering shapes with Maya is similar to registering DG nodes. The only difference is that shapes have a separate UI class that must be registered with the shape node.
MStatus initializePlugin( MObject obj )
{
MFnPlugin plugin( obj, PLUGIN_COMPANY, "5.0", "Any");
MStatus stat = plugin.registerShape( "apiSimpleShape", apiSimpleShape::id,
&apiSimpleShape::creator,
&apiSimpleShape::initialize,
&apiSimpleShapeUI::creator );
if ( ! stat ) {
cerr << "Failed to register shape\n";
}
return stat;
}
在我们的mll入口方法中,我们要如上所示来填写.shape node 和DG node有一点不同,虽然shape node是DG node的一种,但是它还涉及到geometry data,这个geometry data是可以用来渲染以及很多种用途的,它不是普通意义上用openGL画出来的图形。所以,在这里分开来,写一个UI的派生类也是非常好的任务分工。
UI的creator方法会返回我们派生类的实例,所以maya就会根据这个实例找getDrawRequests的函数地址。
好了,继续我们的绘画,我们要知道getDrawRequests是如何绘画才能制作出geometry data呢?
看这最开始的几行代码:
// Get the data necessary to draw the shape
//
MDrawData data;
apiSimpleShape* shape = (apiSimpleShape*) surfaceShape();
MVectorArray* geomPtr = shape->getControlPoints();
// This call creates a prototype draw request that we can fill
// in and then add to the draw queue.
//
MDrawRequest request = info.getPrototype( *this );
// Stuff our data into the draw request, it’ll be used when the drawing
// actually happens
getDrawData( geomPtr, data );
request.setDrawData( data );
….
queue.add( request );
第一行是准备个数据结构来放geometry data。
第二,三行告诉我们,这个geometry data是从apiSimpleShape得到的,API里面给我们这个解释:
MPxSurfaceShape * MPxSurfaceShapeUI::surfaceShape ( ) const
Returns the non-ui shape associated with current instance of this class.
Returns:
The non ui shape object
这里的shape object就是我们要写的shape node部分。
shape node有一个方法getControlPoints()
这个方法让我们可以的得到CV点,CV点在maya里面是这样做的:
Shapes which are formed and manipulated by the position of control vertices (or CVs) are called control point shapes. The control points are attributes on the shape which are usually arrays of points.
它就是作为shape node 的属性,每一个cv点都是MVector(MPoint)结构的,也就是3个double(vector)。在maya里面是用array attribute node来作为数据接口。
mel里面就是:
// // Now add some CVs, one // string $attr = $node + ".controlPoints[0]"; // setAttr $attr 2 2 2;
第四行我们又要遇到两个陌生的类MDrawInfo和MDrawRequest。先看看getPrototype的说明:
MDrawRequest MDrawInfo::getPrototype ( const MPxSurfaceShapeUI & drawHandler ) const
This method creates a draw request based on the current draw state.
The draw request is placed onto maya’s drawing queue (MDrawRequestQueue) where it can be processed in turn. The drawHandler argument is the shape that will be doing the drawing which is the object calling this function.
我们从这里只能知道,request实例是基于info与UI类的绑定,从而得到的。
This getPrototype method is used to construct a draw request object based on the current draw state for the object.
我们从info得到的信息包括:
Information automatically set by MDrawInfo::getPrototype :
- path path to object to be drawn
- view view to draw in
- matrix world matrix for object
- display appearance how object should be drawn
- display status active, dormant etc.
这些信息maya都会自动的传给我们,所以,在代码中我们都必须按这样的格式来写!
第5,6部就是把MVectorArray转化成MDrawData数据结构,用的是getDrawData,然后把数据存到request实例中。
void MPxSurfaceShapeUI::getDrawData ( void * geom, MDrawData & data ) Sets up draw data for the shape. The draw data is meant to be a light weight class which can be used to pass geometry data through draw requests.
最后,就把request加到queue中就是了。
——————>
getDrawRequests并不是真正执行绘画的部分,它是maya环境->shape node 绘画之间的一个数据类型转换器,它把maya给shape node的信息转换成绘画所需要的数据结构。
所以,我们的MDrawRequest可以算是提供数据结构模板。
实例利用这个模板里的数据来画画,是在draw方法里面,maya自然会去调用它,并把request,以及view当参数传过去。
MDrawData data = request.drawData(); MVectorArray * geom = (MVectorArray*)data.geometry();
我们从request里面得到了drawData,这个data里面包括了maya环境信息:dag path,3d view,world 矩阵,以及一些显示状态。
然后就要调用openGL方法进行绘画。在绘画过程中还要考虑是否有activeComponent
在draw这里,它只是对于cv点的位置进行绘画,至于材质,颜色等等信息,都包含在request中,不再做修改,maya会取出queue里面的request里的材质,颜色数据,就像在getDrawRequests里面的这几行:
<pre>
MDagPath path = info.multiPath(); // path to your dag object
M3dView view = info.view();; // view to draw to
MMaterial material = MPxSurfaceShapeUI::material( path );
</pre>
所以说,draw只是画vertex(vertex data group也就是geometry data)
component的存在要影响绘画,因为有component的存在的话,我们就要对shape node重绘。(就是我们点选择或者其他选择模式下,shape node 的表现方式不一样)
component到底是什么呢?其实很简单,它是个索引类,我们对属性的操作其实一直是通过MPlug的,cv是属性,自然也不例外了。
只是maya在这里没有让我们麻烦的使用MPlug,毕竟cv的数据结构是固定的,每个cv都是MVector类型,没有其他,所以就不需要wrapper来再包裹一层了。
那么,我们需要什么来判断是否cv点被manipulator选中了呢?component在这里就做这个工作,我们每选中一个点,它就把这个点的序号加进去。
那么,这个索引库有什么用?那要在select方法里面用了,maya自然有方法支持这样的数据类型
——————>
component实际上就是索引库,只是maya很无良的在这里取了个这样的名字,component有零件之意,但是maya却不是给的实体,而是放的是索引。。一开始我以为所有的CV数据都是放在component里面的,结果呢。。他只是所索引库而不是database。。无良。。
(数据类型能告诉他骨子里卖什么药,算法可以隐藏,但是数据结构就能告诉人这个程序的脉络,而对这个数据结构实例的命名都是浮云。)
不过,我想关于component的使用涉及到selectionList的又一种应用,还是放到下一篇吧。
不过,应该知道的是,maya做了个简单说明:
they can be selected and manipulated, by associating the control point attributes with a component.
Components are objects (MObject’s) which contain two pieces of information, the type of component and the index values or range. For example, a mesh vertex component. This component represents the vertex (or “pnts”) attribute of a mesh shape
component是select的时候才有值,它存储的是索引,并且这个索引库有多种类型,也就是几重索引,就像数据库里面的,有时候primariy key有多个。