• Advertisement
Sign in to follow this  

Drawing Thick Lines

This topic is 2578 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys. Recently I had a need to draw thick lines using DirectX. I came up with a very simple solution that works well for my needs although it could be optimized a lot more.
I am sure most of you probably have a better solution but I figured I would share mine in case it might help someone.

Basically in my draw line method, there is an argument for the radius of the line. The default value if 0.0f. If the value is 0.0f, then I use a line primitive. Otherwise,
I create a cylinder mesh and transform it to represent the line. The following is my implementation.

// The drawLine method will draw a line from vert1 to vert2.
// By default or in the case that the radius is set to 0.0f, a line primitive will
// be used to represent the line. Otherwise, a cylinder mesh will be used to
// represent thick lines.
void CRenderEngine::drawLine(SVERTEX3D vert1, SVERTEX3D vert2, D3DXCOLOR color, float fRadius)
SVERTEX3D verts[] =

// Check the radius to determine if we should
// use a line or cylinder to represent our line.
if(fRadius > 0.0)
// When using a cylinder, first we need to check
// for the magnitude of our line to determine
// how long our cylinder should be.
LPD3DXMESH meshCylinder;
D3DXVECTOR3 vecDistance;
vecDistance.x = vert2.m_fX - vert1.m_fX;
vecDistance.y = vert2.m_fY - vert1.m_fY;
vecDistance.z = vert2.m_fZ - vert1.m_fZ;

float fLength = D3DXVec3Length(&vecDistance);

D3DXVec3Normalize(&vecDistance, &vecDistance);

// You can play with the slice and stack parameters to reduce the
// face count for optimization.
D3DXCreateCylinder(m_pGfxDev, fRadius, fRadius, fLength, 5, 5, &meshCylinder, NULL);

D3DXMATRIX matOldWorld;
D3DXMATRIX matWorld;
m_pGfxDev->GetTransform(D3DTS_WORLD, &matOldWorld);

// First we need to make our cylinder point in the
// direction of our line.
D3DXVECTOR3 vecFwd = vecDistance;
D3DXVECTOR3 vecUp = D3DXVECTOR3(0.0f,1.0f,0.0f);
D3DXVECTOR3 vecRight;
D3DXVec3Normalize(&vecFwd, &vecFwd);
D3DXVec3Cross(&vecRight, &vecFwd, &vecUp);
D3DXVec3Normalize(&vecRight, &vecRight);
D3DXVec3Cross(&vecUp, &vecFwd, &vecRight);
D3DXVec3Normalize(&vecUp, &vecUp);


matRot._11 = vecRight.x; matRot._12 = vecRight.y; matRot._13 = vecRight.z;
matRot._21 = vecUp.x; matRot._22 = vecUp.y; matRot._23 = vecUp.z;
matRot._31 = vecFwd.x; matRot._32 = vecFwd.y; matRot._33 = vecFwd.z;

D3DXMatrixMultiply(&matWorld, &matWorld, &matRot);

// We now need to place our cylinder's starting position
// at the first vector position.
D3DXMATRIX matTrans;
D3DXMatrixTranslation(&matTrans, vert1.m_fX, vert1.m_fY, vert1.m_fZ);
D3DXMatrixMultiply(&matWorld, &matWorld, &matTrans);

// Finally, DirectX creates the cylinder by placing the pivot or center
// of mass at the center of the cylinder. We need to multiply the
// cylinder's position by its forward vector times half its length.
vecFwd.x = matWorld._31; vecFwd.y = matWorld._32; vecFwd.z = matWorld._33;
D3DXVec3Scale(&vecFwd, &vecFwd, fLength/2);
matWorld._41 += vecFwd.x; matWorld._42 += vecFwd.y; matWorld._43 += vecFwd.z;

m_pGfxDev->SetTransform(D3DTS_WORLD, &matWorld);


m_pGfxDev->SetTransform(D3DTS_WORLD, &matOldWorld);
// Otherwise use a simple line primitive.
m_pGfxDev->DrawPrimitiveUP(D3DPT_LINELIST, 1, verts, sizeof(SVERTEX3D));

Share this post

Link to post
Share on other sites
The downfall of your implementation is that you are reconstructing a cylinder mesh for each line that you draw for every frame. To prevent this, you can create a single "unit-sized" cylinder (has a radius of 1.0 and a length of 1.0) and then reuse that mesh for every line that you draw. In order to create an appropriately sized line, you can scale the cylinder to the appropriate dimensions with a scaling transformation. As an added bonus, this allows you to store all your lines simply as a list or array of transformation matrices for this unit-cylinder, and you can draw all of your lines at once using instancing.

Share this post

Link to post
Share on other sites
You are exactly right. To keep things simple I just threw the instantiation in the same method but it would definitely be more efficient to have a member cylinder or mesh for that matter.

Share this post

Link to post
Share on other sites
Thank you for the sample.

It seems I am doing something wrong because I could not display the cylinder.

I declared

struct SVERTEX3D
float m_fX;
float m_fY;
float m_fZ;

SVERTEX3D v1, v2;
v1.m_fX = 1.0;
v1.m_fY = 1.0;
v1.m_fZ = 0;

v2.m_fX = -1.0;
v2.m_fY = -1.0;
v2.m_fZ = 0.0f;

then I called the function:

drawLine(v1, v2, D3DXCOLOR(0xff00000), 1.0f);

nothing appeared on the window

What could I be doing wrong?


Share this post

Link to post
Share on other sites
Additionally, I have wrote the createMaterial function as:

D3DMATERIAL9 createMaterial(D3DXCOLOR c1, D3DXCOLOR c2, D3DXCOLOR c3, float power)
static D3DMATERIAL9 mat;

// Set the RGBA for diffuse reflection.
mat.Diffuse.r = c1.r;
mat.Diffuse.g = c1.g;
mat.Diffuse.b = c1.b;
mat.Diffuse.a = 1.0f;

// Set the RGBA for ambient reflection.
mat.Ambient.r = c2.r;
mat.Ambient.g = c2.g;
mat.Ambient.b = c2.b;
mat.Ambient.a = 1.0f;

// Set the color and sharpness of specular highlights.
mat.Specular.r = c3.r;
mat.Specular.g = c3.g;
mat.Specular.b = c3.b;
mat.Specular.a = 1.0f;
mat.Power = power;

// Set the RGBA for emissive color.
mat.Emissive.r = 0.0f;
mat.Emissive.g = 0.0f;
mat.Emissive.b = 0.0f;
mat.Emissive.a = 0.0f;

return mat;


Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement