硬件渲染插件概述
一个具体的例子
一个硬件渲染的节点插件是当做maya的DG节点来写的。基本的硬件渲染节点包含被当做input和output的属性;每个渲染节点必须有output,能在DG中被连接。硬件渲染节点也要重载资源创建,删除,绘制的函数。这些虚函数在下列情况调用。当maya检测到和几何图元关联的硬件渲染节点,并且指定使用此shader。可以在硬件渲染节点中使用多种方法来控制maya的最终显示,例如,实现标准的OpenGL渲染,扩展,像素、顶点shader,多通道渲染等。
实现硬件渲染插件
Maya场景的视口支持硬件渲染插件,场景视口有高质量交互渲染模式,硬件渲染器,UV编辑器。Maya支持的图元类型如下:
- 网格图形全都支持。
- Nurbs曲面仅在高质量渲染模式和使用gl接口的硬件渲染器 情况下支持。
原始接口如下:
virtual MStatus bind( const MDrawRequest& request, M3dView& view);
virtual MStatus unbind( const MDrawRequest& request, M3dView& view);
virtual MStatus geometry( const MDrawRequest& request, M3dView& view,
int prim, unsigned int writable, int indexCount,
const float** normalArrays, int colorCount,
const float** colorArrays, int texCoordCount,
const float** texCoordArrays);
第二接口或者gl方法如下:
virtual MStatus glBind( const MDagPath& shapePath );
virtual MStatus glUnbind( const MDagPath& shapePath);
virtual MStatus glGemetry( const MDagPath& shapePath, int glPrim, unsigned int writeMask,
int indexCount, const unsigned int* indexArray, int vertexCount,
const int* vertexIDs, const float* vertexArray, int normalCount,
const float** normalArrays, int colorCount, const float** colorArrays,
int texCoordCount, const float** texCoordArrays);
当比较函数参数时会发现这些接口很相似。最大的区别就是原始接口参数列表中的MDrawRequest和M3dView在第二接口中被替换成了MDagPath。如果硬件渲染节点不需要绘制信息(MDrawRequest object),建议实现功能更强大的gl版。
注意: 默认情况下,bind(),geometry(),unbind()会调用对应的gl版本接口。
实现硬件渲染插件
MPxHwShaderNode中有两个接口可以用来实现渲染器的硬件渲染节点。当对比参数时,你会发现这两个接口很像,但调用的方式却截然不同。
- bind/geometry/unbind接口
- 实现bind(),geometry()和unbind()方法就可以让maya场景显示器渲染硬件节点。三个方法的目的如下:
- bind用来设置OpenGL的状态和资源。
- geometry用来渲染效果。
- unbind用于保存OpenGL的状态和清理资源。
- 在此模式下仅支持mesh图形,以下步骤用于绘制:
- maya访问每个DAG节点,收集绘制请求。
- 绘制请求被保存在“透明”和“不透明”队列中。
- maya执行不透明绘制,无需排序。
- maya根据深度排序透明物体,执行绘制。
- maya绘制信息的请求响应如下:
- mesh图形接到绘制请求。
- 图形检测材质是否为硬件shader。
- 如果是硬件渲染节点,图元打包传送给节点的虚函数。
- 硬件渲染节点根据传进来的信息决定如何在屏幕上显示。
- 接口调用循序如下:
- for every shape
bind(...)
geometry(...)
unbind(...)
- for every shape
- 这种调用模式的结果是OpenGL的状态在bind()中设置,在geometry()中使用,在unbind()中存储。
- 此接口中会被传入M3dView,此参数用来设置绘制所用的图形内容。接口中实际操作要在beginGL()和endGL()中间实现。如下:
MStatus hwShader::bind( const MDrawRequest& request, M3dView& view){view.beginGL();// oprations....view.endGL();2. glbind/glGeometry/glUnbind接口}这些接口调用失败会导致程序崩溃。
实现上面三个方法,可以让maya视口显示硬件渲染的内容。三个接口的目的:接口中,虚函数调用循序如下:
- glBind 用来设置插件状态和资源。
- glGeometry用来设置OpenGL状态,渲染shader特效,存储OpenGL状态。
- glUnbind用于存储插件的状态和资源。
for every pass // 一个更新可能有多个pass{for every object{if glBind() has not been called for this refresh// 如果此更新没有调用glBind()glBind(...)glGeometry(....)}}for every objectglUnbind(...)
接口调用顺序的改动,会造成多方面的影响。使用这个接口,OpenGL的接口必须在glGeometry()中设置,而不是在glBind()中。现在glBind()仅用来加载资源,处理glGeometry()所用到的属性。3. 控制传入geometry、glGeometry的信息
geometry()和glGeometry()有很长的参数列表,包含描述渲染当前几何体必选和可选的顶点,面的shader。下面的方法控制哪些可选数据能传入shader。
4. 透明盒硬件渲染节点virtual int normalsVertex();virtual int colorsPerVertex();virtual int getColorSetNames( MStringArray& names);virtual int texCoordsPerVertex();virtual int getTexCoordSetNames( MStringArray& names);virtual bool provideVertexIDs();重要提示,如果请求的信息不存在,Null就会被传给shader。硬件渲染插件应该检测参数信息确保数据有效,避免Null。
5. 索引和geometry(),glGeometry()使用的稀疏数组当shader中有透明物体时,maya会对渲染信息进行排序。如果硬件渲染节点不支持透明,就重载下面的函数,返回false。virtual bool hasTransparency();
数据通过索引机制传给这些方法,这些方法有:virtual MStatus geometry( const MDrawRequest& request, M3dView& view, int prim, unsigned int writable, int indexCount, const unsigned int * indexArray, int vertexCount, const int * vertexIDs, const float * vertexArray, int normalCount, const float ** normalArrays, int colorCount, const float ** colorArrays, int texCoordCount, const float ** texCoordArrays);virtual MStatus glGeometry( const MDagPath& shapePath, int glPrim, unsigned int writeMask, int indexCount, const unsigned int* indexArray, int vertexCount, const int * vertexIDs, const float * vertexArray, int normalCount, const float ** normalArrays, int colorCount, const float ** colorArrays, int texCoordCount, const float ** texCoordArrays);用来索引的参数是 indexCount, 其包含indexArray的长度。保存在indexArray中的索引是在存取其他数据,例如,顶点,颜色,法线时用的。传入geometry()的好几个参数是数组的数组。其是指向指针的指针。这些数组可能是稀疏的。当一条信息请求的信息比实际有的还多时,就会发生稀疏现象。例如,getTexCoordSetNames()可以请求3个UV集合,但仅第一和第三个存在。这种情况,第二位置的数组就是空的,那么检测NUll确保数据有效就很重要。
6. blind data
硬件渲染节点使用baked的顶点网格数据来渲染是一种很有用的技术。这对两个geometry方法都有效。硬件渲染节点需实现 provideVertexIDs()来返回true。这步完成后,vertexIDs数组就包含了请求数据信息,vertexCount包含数组长度。如果使用MDrawRequest,可以用下面的方法来获取数据:
request.multiPath.node();
在gl版本的接口中,shapePath这个参数保存了mesh。联合使用vertex IDs和shape就可以使用MFnMesh获取blind data了。
7. 和maya其他部分互动
使用MPxHwShaderNode类就可以让硬件渲染节点和maya的其他部分互动了。请看下节。
8. 软件渲染和shader 样本
你实现硬件渲染节点的时候,可以采用能给软件渲染和属性编辑器中的shader样本一个合适输出的方式。基本方法就是实现compute()函数来影响 outColor属性。此步完成后,软件渲染和shader样本就不会是默认的黑色了。
可选方案,实现一个特殊的虚函数来直接绘制shader样本,方法如下:
virtual MStatus renderSwatchImage(MImage& image);
这个函数需要下面样本定义:
const MString UserClassify(“shader/surface/utility/:swatch/" + swatchName);
当插件调用MFnPlugin::registerNode()时,字符串就传给了maya。
9. UV贴图编辑器
类MPxHwShaderNode中有一个票函数来帮助硬件渲染节点和UV贴图编辑器交互。方法如下:
virtual MStatus getAvailableImages( const MString& uvSetName, MStringArray& imageNames);
virtual MStatus renderImage( const MString& imageName, const float region[2][2], int& imageWidth, int& imageHeight);
第一个方法getAvailableImages()是用来提供UV通道的列表,就可以在UV编辑器里看了。第二个方法renderImage(),当在UV编辑器里面选中一个通道时,就会调用。然后这个程序就会绘制图像了。
如果硬件渲染节点采用maya标准纹理,就没有必要实现此方法了。标准maya纹理,可以字节在纹理编辑器里查看。
10. HyperShade 窗口上的图标
你可以给硬件渲染节点提供一个图标,这样就可以在hypershade窗口显示。如果没有指定图标,默认图标是黑色的。想指定图标,做法如下:
创建名为render_nodeName.xpm的icon,例如render_hwPhongShader.xpm
将icon放在环境变量XBMLANGPATH路径下。
11. 拖动,放置动作
可以利用MPxDragAndDropBehavior来实现drap和drop行为。此类提供了很多方法在hypershade菜单里支持此功能。具体实现请查看hwPhongShaderBehavior.cpp
一个具体的例子
hwPhoneShader节点插件可以在Maya API Devkit中找到。这个例子中,用一张立方体环境贴图来实现每像素的phong渲染。当前,光源方向被固定在视角方向。
1. 加载和卸载插件
加载插件的过程很直接。 加载过程中,会构建样本分类字符串,同时需要drag和drop行为类。注意,drop和drag类并不需要唯一的MTypeId。 给一个字符串命名就足够了。
MStatus initializePlugin( MObject obj )
{
MStatus status;
const MString& swatchName = MHWShaderSwatchGenerator::initialize();
const MString UserClassify( "shader/surface/utility/:swatch/"+swatchName );
MFnPlugin plugin( obj, "Autodesk", "4.5", "Any");
status = plugin.registerNode( "hwPhongShader", hwPhongShader::id,
hwPhongShader::creator, hwPhongShader::initialize,
MPxNode::kHwShaderNode, &UserClassify );
if (!status)
{
status.perror("registerNode");
return status;
}
plugin.registerDragAndDropBehavior("hwPhongShaderBehavior",
hwPhongShaderBehavior::creator);
return MS::kSuccess;
}
卸载插件,注销Phong节点和drag、drop行为:
MStatus uninitializePlugin( MObject obj )
{
MStatus status;
MFnPlugin plugin( obj );
// Unregister all chamelion shader nodes
plugin.deregisterNode( hwPhongShader::id );
if (!status) {
status.perror("deregisterNode");
return status;
}
plugin.deregisterDragAndDropBehavior("hwPhongShaderBehavior");
return MS::kSuccess;
}
2. 初始化节点
硬件shader插件的initialize()中被DG用到的属性都是提前定义好的。添加标准颜色属性,基于其工作目的给于标记。首先,创建attribute,然后添加,最后设置attributes间的连接关系。此例子中为了性能将attribute设置为cached和内部的。
MStatus hwPhongShader::initialize(){MFnNumericAttribute nAttr;// Create input attributesaColor = nAttr.createColor( "color", "c");nAttr.setStorable(true);nAttr.setKeyable(true);nAttr.setDefault(0.1f, 0.1f, 0.1f);nAttr.setCached( true );nAttr.setInternal( true );aDiffuseColor = nAttr.createColor( "diffuseColor", "dc" );nAttr.setStorable(true);nAttr.setKeyable(true);nAttr.setDefault(1.f, 0.5f, 0.5f);nAttr.setCached( true );nAttr.setInternal( true );aSpecularColor = nAttr.createColor( "specularColor", "sc" );nAttr.setStorable(true);nAttr.setKeyable(true);nAttr.setDefault(0.5f, 0.5f, 0.5f);nAttr.setCached( true );nAttr.setInternal( true );// This is defined as a point, so that users can easily enter// values beyond 1.aShininess = nAttr.createPoint( "shininess", "sh" );nAttr.setStorable(true);nAttr.setKeyable(true);nAttr.setDefault(100.0f, 100.0f, 100.0f);nAttr.setCached( true );nAttr.setInternal( true );aGeometryShape = nAttr.create( "geometryShape", "gs", MFnNumericData::kInt );nAttr.setStorable(true);nAttr.setKeyable(true);nAttr.setDefault(0);nAttr.setCached( true );nAttr.setInternal( true );// create output attributes here// outColor is the only output attribute and it is inherited// so we do not need to create or add it.//// Add the attributes hereaddAttribute(aColor);addAttribute(aDiffuseColor);addAttribute(aSpecularColor);addAttribute(aShininess);addAttribute(aGeometryShape);attributeAffects (aColor, outColor);attributeAffects (aDiffuseColor, outColor);attributeAffects (aSpecularColor, outColor);attributeAffects (aShininess, outColor);return MS::kSuccess;}3. 计算方法下面简单介绍compute()方法的实现。此方法仅处理outColor属性。其他传入的属性会直接返回MS::kUnkownParameter,这样maya就会处理这些属性。否则,aDiffuseColor可以从datablock访问,这是用来设置输出颜色的。MStatus hwPhongShader::compute(const MPlug& plug,MDataBlock& block ){if ((plug != outColor) && (plug.parent() != outColor))return MS::kUnknownParameter;MFloatVector & color = block.inputValue( aDiffuseColor ).asFloatVector();// set output color attributeMDataHandle outColorHandle = block.outputValue( outColor );MFloatVector& outColor = outColorHandle.asFloatVector();outColor = color;outColorHandle.setClean();return MS::kSuccess;}通过实现这个方法,硬件渲染节点就可以在软件渲染里面实现了。如果不需要软件渲染,就不必实现了。4. bind, draw, unbind方法bind()和glBind()遵从下面的策略。 如果所需属性改变了或者Phong纹理没有设置,那么就会初始化Phong纹理。MStatus hwPhongShader::bind(const MDrawRequest& request, M3dView& view){if (mAttributesChanged || (phong_map_id == 0)){init_Phong_texture ();}return MS::kSuccess;}MStatus hwPhongShader::glBind(const MDagPath&){if ( mAttributesChanged || (phong_map_id == 0)){init_Phong_texture ();}return MS::kSuccess;}上面的例子中unbind()和glUnbind()方法仅仅返回了MS::kSucess,还有其他可选方法释放资源。在hwPhongShader例子中,消息是通过API检测的,资源会在新建文件,打开文件,打开文件索引等事件之前释放,具体内容请查看完整代码。MStatus hwPhongShader::unbind(const MDrawRequest& request, M3dView& view)
{// The texture may have been allocated by the draw; it's kept// around for use again. When scene new or open is performed this// texture will be released in releaseEverything().return MS::kSuccess;}MStatus hwPhongShader::glUnbind(const MDagPath&){// The texture may have been allocated by the draw; it's kept// around for use again. When scene new or open is performed this// texture will be released in releaseEverything().return MS::kSuccess;}geometry()和glGeometry()的设置很相似。为了避免复制代码,每个接口都调用独立接口draw()。MStatus hwPhongShader::geometry( const MDrawRequest& request,M3dView& view,int prim,unsigned int writable,int indexCount,const unsigned int * indexArray,int vertexCount,const int * vertexIDs,const float * vertexArray,int normalCount,const float ** normalArrays,int colorCount,const float ** colorArrays,int texCoordCount,const float ** texCoordArrays){MStatus stat = MStatus::kSuccess;if (mGeometryShape != 0)drawDefaultGeometry();elsestat = draw( prim, writable, indexCount, indexArray, vertexCount,vertexIDs, vertexArray, normalCount, normalArrays,colorCount, colorArrays,texCoordCount, texCoordArrays);return stat;}MStatus hwPhongShader::glGeometry(const MDagPath & path,int prim,unsigned int writable,int indexCount,const unsigned int * indexArray,int vertexCount,const int * vertexIDs,const float * vertexArray,int normalCount,const float ** normalArrays,int colorCount,const float ** colorArrays,int texCoordCount,const float ** texCoordArrays){MStatus stat = MStatus::kSuccess;if (mGeometryShape != 0)drawDefaultGeometry();elsestat = draw( prim, writable, indexCount, indexArray, vertexCount,vertexIDs, vertexArray, normalCount, normalArrays,colorCount, colorArrays,texCoordCount, texCoordArrays);return stat;}5. 绘制drawingdraw()函数的参数是为了将信息传送给OpenGL渲染用的。请注意indexArray是其他数组用来读取数据用的。MStatus hwPhongShader::draw(int prim,
unsigned int writable,int indexCount,const unsigned int * indexArray,int vertexCount,const int * vertexIDs,const float * vertexArray,int normalCount,const float ** normalArrays,int colorCount,const float ** colorArrays,int texCoordCount,const float ** texCoordArrays){if ( prim != GL_TRIANGLES && prim != GL_TRIANGLE_STRIP) {return MS::kFailure;}{glPushAttrib ( GL_ENABLE_BIT );glDisable ( GL_LIGHTING );glDisable ( GL_TEXTURE_1D );glDisable ( GL_TEXTURE_2D );// Setup cube map generationglEnable ( GL_TEXTURE_CUBE_MAP_EXT );glBindTexture ( GL_TEXTURE_CUBE_MAP_EXT, phong_map_id );glEnable ( GL_TEXTURE_GEN_S );glEnable ( GL_TEXTURE_GEN_T );glEnable ( GL_TEXTURE_GEN_R );glTexGeni ( GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );glTexGeni ( GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );glTexGeni ( GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );// Could modify the texture matrix here to do light tracking...glMatrixMode ( GL_TEXTURE );glPushMatrix ();glLoadIdentity ();glMatrixMode ( GL_MODELVIEW );}// Draw the surface.//{glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT );glEnableClientState( GL_VERTEX_ARRAY );glEnableClientState( GL_NORMAL_ARRAY );glVertexPointer ( 3, GL_FLOAT, 0, &vertexArray[0] );glNormalPointer ( GL_FLOAT, 0, &normalArrays[0][0] );glDrawElements ( prim, indexCount, GL_UNSIGNED_INT, indexArray );// The client attribute is already being popped. YouglPopClientAttrib();}{glMatrixMode ( GL_TEXTURE );glPopMatrix ();glMatrixMode ( GL_MODELVIEW );glDisable ( GL_TEXTURE_CUBE_MAP_EXT );glDisable ( GL_TEXTURE_GEN_S );glDisable ( GL_TEXTURE_GEN_T );glDisable ( GL_TEXTURE_GEN_R );glPopAttrib();}return MS::kSuccess;}6. 绘制样本绘制样本会调用虚函数renderSwatchImage()的具体实现,并利用MHardwareRenderer类来和MGeometryData,OpenGL协作来绘制图像。传送给renderSwatchImage()的MImage包含输出必须的width和height。MStatus hwPhongShader::renderSwatchImage( MImage & outImage )
{MStatus status = MStatus::kFailure;// Get the hardware renderer utility classMHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();if (pRenderer){const MString& backEndStr = pRenderer->backEndString();// Get geometry// ============unsigned int* pIndexing = 0;unsigned int numberOfData = 0;unsigned int indexCount = 0;MHardwareRenderer::GeometricShape gshape =MHardwareRenderer::kDefaultSphere;if (mGeometryShape == 2){gshape = MHardwareRenderer::kDefaultCube;}else if (mGeometryShape == 3){gshape = MHardwareRenderer::kDefaultPlane;}MGeometryData* pGeomData =pRenderer->referenceDefaultGeometry( gshape, numberOfData, pIndexing, indexCount );if( !pGeomData ){return MStatus::kFailure;}// Make the swatch context current// ===============================//unsigned int width, height;outImage.getSize( width, height );unsigned int origWidth = width;unsigned int origHeight = height;MStatus status2 = pRenderer->makeSwatchContextCurrent( backEndStr,width, height );if( status2 == MS::kSuccess ){// NOTE: Must be called after makeSwatchContextCurrent()glPushAttrib ( GL_ALL_ATTRIB_BITS );// Get camera// =========={// Get the camera frustum from the APIdouble l, r, b, t, n, f;pRenderer->getSwatchOrthoCameraSetting( l, r, b, t, n, f );glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho( l, r, b, t, n, f );glMatrixMode(GL_MODELVIEW);glLoadIdentity();// Rotate the cube a bit so we don't see it head onif (gshape == MHardwareRenderer::kDefaultCube)glRotatef( 45, 1.0, 1.0, 1.0 );else if (gshape == MHardwareRenderer::kDefaultPlane)glScalef( 1.5, 1.5, 1.5 );elseglScalef( 1.0, 1.0, 1.0 );}// Draw The Swatch// ===============drawTheSwatch( pGeomData, pIndexing, numberOfData, indexCount );// Read pixels back from swatch context to MImage// ==============================================pRenderer->readSwatchContextPixels( backEndStr, outImage );// Double check the outing going image size as image resizing// was required to properly read from the swatch contextoutImage.getSize( width, height );if (width != origWidth || height != origHeight){status = MStatus::kFailure;}else{status = MStatus::kSuccess;}glPopAttrib();}else{pRenderer->dereferenceGeometry( pGeomData, numberOfData );}}return status;}方法drawTheSwatch()在renderSwatchImage()中调用。其执行OpenGL来绘制图像。void
hwPhongShader::drawTheSwatch( MGeometryData* pGeomData,unsigned int* pIndexing,unsigned int numberOfData,unsigned int indexCount ){MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();if( !pRenderer ) return;if ( mAttributesChanged || (phong_map_id == 0)){init_Phong_texture ();}// Get the default background colorfloat r, g, b, a;MHWShaderSwatchGenerator::getSwatchBackgroundColor( r, g, b, a );glClearColor( r, g, b, a );glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glShadeModel(GL_SMOOTH);glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);glDisable ( GL_LIGHTING );glDisable ( GL_TEXTURE_1D );glDisable ( GL_TEXTURE_2D );{glEnable ( GL_TEXTURE_CUBE_MAP_EXT );glBindTexture ( GL_TEXTURE_CUBE_MAP_EXT, phong_map_id );glEnable ( GL_TEXTURE_GEN_S );glEnable ( GL_TEXTURE_GEN_T );glEnable ( GL_TEXTURE_GEN_R );glTexGeni ( GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );glTexGeni ( GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );glTexGeni ( GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );// Could modify the texture matrix here to do light tracking...glMatrixMode ( GL_TEXTURE );glPushMatrix ();glLoadIdentity ();glRotatef( 5.0, -1.0, 0.0, 0.0 );glRotatef( 10.0, 0.0, 1.0, 0.0 );glMatrixMode ( GL_MODELVIEW );}// Draw default geometry{if (pGeomData){glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT );float *vertexData = (float *)( pGeomData[0].data() );if (vertexData){glEnableClientState( GL_VERTEX_ARRAY );glVertexPointer ( 3, GL_FLOAT, 0, vertexData );}float *normalData = (float *)( pGeomData[1].data() );if (normalData){glEnableClientState( GL_NORMAL_ARRAY );glNormalPointer ( GL_FLOAT, 0, normalData );}if (vertexData && normalData && pIndexing )glDrawElements ( GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, pIndexing );glPopClientAttrib();// Release data referencespRenderer->dereferenceGeometry( pGeomData, numberOfData );}}{glMatrixMode ( GL_TEXTURE );glPopMatrix ();glMatrixMode ( GL_MODELVIEW );glDisable ( GL_TEXTURE_CUBE_MAP_EXT );glDisable ( GL_TEXTURE_GEN_S );glDisable ( GL_TEXTURE_GEN_T );glDisable ( GL_TEXTURE_GEN_R );}}
Improving the performance of hardware shadersMPxHwShaderNode包含的supportsBatching()方法,控制着是否将材质的绘制调用捆绑起来以减少渲染状态的转换。通过实现这个方法,并返回true,MPxHwShaderNode的每个前(bind/glBind)和后(unbind/glUnbind)每帧都会调用此方法,而不是每个图形每帧。默认情况下,此方法为了和以前的插件兼容会返回false。更多信息请查看此函数的文档。