Below is an example demonstrating the use of the geometry pipeline to generate a geometric cylinder.
// Define an anonymous function; // serves as our main loop, // limits the scope of variables (function(){ /*********************************************************************/ // Number : A function to convert from meters/yards/feet/inches to centimeters function convertToCM( nVal, sFromUnit ) { switch( sFromUnit.lower() ){ case "m": return nVal * 100; case "yd": return nVal * 36.0 * 2.54; case "ft": return nVal * 12.0 * 2.54; case "in": return nVal * 2.54; } return nVal; }; /*********************************************************************/ // String : A function for finding a unique label in the scene function getUniqueLabel( sLabel ) { // Initialize var sUnqLabel = sLabel; // If a node by the same label already exists if( Scene.findNodeByLabel( sUnqLabel ) ){ // Create an array of the label parts var aLabel = sUnqLabel.split( " " ); // Initialize var sPreLabel = sUnqLabel; // Get the last label part var sLastPart = aLabel[ aLabel.length - 1 ]; // If the last label part is a number enclosed in parens if( sLastPart.startsWith( "(" ) && sLastPart.endsWith( ")" ) && !isNaN( sLastPart.substring( 1, sLastPart.length - 1 ) ) ){ // Get rid of the number aLabel.pop(); // Reconstruct the Label without the number sPreLabel = aLabel.join( " " ); } // Initialize a count var i = 2; // Until we cannot find a node with the label while( Scene.findNodeByLabel( String( "%1 (%2)" ).arg( sPreLabel ).arg( i ) ) ){ // Increment the count i += 1; } // Construct the unique Label sUnqLabel = String( "%1 (%2)" ).arg( sPreLabel ).arg( i ); } // Return the unique Label return sUnqLabel; }; /*********************************************************************/ // Get the user input var sOrigin = "Object Center"; // "World Center" var nSize = 10; var sSizeUnit = "cm"; // "m", "yd", "ft", "in" var nDiameter = 10; var sDiameterUnit = "cm"; var nSegments = 12; var nSides = 12; // Convert the input value to centimeters nSize = convertToCM( nSize, sSizeUnit ); nDiameter = convertToCM( nDiameter, sDiameterUnit ); // Sanity check the input values if ( nSize <= 0.0 || nDiameter <= 0.0 || nSegments < 1 || nSides < 3 ) { // We are done... return; } // Let the user know we are busy setBusyCursor(); // Create new node var oNode = new DzNode(); // Set the node name; // use a name that is consistent with the create primitive action oNode.setName( "Cylinder" ); // Build the label of the node var sLabel = String( "Cylinder %1x%2 %3%4 %5%6" ) .arg( nSides ) .arg( nSegments ) .arg( nSize ) .arg( sSizeUnit ) .arg( nDiameter ) .arg( sDiameterUnit ); oNode.setLabel( getUniqueLabel( sLabel ) ); // Create a new object var oObject = new DzObject(); // Set the object name; // use a name that is consistent with the create primitive action oObject.name = String( "pCylinder(%1_%2)%3_%4" ) .arg( nSize ) .arg( nDiameter ) .arg( nSides ) .arg( nSegments ); // Create a new polygonal shape var oFacetShape = new DzFacetShape(); // Set the shape name and label; // use a name that is consistent with the create primitive action oFacetShape.name = "Default"; oFacetShape.setLabel( oFacetShape.name ); // Create a new polygonal mesh var oFacetMesh = new DzFacetMesh(); // Create a new default material var oMaterial = new DzDefaultMaterial(); // Set the material name and label; // use a name that is consistent with the create primitive action oMaterial.name = "Default"; oMaterial.setLabel( oMaterial.name ); // Add the material to the shape oFacetShape.addMaterial( oMaterial ); // Begin editing the mesh oFacetMesh.beginEdit(); // Get the UV map var oMap = oFacetMesh.getUVs(); // Activate the material; all new geometry will be added to this oFacetMesh.activateMaterial( oMaterial.name ); // Declare some variables for generating the mesh var i, j, nNext; var x, y, z, nAngle, nSinAngle, nCosAngle; var bAtSeam = false; var vecUVsA = new DzVec3( 0, 0, 0 ); var vecUVsB = new DzVec3( 0, 0, 0 ); var nVerts = nSegments + 1; var nRadius = nDiameter / 2; // Pre-size the vertex array; faster than dynamic resizing oFacetMesh.preSizeVertexArray( nSides * nVerts + 2 ); // Create the center vertex and UV for the bottom oFacetMesh.addVertex( 0.0, 0.0, 0.0 ); vecUVsA.x = 0.25; vecUVsA.y = 0.75; oMap.appendPnt2Vec( vecUVsA ); // Create the center vertex and UV for the top oFacetMesh.addVertex( 0.0, nSize, 0.0 ); vecUVsA.x = 0.75; //vecUVsA.y = 0.75; oMap.appendPnt2Vec( vecUVsA ); // Create the vertices and UVs for the sides for( i = 0; i < nSides; i += 1 ){ nAngle = ((Math.PI * 2) * i) / nSides; nSinAngle = Math.sin( nAngle ); nCosAngle = Math.cos( nAngle ); x = nSinAngle * nRadius; z = nCosAngle * nRadius; // Create an extra UV for the bottom vecUVsA.x = (nSinAngle * 0.25) + 0.25; vecUVsA.y = (nCosAngle * 0.25) + 0.75; oMap.appendPnt2Vec( vecUVsA ); for( j = 0; j < nVerts; j += 1 ){ oFacetMesh.addVertex( x, nSize * j / nSegments, z ); vecUVsB.x = i / nSides; vecUVsB.y = (j / (nVerts - 1)) * 0.5; oMap.appendPnt2Vec( vecUVsB ); } // Create an extra UV for the top vecUVsA.x += 0.5; vecUVsA.y = -(vecUVsA.y - 0.75) + 0.75; oMap.appendPnt2Vec( vecUVsA ); } // Create UVs for the seam var nSeam = oMap.getNumValues(); vecUVsB.x = 1; for( i = 0; i < nVerts; i += 1 ){ vecUVsB.y = (i / (nVerts - 1)) * 0.5; oMap.appendPnt2Vec( vecUVsB ); } // Pre-size the facet array; faster than dynamic resizing oFacetMesh.preSizeFacets( nSides * (nSegments + 2) ); // Create the faces var nUVs = nVerts + 2; var aVertexIndices = new Array( 4 ); var aUvIndices = new Array( 4 ); for( i = 0; i < nSides; i += 1 ){ nNext = i + 1; if( nNext >= nSides ){ bAtSeam = true; nNext = 0; } aVertexIndices[0] = 0; aUvIndices[0] = 0; aVertexIndices[1] = nNext * nVerts + 2; aUvIndices[1] = nNext * nUVs + 2; aVertexIndices[2] = i * nVerts + 2; aUvIndices[2] = i * nUVs + 2; aVertexIndices[3] = -1; aUvIndices[3] = -1; oFacetMesh.addFacet( aVertexIndices, aUvIndices ); for( j = 0; j < nSegments; j += 1 ){ aVertexIndices[0] = i * nVerts + 2 + j; aUvIndices[0] = i * nUVs + 3 + j; aVertexIndices[1] = nNext * nVerts + 2 + j; aUvIndices[1] = bAtSeam ? nSeam + j : ( nNext * nUVs + 3 + j ); aVertexIndices[2] = nNext * nVerts + 3 + j; aUvIndices[2] = bAtSeam ? nSeam + j + 1 : ( nNext * nUVs + 4 + j ); aVertexIndices[3] = i * nVerts + 3 + j; aUvIndices[3] = i * nUVs + 4 + j; oFacetMesh.addFacet( aVertexIndices, aUvIndices ); } aVertexIndices[0] = 1; aUvIndices[0] = 1; aVertexIndices[1] = ( i + 1 ) * nVerts + 1; aUvIndices[1] = ( i + 1 ) * nUVs + 1; aVertexIndices[2] = ( nNext + 1 ) * nVerts + 1; aUvIndices[2] = ( nNext + 1 ) * nUVs + 1; aVertexIndices[3] = -1; aUvIndices[3] = -1; oFacetMesh.addFacet( aVertexIndices, aUvIndices ); } // Finish editing the mesh oFacetMesh.finishEdit(); // Set the mesh for the shape oFacetShape.setFacetMesh( oFacetMesh ); // Add the shape to the object oObject.addShape( oFacetShape ); // Add the object to the node oNode.setObject( oObject ); // Get the local bounding box var boxLocal = oNode.getLocalBoundingBox(); var vecMax = boxLocal.max; var vecMin = boxLocal.min; // If the user chose the object center for the origin if( sOrigin == "Object Center" ){ // Get the middle of the height of the box var nMid = (vecMax.y + vecMin.y) * 0.5; // Set the origin; default and current var vecOrigin = new DzVec3(0, nMid, 0); oNode.setOrigin( vecOrigin, true ); oNode.setOrigin( vecOrigin ); } // If the height of the bounding box is less than // 1 unit (1cm) tall, set it to be 1 unit tall if( vecMax.y < 1 ){ vecMax.y = 1; } // Set the end point; default and current var vecEndPoint = new DzVec3( 0, vecMax.y, 0 ); oNode.setEndPoint( vecEndPoint, true ); oNode.setEndPoint( vecEndPoint ); // Get the presentation for the node var oPresentation = oNode.getPresentation(); // If the node did not have a presentation, // create one and assign it to the node if( !oPresentation ){ oPresentation = new DzPresentation(); oNode.setPresentation( oPresentation ); } // Set the type of node oPresentation.type = "Prop"; // Add the node to the scene Scene.addNode( oNode ); // Let the user know we are done clearBusyCursor(); // Finalize the function and invoke })();