Solved

# Drawing a thick line using a cylinder in directx

Posted on 2011-02-28
1,218 Views
I am a newbie to DirectX. I wanted to draw a thick line and I came across this solution on the Internet:

http://www.gamedev.net/topic/592823-drawing-thick-lines/

It is using a cylinder to draw the thick line. I tried using this code in the article, but I could not make my cylinder show on the screen. Can someone help me find what I am missing? Like what could be the SVERTEX3D and createMatrial function? Also can this function really work or what I am doing wrong?

Regards,
0
Question by:nabehs
• 8
• 7

LVL 12

Expert Comment

ID: 35003242
The function can work, its not the most efficient way to do things, but it gets the job done.

The math in the function only uses the x, y and z from the SVERTEX3D so the definition you give on the page should work OK when fRadius > 0.  You could just SVERTEX3D with D3DVECTOR, it wouldn't have any effect on that part of the function.

The code in the radius = 0 section uses IDirect3DDevice::SetMaterial, which takes a pointer to a D3DMATERIAL structure.  I guess the createMaterial initialises the Diffuse, Ambient and Specular parts of the structure as the same color and returns it by reference.  You could just use a pointer to a static D3DMATERIAL in the same way.

However, there dosen't seem to be much purpose to doing that because the code sets the vertex format to 3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1.  DirectX will read the vertex color from the diffuse component of the vertex, rather than the material.  However, for rendering to work with that vertex format, the SVERTEX3D would be defined something like this (following the naming style of the code).

``````typedef struct
{
float m_fX, m_fY,m_fZ;
D3DCOLOR m_cDiffuse;
float m_fU, m_fV;
}
SVERTEX3D;
``````
What output do you get?
0

LVL 6

Author Comment

ID: 35003294
Thank you. I just noticed that the shpere is drawn white. Since the background is also white nothing appears. When I change the background to a different color, the white line appears. Why? The material color is not white and the radius is not zero.
0

LVL 6

Author Comment

ID: 35003314
Also the line looks ugly. I changed the aspect ratio to screen_width / screen_height but still does not look smooth. I added the following code before drawing the sphere:

D3DXVECTOR3 vEyePt( 0.0f, 0.0f, -5.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView);

D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4.0f, float(g_iScreenWidth) / float(g_iScreenHeight), 1.0f, 1000.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj);

How can I make it smooth?
0

LVL 12

Expert Comment

ID: 35006059
The problem with white is because the material is not set before rendering the mesh.  Although (strangely) it's set before rendering a line, so I suspect the code has lines in the wrong place.  The SetMaterial() line should go before calling DrawSubset().

``````m_pGfxDev->SetMaterial(&createMaterial(color,color,color,1));
meshCylinder->DrawSubset(0);
``````
The smoothing problem is probably the normals in the mesh, use D3DXComputeNormals() to smooth mesh normals.  The mesh needs to be created with D3DFVF_NORMAL in its vertex format.  I'd guess D3DXCreateCylinder does that anyway though I've never used it.

The matrix setup you've done looks good.
0

LVL 12

Expert Comment

ID: 35006125
Shortly after posting that, I realised the material is set before rendering the mesh, further up the code.  I would test that createMaterial() is actually working, try defining a static red material and applying that before rendering the mesh.
0

LVL 6

Author Comment

ID: 35008979
1. Regarding the smoothness I figured out the problem. It is the aspect ratio. Because I resize the window after I create the device, the back buffer size is not as the window size, so stretching happens and distortion occurs. After I created the device after the window resizing, the lines were very smooth

2. Regarding the material, I was able to draw the lines with the material, but I have to set several render parameters such as lighting. If I do not set the lighting, the lines are drawn black.

The problem I am facing now is that the lines appear as 3D (cylinders) because of the lighting parameters. How I can set the material matrix so that I get solid flat line?

Thank you for all your contributions

0

LVL 12

Expert Comment

ID: 35011536
If the code isn't doing it now, set the material's Diffuse, Specular and Ambient colors to the same value.  I think I would turn lighting off while rendering the lines.  As in pDevice->SetRenderState (D3DRS_LIGHTING, FALSE).
0

LVL 6

Author Comment

ID: 35012506
I tried that, but I only got a white line regardless of the color I specify. Well I know it is a simple matter but I am doing something wrong for sure. If I turn on the lighting I start to see some color (not the color I specify), and the drawing is a 3D cylinder not a solid line
0

LVL 6

Author Comment

ID: 35012517
Do you think drawing a cylinder for a thick line is a bad idea? I am open to try other methods, but please help me with code samples
0

LVL 12

Accepted Solution

satsumo earned 500 total points
ID: 35013241
I have some code which renders thick lines as two triangles which always face the camera.  That less rendering than cylinders, but the code is quite complex.  Also cylinders interact differently with depth buffering.

Could you post some of your code so that I could check it for problems?  Or alternatively, I could describe faster code to render cylinders which doesn't use a mesh.  That gives more control over the rendering.
0

LVL 6

Author Comment

ID: 35020335
Here is the function I Use. Can I get the code you use using triangles. I hope you dont mind

void drawLine(Vertex2 vert1, Vertex2 vert2, D3DXCOLOR color, float fRadius)
{
Vertex2 verts[] =
{
vert1,
vert2,
};

return;

// Check the radius to determine if we should
// use a line or cylinder to represent our line.
{
// 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 = NULL;
D3DXVECTOR3 vecDistance;
vecDistance.x = vert2.x - vert1.x;
vecDistance.y = vert2.y - vert1.y;
vecDistance.z = vert2.z - vert1.z;

float fLength = D3DXVec3Length(&vecDistance);

D3DXVec3Normalize(&vecDistance, &vecDistance);

static D3DMATERIAL9 mat;

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

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

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

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

static D3DLIGHT9 g_pLight0;
g_pLight0.Type = D3DLIGHT_DIRECTIONAL;
g_pLight0.Direction = D3DXVECTOR3( 0.0f, 0.0f, -5.0f );

g_pLight0.Diffuse.r = color.r;
g_pLight0.Diffuse.g = color.g;
g_pLight0.Diffuse.b = color.b;
g_pLight0.Diffuse.a = 1.0f;

g_pLight0.Specular.r = color.r;
g_pLight0.Specular.g = color.g;
g_pLight0.Specular.b = color.b;
g_pLight0.Specular.a = 1.0f;

g_pd3dDevice->SetLight( 0, &g_pLight0 );
g_pd3dDevice->LightEnable( 0, TRUE );

g_pd3dDevice->SetRenderState( D3DRS_COLORVERTEX, FALSE );
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( 1.0f, 1.0f, 1.0f, 1.0f ) );

g_pd3dDevice->SetMaterial(&mat);

// You can play with the slice and stack parameters to reduce the
// face count for optimization.

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

// First we need to make our cylinder point in the
// direction of our line.
D3DXMATRIX matRot;
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);

D3DXMatrixIdentity(&matRot);

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;
D3DXMatrixIdentity(&matTrans);
D3DXMatrixTranslation(&matTrans, vert1.x, vert1.y, vert1.z);
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;

D3DXMATRIX matWorld2;
UINT  iTime  = 250;//GetTickCount() % 250;//1000;
float fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
D3DXMatrixRotationX( &matWorld2, fAngle );
g_pd3dDevice->SetTransform(D3DTS_WORLD, &(matWorld*matWorld2));

D3DXVECTOR3 vEyePt( 0.0f, 5.0f, -5.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView);

D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4.0f, (float(g_iScreenWidth) / float(g_iScreenHeight)), 1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj);

meshCylinder->DrawSubset(0);

g_pd3dDevice->SetTransform(D3DTS_WORLD, &matOldWorld);
meshCylinder->Release();
}
}
0

LVL 6

Author Comment

ID: 35023871
I need to use your function (two triangles) into my code and I can pay you for it. this also opens an opportunity for us to cooperate on future issues and you get paid for them. What do you think? However, I need to check the function so if you can send me a sample executable that is using this function (draws multiple thick lines in different directions). No need to send me the code now. Just send me the exe and I will check it, then send you the money and you email me the code of the sample.

0

LVL 12

Expert Comment

ID: 35026251
It's against the terms of EE for experts to use the site to bid for work.  The site doesn't mind if work comes from the questions, they simply want to avoid the site becoming a marketplace.  I will use the e-mail address you give.
0

LVL 6

Author Comment

ID: 35026625
My apology for this. I did not know it is against the rules. The moderator can remove my comment if they want. But I will contact via private email.
0

LVL 12

Expert Comment

ID: 35027087
I don't think your comment is a problem, the site has the Hire Me function to allows people to discuss working.  When I began using the site I offered to write a program for someone, assuming they paid for my time.  I was told that was against the policy of the site.  I don't use the site to look for work so it's not a problem for me.
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question