Below is an example demonstrating the use of the geometry pipeline to convert geometry constructed of quadrilaterals into geometry constructed of adjacent triangles (both visually and in order of facet indices).
See Also: Geometry Detriangulate
// Define an anonymous function; // serves as our main loop, // limits the scope of variables (function(){ // Initialize 'static' variables that hold modifier key state var s_bShiftPressed = false; var s_bControlPressed = false; var s_bAltPressed = false; var s_bMetaPressed = false; // If the "Action" global transient is defined, and its the correct type if( typeof( Action ) != "undefined" && Action.inherits( "DzScriptAction" ) ){ // If the current key sequence for the action is not pressed if( !App.isKeySequenceDown( Action.shortcut ) ){ updateModifierKeyState(); } // If the "Action" global transient is not defined } else if( typeof( Action ) == "undefined" ) { updateModifierKeyState(); } /*********************************************************************/ // void : A function for updating the keyboard modifier state function updateModifierKeyState() { // Get the current modifier key state var nModifierState = App.modifierKeyState(); // Update variables that hold modifier key state s_bShiftPressed = (nModifierState & 0x02000000) != 0; s_bControlPressed = (nModifierState & 0x04000000) != 0; s_bAltPressed = (nModifierState & 0x08000000) != 0; s_bMetaPressed = (nModifierState & 0x10000000) != 0; }; /*********************************************************************/ // void : A function for printing only if debugging function debug() { // If we are not debugging if( !s_bAltPressed ){ // We are done... return; } // Convert the arguments object into an array var aArguments = [].slice.call( arguments ); // Print the array print( aArguments.join(" ") ); }; /*********************************************************************/ // Boolean : A function for testing whether or not a QObject instance // inherits one of a list of types function inheritsType( oObject, aTypeNames ) { // If the object does not define the 'inherits' function if( !oObject || typeof( oObject.inherits ) != "function" ){ // We are done... it is not a QObject return false; } // Iterate over the list of type names for( var i = 0, nTypes = aTypeNames.length; i < nTypes; i += 1 ){ // If the object does not inherit the 'current' type if( !oObject.inherits( aTypeNames[i] ) ){ // Next!! continue; } // Return the result return true; } // Return the result return false; }; /*********************************************************************/ // DzNode : A function for getting the root of a node function getRootNode( oNode ) { // If we have a node and it is a bone if( oNode && inheritsType( oNode, ["DzBone"] ) ){ // We want the skeleton return oNode.getSkeleton(); } // Return the original node return oNode; }; /*********************************************************************/ // DzObject : A function for getting the object for a node function getObjectForNode( oNode, bRoot ) { // Get the node var oContextNode = bRoot ? getRootNode( oNode ) : oNode; // If we do not have a root node if( !oContextNode ){ // We are done... return null; } // Get the object of the root node var oObject = oContextNode.getObject(); // If we do not have an object if( !oObject ){ // We are done... return null; } // Return the object return oObject; }; /*********************************************************************/ // DzShape : A function for getting the shape for a node function getShapeForNode( oNode, bRoot ) { // Get the object of the node var oObject = getObjectForNode( oNode, bRoot ); // If we do not have an object if( !oObject ){ // We are done... return null; } // Get the shape of the root node var oShape = oObject.getCurrentShape(); // If we do not have a shape if( !oShape ){ // We are done... return null; } // Return the shape return oShape; }; /*********************************************************************/ // DzGeometry : A function for getting the geometry for the root of a node function getGeometryForNode( oNode, bRoot, bCached ) { // Get the shape of the root node var oShape = getShapeForNode( oNode, bRoot ); // If we do not have a shape if( !oShape ){ // We are done... return null; } // If we are getting the cached geometry if( bCached ){ // Update the working mesh //oShape.invalidateWorkingMesh(); // Get the object of the root node var oObject = getObjectForNode( oNode, bRoot ); // Return the geometry return oObject.getCachedGeom(); } // Get the geometry of the root node var oGeometry = oShape.getGeometry(); // If we do not have a geometry if( !oGeometry ){ // We are done... return null; } // Return the geometry return oGeometry; }; /*********************************************************************/ // DzFacetMesh : A function for getting the facet mesh for a node function getFacetMeshForNode( oNode, bRoot, bCached ) { // Get the geometry of the node var oGeometry = getGeometryForNode( oNode, bRoot, bCached ); // If we do not have a facet mesh if( !inheritsType( oGeometry, ["DzFacetMesh"] ) ){ // We are done... return null; } // Return the geometry return oGeometry; }; /*********************************************************************/ // Array : A function for weeding out non-unique elements of an array function unique( vValue, nIndex, aArray ) { // return aArray.indexOf( vValue ) === nIndex; }; /*********************************************************************/ // Get the primary selection var oNode = getRootNode( Scene.getPrimarySelection() ); // If nothing is selected if( !oNode ){ // We are done... return; } // Get the mesh of the root node var oMesh = getFacetMeshForNode( oNode, true, false ); // If we do not have a mesh if( !oMesh ){ // We are done... return; } // Get the number of facets in the mesh var nFacets = oMesh.getNumFacets(); // Decalre working variable var oFaceGroup; // Get the number of face groups var nFaceGroups = oMesh.getNumFaceGroups(); // Pre-size the array of face group names var aFaceGroups = new Array( nFaceGroups ); // Iterate over the face groups for( var i = 0; i < nFaceGroups; i += 1 ){ // Get the 'current' face group oFaceGroup = oMesh.getFaceGroup( i ); // Capture the face group name aFaceGroups[ i ] = oFaceGroup.name; } // Decalre working variable var oSurface; // Get the number of surfaces var nSurfaces = oMesh.getNumMaterialGroups(); // Pre-size the array of surface names var aSurfaceNames = new Array( nSurfaces ); // Iterate over the surfaces for( var i = 0; i < nSurfaces; i += 1 ){ // Get the 'current' surface oSurface = oMesh.getMaterialGroup( i ); // Capture the surface name aSurfaceNames[ i ] = oSurface.name; } // Decalre working variables var oFacet; var aVertsA, aVertsB; var aUVsA, aUVsB; // Initialize the facet data index var nFacetDataIdx = 0; // Pre-size the array of facet data objects var aFacetDatas = new Array( nFacets * 2 ); // Iterate over all the facets for( var i = 0; i < nFacets; i += 1 ){ // Get the 'current' facet oFacet = oMesh.getFacet( i ); // Get the vertex indices for the first triangle aVertsA = [ oFacet.vertIdx1, oFacet.vertIdx2, oFacet.vertIdx3 ]; // Get the UV indices for the first triangle aUVsA = [ oFacet.uvwIdx1, oFacet.uvwIdx2, oFacet.uvwIdx3 ]; // Provide feedback debug( i, ":", aVertsA ); // Capture the facet data aFacetDatas[ nFacetDataIdx ] = { "v": aVertsA, "uv": aUVsA, "g": oFacet.faceGroupIndex, "m": oFacet.materialIndex }; // Provide feedback debug( "#", nFacetDataIdx, ":", JSON.stringify( aFacetDatas[ nFacetDataIdx ], null, "\t" ) ); // Increment the index nFacetDataIdx += 1; // If the facet is a triangle if( oFacet.isTri() ){ // Next!! continue; } // Get the vertex indices for the second triangle aVertsB = [ oFacet.vertIdx1, oFacet.vertIdx3, oFacet.vertIdx4 ]; // Get the UV indices for the second triangle aUVsB = [ oFacet.uvwIdx1, oFacet.uvwIdx3, oFacet.uvwIdx4 ]; // Provide feedback debug( i, ":", aVertsB ); // Capture the facet data aFacetDatas[ nFacetDataIdx ] = { "v": aVertsB, "uv": aUVsB, "g": oFacet.faceGroupIndex, "m": oFacet.materialIndex }; // Provide feedback debug( "#", nFacetDataIdx, ":", JSON.stringify( aFacetDatas[ nFacetDataIdx ], null, "\t" ) ); // Increment the index nFacetDataIdx += 1; } // Remove 'empty' elements from the list aFacetDatas = aFacetDatas.filter( Boolean ); // Get the current shape for the node var oShape = getShapeForNode( oNode, true ); // Get the working geometry for the current shape var oGeometry = oShape.getCurrentGeometry( DzShape.WorkingGeometry ); // Switch the mesh we are using to a copy of the working geometry - do not share vertices or facets; // we only want to modify the mesh for the selected node, not every instance in the scene oMesh = oGeometry.makeCopy( false, false ); // If the mesh does not inherit DzFacetMesh if( !oMesh.inherits( "DzFacetMesh" ) ){ // We are done... return; } // Declare working variable var oUVmap; // Define whether or not we want a new facet set var bNewFacetSet = false; // If we want a new facet set if( bNewFacetSet ){ // Get the current UV map oUVmap = oMesh.getUVs(); // Create a new facet set (LOD); capture the index var nFacetSet = oMesh.createFacetSet( "Quads from Tris" ); // If the active facet set is not our new one if( oMesh.getActiveFacetSet() != nFacetSet ){ // Make our facet set the active one oMesh.setActiveFacetSet( nFacetSet ); } } // Start editing the mesh oMesh.beginEdit(); // If we do not want a new facet set if( !bNewFacetSet ){ // Remove all existing facets; keep surfaces and face groups oMesh.removeAllFacets( false, false ); // Remove all existing UV sets oMesh.removeAllUVSets(); // If we want a new facet set } else { // Now that our facet set is created, // cause the existing UV map to be used oMesh.setUVList( oUVmap ); // Iterate over the list of face groups for( var i = 0; i < nFaceGroups; i += 1 ){ // Create the 'current' face group for our facet set oMesh.createFaceGroup( aFaceGroups[ i ] ); } // Iterate over the list of surfaces for( var i = 0; i < nSurfaces; i += 1 ){ // Create the 'current' surface for our facet set oMesh.createMaterialGroup( aSurfaceNames[ i ] ); } } // Declare working variable var oFacetData; // Get the number of facet data objects var nNewFacets = aFacetDatas.length; // Pre-size the number of facets for our facet set oMesh.preSizeFacets( nNewFacets ); // Iterate over the list of facet data objects for( var i = 0; i < nNewFacets; i += 1 ){ // Get the 'current' facet data object oFacetData = aFacetDatas[ i ]; // Create a new facet oFacet = new DzFacet(); // Assign vertex indices oFacet.vertIdx1 = oFacetData[ "v" ][ 0 ]; oFacet.vertIdx2 = oFacetData[ "v" ][ 1 ]; oFacet.vertIdx3 = oFacetData[ "v" ][ 2 ]; oFacet.vertIdx4 = -1; // Assign normal indices oFacet.normalIdx1 = oFacetData[ "v" ][ 0 ]; oFacet.normalIdx2 = oFacetData[ "v" ][ 1 ]; oFacet.normalIdx3 = oFacetData[ "v" ][ 2 ]; oFacet.normalIdx4 = -1; // Assign UV indices oFacet.uvwIdx1 = oFacetData[ "uv" ][ 0 ]; oFacet.uvwIdx2 = oFacetData[ "uv" ][ 1 ]; oFacet.uvwIdx3 = oFacetData[ "uv" ][ 2 ]; oFacet.uvwIdx4 = -1; // Assign face group oMesh.activateFaceGroup( oFacetData[ "g" ] ); // Assign surface oMesh.activateMaterial( oFacetData[ "m" ] ); // Add the facet to the mesh (for our facet set) oMesh.addFacet( oFacet ); } // We are done editing the mesh oMesh.finishEdit(); // Set the facet mesh oShape.setFacetMesh( oMesh ); // Finalize the function and invoke })();