can anyone explain algorithm behind drawing a cylinder?

Started by
7 comments, last by diptyendu 15 years, 3 months ago
can anyone explain algorithm behind drawing a cylinder, as used in light tutorial for direct3D. I am relatively new to this gaming world, any help would be highly appreciated. Thanks in advance
Advertisement
Its not that difficult, basically i use two circle and connect them with faces
have a look at my code , sorry for source tags but i don't remeber how to put them

bool CreateCylinder( CMesh *Mesh,
int Size,
int Mode)
{

if ( Size < 0 ) Size = -Size;
if ( Size < 4 || Size==0 )
return false;

float minorStep ;
float a,du;
float px,py,pz;
float nx,ny,nz;
float d;
int i;

////////////////////////////////////////

Mesh->Reset();

Mesh->ReserveFileName("Cylinder.3df");

///////////////////////////////////////
// allocate vertex list

if ( Mesh->ReserveVertexBuffer( Size*Size )==false )
return false;

// allocating proper sized texcoords list
if ( Mesh->ReserveTexCoordBuffer( Size*Size )==false )
return false;

//////////////////////////////////////////
// allocating surfaces

if ( Mesh->ReserveSurfaceBuffer( Size*2 )==false )
return false;

/////////////////////////////////////////
// adding vertices

du=(1.0f/(float)Size);

minorStep = 2.0F * __PI *du;

a=0.0f;

for (i=0; i<Size; i++)
{

px = sin(a);
py= -1.0f;
pz = cos(a);

nx= px;
ny= py;
nz= pz;

d=sqrt( nx*nx+ny*ny+nz*nz);

nx/=d;
ny/=d;
nz/=d;

Mesh->AddVertex( px , py , pz ,nx,ny,nz );

/////////////////////////////

px = sin(a);
py= 1.0f;
pz = cos(a);

nx= px;
ny= py;
nz= pz;

d=sqrt( nx*nx+ny*ny+nz*nz);

nx/=d;
ny/=d;
nz/=d;

Mesh->AddVertex( px , py , pz ,nx,ny,nz );

a+=minorStep;
}

///////////////////////////////////
// last 2 triangles closing the mesh

px = sin(a);
py= -1.0f;
pz = cos(a);

nx= px;
ny= py;
nz= pz;

d=sqrt( nx*nx+ny*ny+nz*nz);

nx/=d;
ny/=d;
nz/=d;

Mesh->AddVertex( px , py , pz ,nx,ny,nz );

/////////////////////////////

px = sin(a);
py= 1.0f;
pz = cos(a);

nx= px;
ny= py;
nz= pz;

d=sqrt( nx*nx+ny*ny+nz*nz);

nx/=d;
ny/=d;
nz/=d;

Mesh->AddVertex( px , py , pz ,nx,ny,nz );

for ( i=0; i<2*Size; i+=2 )
{
Mesh->AddSurface( i+1,i ,i+2 );
Mesh->AddSurface( i+3,i+1,i+2 );
}

//////////////////////////////////////////////////////////
// capping size*2+2

switch ( Mode )
{

case _VT_CAPBOTH_ :

a=0.0f;

i=0;

for ( i=0; i< Size; i++ )
{
px = sin(a);
py= -1.0f;
pz = cos(a);

Mesh->AddVertex( px , py , pz ,0,-1,0 );

a+=minorStep;
}

px = sin(a);
py= -1.0f;
pz = cos(a);

Mesh->AddVertex( px , py , pz ,0,-1,0 );

Mesh->AddVertex( 0,-1,0 ,0,-1,0 );

for ( i=Size*2+2; i<Size*2+2+Size; i++ )
Mesh->AddSurface( i+1,i,3*Size+3 );

/////////////////////////////////////////////

a=0.0f;

for ( i=0; i< Size; i++ )
{
px = sin(a);
py= 1.0f;
pz = cos(a);

Mesh->AddVertex( px , py , pz ,0,1,0 );

a+=minorStep;
}

px = sin(a);
py= 1.0f;
pz = cos(a);

Mesh->AddVertex( px , py , pz ,0,1,0 );

Mesh->AddVertex( 0,1,0 ,0,1,0 );

for ( i=Size*3+4; i<Size*4+4; i++ )
Mesh->AddSurface( i,i+1,4*Size+5 );

break;

case _VT_CAPTOP_ :

a=0.0f;

for ( i=0; i< Size; i++ )
{
px = sin(a);
py= 1.0f;
pz = cos(a);

Mesh->AddVertex( px , py , pz ,0,-1,0 );

a+=minorStep;
}

px = sin(a);
py = 1.0f;
pz = cos(a);

Mesh->AddVertex( px , py , pz ,0,-1,0 );

Mesh->AddVertex( 0,1,0 ,0,-1,0 );

for ( i=Size*2+2; i<Size*2+2+Size; i++ )
Mesh->AddSurface( i,i+1,3*Size+3 );

break;

case _VT_CAPBOTTOM_ :

a=0.0f;

for ( i=0; i< Size; i++ )
{
px = sin(a);
py= -1.0f;
pz = cos(a);

Mesh->AddVertex( px , py , pz ,0,1,0 );

a+=minorStep;
}

px = sin(a);
py= -1.0f;
pz = cos(a);

Mesh->AddVertex( px , py , pz ,0,1,0 );

Mesh->AddVertex( 0,-1,0 ,0,1,0 );

for ( i=Size*2+2; i<Size*2+2+Size; i++ )
Mesh->AddSurface( i+1,i,3*Size+3 );

break;

}

//////////////////////////////////////////////

Mesh->Finalize();

///////////////////////////////////
// sets normal flag as computed

Mesh->SetBitFlag( _VT_NORMALS_COMPUTED_,true );

return true;
}
Thanks, but i was asking for the explanation of this code:



// Fill the vertex buffer. We are algorithmically generating a cylinder
// here, including the normals, which are used for lighting.
CUSTOMVERTEX* pVertices;
if( FAILED( g_pVB->Lock( 0, 0, ( void** )&pVertices, 0 ) ) )
return E_FAIL;
for( DWORD i = 0; i < 50; i++ )
{
FLOAT theta = ( 2 * D3DX_PI * i ) / ( 50 - 1 );
pVertices[2 * i + 0].position = D3DXVECTOR3( sinf( theta ), -1.0f, cosf( theta ) );
pVertices[2 * i + 0].normal = D3DXVECTOR3( sinf( theta ), 0.0f, cosf( theta ) );
pVertices[2 * i + 1].position = D3DXVECTOR3( sinf( theta ), 1.0f, cosf( theta ) );
pVertices[2 * i + 1].normal = D3DXVECTOR3( sinf( theta ), 0.0f, cosf( theta ) );
}
g_pVB->Unlock();



This code is used to generate a cylinder, and is used in the lighting tutorial of the microsoft direct3D samples, i am asking for the logic behind it.
The sin and cos, which are used to generate x and z coordinates of the vertices, will produce the circle given theta which goes from 0 to pi*2 (full circle in radians). For each iteration of i (in this case, 50 iterations), a single edge for a face of the cylinder is created. The edge's y coordinate goes from -1 to +1; this defines the cylinder's length.

Since the normal of a vertex on a cylinder slice is essentially the same as its normalized position, the x and z coordinates of the normal are the same except the y component which is zero - because the normals point directly outward from the cylinder surface.

The code in your last post does not cap the cylinder at either end.

Locking is a way to gain access to the internal data of buffers. You get a pointer to which you copy your stuff; then, you unlock the buffer so as to let the device use the data.

I think that the sample also uses an index buffer that basically tells the device which vertices to use for given triangles. I assume that Mesh::AddSurface mentioned in your first post adds 3 indices to the index buffer in order to specify the triangles.

Niko Suni

Thanks a lot for describing it, but still i cannot entirely build the idea in my mind about drawing the cylinder. It would be nice, if you can suggest me any article on the internet, of describing the concept with some visual representations.
I am clear about the locking and releasing of vertex buffers, i am just concerned about the formulas used to build the coordinates of individual vertices.
That code doesn not draw a cylinder, it creates one.

Sine/cosine are commonly used to describe the radius of a circle.

Assume we have our angles in radians (which range from -pi to pi, or sometims 0 to 2pi, but see wikipedia), then with the following you will get a point on the unit circle's radius:
angle = something between -PI and +PIu = cos (angle)v = sin (angle)


You can create more circles by multiplying u and v with a radius:
angle = something between -PI and +PIradius = arbitraryu = radius * cos (angle)v = radius * sin (angle)


Now, you can pack this one into a loop to produce a number of points on a circle's radius:

radius = arbitraryfor (angle=-PI; angle<PI; angle+=(2*PI)/numSegments)    u = radius * cos (angle)    v = radius * sin (angle)


You can use u,v as coordinates to initialise vertices to be passed to some graphics API. Now think about it: How can you define a cylinder with the circe code?
You just need to understand the relation of sine and cosine (sinf and cosf in the code) to the unit circle, and you will "get" the idea :)

See here for more info.

Niko Suni

Quote:Original post by v71_3
Its not that difficult, basically i use two circle and connect them with faces
have a look at my code , sorry for source tags but i don't remeber how to put them
*süpersnip*


Source-tags. Furthermore: What is all that supposed to do? Looks a bit waste, but maybe the source-tags reveal the secret [oh].
Thanks to all of you, now i do understand the algorithm behind generating a cylinder. I appreciate your help.

This topic is closed to new replies.

Advertisement