Below is an example demonstrating the use of the geometry pipeline to generate a geometric sphere.
// 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 sUnit = "cm"; // "m", "yd", "ft", "in" var nSegments = 12; var nSides = 12; // Convert the input value to centimeters nSize = convertToCM( nSize, sUnit ); // Sanity check the input values if ( nSize <= 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( "Sphere" ); // Build the label of the node var sLabel = String( "Sphere %1x%2 %3%4" ) .arg( nSides ) .arg( nSegments ) .arg( nSize ) .arg( sUnit ); 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( "pSphere(%1)%2_%3" ) .arg( nSize ) .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; var bAtSeam = false; var vecUVs = new DzVec3( 0, 0, 0 ); var nVerts = nSegments - 1; var nPoleSegments = nSegments - 2; var nUvOffset = (nSides - 1) * 2; var nHalfSize = nSize / 2; // Pre-size the vertex array; faster than dynamic resizing oFacetMesh.preSizeVertexArray( nSides * nVerts + 2 ); // Create vertices for the poles oFacetMesh.addVertex( 0.0, 0.0, 0.0 ); oFacetMesh.addVertex( 0.0, nSize, 0.0 ); // Create UVs for the poles var nOffset = 0.5 / nSides; for( i = 0; i < nSides; i += 1 ){ vecUVs.x = i / nSides + nOffset; vecUVs.y = 0; oMap.appendPnt2Vec( vecUVs ); vecUVs.y = 1; oMap.appendPnt2Vec( vecUVs ); } // Create the vertices and UVs for the sides for( i = 0; i < nSides; i += 1 ){ nAngle = ((Math.PI * 2) * i) / nSides; x = Math.sin( nAngle ) * nHalfSize; z = Math.cos( nAngle ) * nHalfSize; vecUVs.x = i / nSides; for( j = 0; j < nVerts; j += 1 ){ nAngle = Math.PI * (j + 1) / nSegments; y = -Math.cos( nAngle ) * nHalfSize + nHalfSize; nSinAngle = Math.sin( nAngle ); oFacetMesh.addVertex( x * nSinAngle, y, z * nSinAngle ); vecUVs.y = (j + 1) / nSegments; oMap.appendPnt2Vec( vecUVs ); } } // Create UVs for the seam var nSeam = oMap.getNumValues(); vecUVs.x = 1; for( i = 0; i < nVerts; i += 1 ){ vecUVs.y = (i + 1) / nSegments; oMap.appendPnt2Vec( vecUVs ); } // Pre-size the facet array; faster than dynamic resizing oFacetMesh.preSizeFacets( nSides * (nPoleSegments + 2) ); var aVertexIndices = new Array( 4 ); var aUvIndices = new Array( 4 ); // Create the faces for( i = 0; i < nSides; i += 1 ){ nNext = i + 1; if( nNext >= nSides ){ bAtSeam = true; nNext = 0; } aVertexIndices[0] = 0; aUvIndices[0] = i * 2; aVertexIndices[1] = nNext * nVerts + 2; aUvIndices[1] = bAtSeam ? nSeam : aVertexIndices[1] + nUvOffset; aVertexIndices[2] = i * nVerts + 2; aUvIndices[2] = aVertexIndices[2] + nUvOffset; aVertexIndices[3] = -1; aUvIndices[3] = -1; oFacetMesh.addFacet( aVertexIndices, aUvIndices ); for( j = 0; j < nPoleSegments; j += 1 ){ aVertexIndices[0] = i * nVerts + 2 + j; aUvIndices[0] = aVertexIndices[0] + nUvOffset; aVertexIndices[1] = nNext * nVerts + 2 + j; aUvIndices[1] = bAtSeam ? nSeam + j : aVertexIndices[1] + nUvOffset; aVertexIndices[2] = nNext * nVerts + 3 + j; aUvIndices[2] = bAtSeam ? nSeam + j + 1 : aVertexIndices[2] + nUvOffset; aVertexIndices[3] = i * nVerts + 3 + j; aUvIndices[3] = aVertexIndices[3] + nUvOffset; oFacetMesh.addFacet( aVertexIndices, aUvIndices ); } aVertexIndices[0] = 1; aUvIndices[0] = i * 2 + 1; aVertexIndices[1] = i * nVerts + nVerts + 1; aUvIndices[1] = aVertexIndices[1] + nUvOffset; aVertexIndices[2] = nNext * nVerts + nVerts + 1; aUvIndices[2] = bAtSeam ? nSeam + nPoleSegments : aVertexIndices[2] + nUvOffset; 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 })();