User Tools

Site Tools


Generate Cylinder

Summary

Below is an example demonstrating the use of the geometry pipeline to generate a geometric cylinder.

API Areas of Interest

Example

Generate_Cylinder.dsa
// 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
})();