Draw 2D thick arc using polygon in OpenGL - c++

I want to draw a thick Arc(something like colored segment of analog dial) using polygon. For that i have added vertices in polygon and its working fine for the outer circumference BUT its joining the ends for inner circumference(the concave side).
The same logic works fine if I add those vertices in Line, but that creates an empty/non-filled arc.
My logic of adding vertices is :
for( float i = m_segmentVertex.size() - 1; i < vCount; i++ )
{
float x1 = (m_segmentVertex[ i ].x ) * cosA - m_segmentVertex[ i ].y * sinA;
float y1 = (m_segmentVertex[ i ].x ) * sinA + m_segmentVertex[ i ].y * cosA;
addVertex( vec3( x1, y1, 0.0f ) );
}

Be aware that GL_POLYGON only works with convex polygons.
You'll have to triangulate concave polygons.

Try using a triangle fan and making the center of your dial the first point.
Possibly addVertex( vec3( 0.0f, 0.0f, 0.0f ) ); before your loop.
I'd also recommend making i an int or unsigned int, a float here doesn't make sense.

This is how I created the polygon dynamically by triangulating it :
//create thick colored segments
void CreateArcMesh( float sAngle, float eAngle, vec4 color, int thickness, int radius )
{
ObjectMeshDynamic meshObj = new ObjectMeshDynamic();
vec3 vertex[0];
float dAngle = ( ( eAngle - sAngle ) / ( VERTEX_COUNT / 2.0f ) );
float cosA = cos( DEG2RAD * dAngle );
float sinA = sin( DEG2RAD * dAngle );
meshObj.setMaterial( "material_base", "*" );
meshObj.setProperty( "surface_base", "*" );
meshObj.setMaterialParameter( "diffuse_color", color, 0 );
//Add the material on both side as the indices for Triangle strip start from last vertex added
Material material = meshObj.getMaterialInherit(0);
material.setTwoSided( 1 );
meshObj.addTriangleStrip( VERTEX_COUNT + 2 );
vec3 startPos = vec3( radius * cos( DEG2RAD * sAngle ), radius * sin( DEG2RAD * sAngle ), 0.0f );
vertex.append( startPos );
vec3 secondPos = vec3( ( radius - thickness ) * cos( DEG2RAD * sAngle ), ( radius - thickness ) * sin( DEG2RAD * sAngle ), 0.0f );
vertex.append( secondPos );
float x1 = startPos.x * cosA - startPos.y * sinA;
float y1 = startPos.x * sinA + startPos.y * cosA;
vertex.append( vec3( x1, y1, 0.0f ) );
x1 = secondPos.x * cosA - secondPos.y * sinA;
y1 = secondPos.x * sinA + secondPos.y * cosA;
vertex.append( vec3( x1, y1, 0.0f ) );
forloop( int k = 0 ; VERTEX_COUNT + 2 )
{
x1 = ( vertex[ vertex.size() - 2 ].x ) * cosA - vertex[ vertex.size() - 2 ].y * sinA;
y1 = ( vertex[ vertex.size() - 2 ].x ) * sinA + vertex[ vertex.size() - 2 ].y * cosA;
vertex.append( vec3( x1, y1, 0.0f ) );
meshObj.addVertex( vertex[k] );
}
vertex.clear();
meshObj.updateBounds();
meshObj.flush();
}

Related

How to bevel a stretched rectangle

I am able to bevel the corner of a rectangle.
When i strech the rectangle and than try to bevel it then the result does not look smooth , it should look like the rectangle on the right side.
How do i calculate the points for the trianlgle fan when the rectangle is streched ?
currently this is the way i am calculating the points for the Quarter circle.
std::vector<float> bevelData;
bevelData.push_back(0.0); // First set the centre of the rectangle to the data
bevelData.push_back(0.0);
bevelData.push_back(0.0);
bevelData.push_back(0);
bevelData.push_back(0);
bevelData.push_back(1);
bevelData.push_back(0);
bevelData.push_back(0);
for (int i = 0; i <= segments; ++i) {
float x, y;
float angle = start_angle + 0.5 * M_PI * i / static_cast<float>(segments);
x = circX + cos(angle) * rad; // circX is the centre of the circle as marked in yellow in the first image
y = circY + sin(angle) * rad; // circY is the centre of the circle as marked in yellow in the first image , rad is the radius of the circle
bevelData.push_back(x);
bevelData.push_back(y);
bevelData.push_back(0.0);
bevelData.push_back(0);
bevelData.push_back(0);
bevelData.push_back(1);
bevelData.push_back(0);
bevelData.push_back(0);
}
After applying soultion this is the result i get.
//Bevel Bottom Right
float rightWidthBottom = (width / 2) - rightBottomBevel;
float rightHeightBottom = (height / 2) - rightBottomBevel;
std::vector<float> bottomRightBevelData = draw_bevel(rightWidthBottom, rightHeightBottom, rightBottomBevel, 1, -1, iSegmentsRightBottom);
std::vector<float> SuperRectangle::draw_bevel(float p_x, float p_y, float rad, int dir_x, int dir_y , int segments)
{
std::vector<float> bevelData;
float c_x, c_y; // the center of the circle
float start_angle; // the angle where to start the arc
bevelData.push_back(0.0);
bevelData.push_back(0.0);
bevelData.push_back(0.0);
bevelData.push_back(0);
bevelData.push_back(0);
bevelData.push_back(1);
bevelData.push_back(0);
bevelData.push_back(0);
c_x = p_x * dir_x;
c_y = p_y * dir_y;
if (dir_x == 1 && dir_y == 1)
start_angle = 0.0;
else if (dir_x == 1 && dir_y == -1)
start_angle = -M_PI * 0.5f;
else if (dir_x == -1 && dir_y == 1)
start_angle = M_PI * 0.5f;
else if (dir_x == -1 && dir_y == -1)
start_angle = M_PI;
for (int i = 0; i <= segments; ++i) {
float x, y;
float angle = start_angle + 0.5 * M_PI * i / static_cast<float>(segments);
x = c_x + cos(angle) * rad;
y = c_y + sin(angle) * rad;
float fscale = (y / (float)(height / 2.0f));
x = (x + (strech * fscale));
bevelData.push_back(x);
bevelData.push_back(y);
bevelData.push_back(0.0);
bevelData.push_back(0);
bevelData.push_back(0);
bevelData.push_back(1);
bevelData.push_back(0);
bevelData.push_back(0);
}
return bevelData;
}
//////////////////////////////////////////////////////////////////
float xWidth = width / 2;
float yHeight = height / 2;
float TriangleRight[] = {
// positions // Normals // Texture Coord
0.0f , 0.0f , 0.0f , 0.0f,0.0,1.0, 0.0,0.0,
xWidth + strech , yHeight - rightTopBevel,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
xWidth - strech , -yHeight + rightBottomBevel,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
};
float TriangleLeft[] = {
// positions
0.0f , 0.0f , 0.0f , 0.0f,0.0,1.0, 0.0,0.0,
-xWidth + strech , yHeight - leftTopBevel ,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
-xWidth - strech , -yHeight + leftBottomBevel,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
};
float TriangleTop[] = {
// positions
0.0f , 0.0f , 0.0f , 0.0f,0.0,1.0, 0.0,0.0,
xWidth - rightTopBevel + strech , yHeight ,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
-xWidth + leftTopBevel + strech , yHeight,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
};
float TriangleBottom[] = {
// positions
0.0f , 0.0f , 0.0f , 0.0f,0.0,1.0, 0.0,0.0,
xWidth - rightBottomBevel - strech , -yHeight ,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
-xWidth + leftBottomBevel - strech , -yHeight,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
};
You've a rectangle with a width w and a height h
(-w/2, h/2) (w/2, h/2)
+----------------+
| |
| |
| |
| |
+----------------+
(-w/2, -h/2) (w/2, -h/2)
The points for the rounded corner of the rectangle are calculated by:
x = circX + cos(angle) * rad;
y = circY + sin(angle) * rad;
Then the rectangle is displaced by d. At the top d is add to the x component of the corner points and at the bottom d is subtracted from the x component of the corner points:
(-w/2 + d, h/2) (w/2 + d, h/2)
+----------------+
/ /
/ /
/ /
/ /
+----------------+
(-w/2 - d, -h/2) (w/2 - d, -h/2)
You have to apply the displacement d to the points along the arc, too. The displacement has to be scaled, in relation to the y coordinate of the point.
Points near the bottom edge have to be displaced by a larger scale, than points near the center of the left edge:
x = circX + cos(angle) * rad
y = circY + sin(angle) * rad
scale = y / (h/2)
x = x - d * scale

Pointer to STL container behaviour

I have this class:
class Model3D
{
public:
void AddVert( Vec3D vert ) { vertices.push_back( vert ); }
void AddTri( Vec3D *v_0, Vec3D *v_1, Vec3D *v_2 );
void Draw( HDC hdc );
std::vector<Vec3D> vertices;
std::vector<Triangle3D> polys;
};
Also relevant, the Triangle3D type is defined as follows: (it is small because it's not finished)
class Triangle3D
{
public:
Vec3D *verts[3];
};
Also, Here is AddTri()
void Model3D::AddTri( Vec3D *v_0, Vec3D *v_1, Vec3D *v_2 )
{
Triangle3D triangle;
triangle.verts[0] = v_0;
triangle.verts[1] = v_1;
triangle.verts[2] = v_2;
polys.push_back( triangle );
}
Vertices members are given initial values. Looking at these members in debug through the pointers in Triangle3D shows these values correctly
Finally, I attempt to alter the members of vertices here:
std::vector<Vec3D>::iterator j;
for (j = vertices.begin(); j != vertices.end(); ++j)
{
j->x = ( j->x ) / ( j->z );
j->y = ( j->y ) / ( j->z );
}
After this loop completes, using the debugger, if I inspect the vertices vector, the members are modified as hoped. Yet, when I inspect the pointers to these members in the Triangle3D class, they are unchanged. Why is this?
EDIT here is a snippet of vertices and triangles being added (defines a cube):
Model3D Cube( Vec3D center, int size )
{
Vec3D vert;
Model3D model;
vert.z = .5;
vert.x = center.x - (float)( 0.5f * size );
vert.y = center.y + (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x + (float)( 0.5f * size );
vert.y = center.y + (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x + (float)( 0.5f * size );
vert.y = center.y - (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x - (float)( 0.5f * size );
vert.y = center.y - (float)( 0.5f * size );
model.AddVert( vert );
vert.z = 1;
//center.x += 120;
//center.y += 120;
vert.x = center.x - (float)( 0.5f * size );
vert.y = center.y + (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x + (float)( 0.5f * size );
vert.y = center.y + (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x + (float)( 0.5f * size );
vert.y = center.y - (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x - (float)( 0.5f * size );
vert.y = center.y - (float)( 0.5f * size );
model.AddVert( vert );
//front
model.AddTri( &model.vertices[0], &model.vertices[1], &model.vertices[2] );
model.AddTri( &model.vertices[2], &model.vertices[3], &model.vertices[0] );
//top
model.AddTri( &model.vertices[4], &model.vertices[5], &model.vertices[1] );
model.AddTri( &model.vertices[1], &model.vertices[0], &model.vertices[4] );
//bottom
model.AddTri( &model.vertices[3], &model.vertices[2], &model.vertices[6] );
model.AddTri( &model.vertices[6], &model.vertices[7], &model.vertices[3] );
//left
model.AddTri( &model.vertices[4], &model.vertices[0], &model.vertices[3] );
model.AddTri( &model.vertices[3], &model.vertices[7], &model.vertices[4] );
//right
model.AddTri( &model.vertices[1], &model.vertices[5], &model.vertices[6] );
model.AddTri( &model.vertices[6], &model.vertices[2], &model.vertices[1] );
//back
model.AddTri( &model.vertices[5], &model.vertices[4], &model.vertices[7] );
model.AddTri( &model.vertices[7], &model.vertices[6], &model.vertices[5] );
return model;
}
And here is the Draw method:
void Model3D::Draw( HDC hdc )
{
std::vector<Triangle3D>::iterator i;
std::vector<Vec3D>::iterator j;
for (j = vertices.begin(); j != vertices.end(); ++j)
{
j->x = ( j->x ) / ( j->z );
j->y = ( j->y ) / ( j->z );
}
for (i = polys.begin(); i != polys.end(); ++i)
{
DrawLine( hdc, *i->verts[0], *i->verts[1], WHITE );
DrawLine( hdc, *i->verts[1], *i->verts[2], WHITE );
DrawLine( hdc, *i->verts[2], *i->verts[0], WHITE );
}
}

Page Roll effect

I want to create a page roll effect in a shader. So i have a XZ plane points with y=0. Now i assume a cylender with R radius and Inf. height is lied down on the plane with certain angle rotated in Y axis. See the image:
I want a equation so that paper can rolled over the sphere in the given XZ direction.
what I am doing is:
float2 currPoint = gl_Vertex.xz;
float2 normDir = normalize(-1, 0); //direction at which paper will start rolling out.
float cylRadius = 1.f;
float dist = sqrt(normDir.x *vi.x * vi.x + normDir.y *vi.y * vi.y);
float beta = dist / cylRadius;
float3 outPos = 0;
outPos.x = currPoint.x + N.x * cylRadius * sin(beta);
outPos.z = cylRadius * (1 -cos(beta));
outPos.y = currPoint.y + N.y * cylRadius * sin(beta);
but it only works in the case of normDir = normalize(-1, 0), in other cases result not as expected.
I got this.My implementation is based on Pawel's page Flip implimentation ( http://nomtek.com/page-flip-3d/ )
Here is the code in HLSL.
float DistToLine(float2 pt1, float2 pt2, float2 testPt)
{
float2 lineDir = pt2 - pt1;
float2 perpDir = float2(lineDir.y, -lineDir.x);
float2 dirToPt1 = pt1 - testPt;
return (dot(normalize(perpDir), dirToPt1));
}
float3 Roll(float2 pos ) //per vertex
{
float time = param1.z ;
float t = (time);
float2 A = float2( 0 , 1 ); //tweak these 4 variables for the direction of Roll
float2 B = float2( 5.f , 1 ); //
float2 C = float2( 1 , 0 ); //
float2 D = float2( 0 , 0 ); //
float2 P1 = lerp( B , A , time ) ;
float2 P2 = lerp( C , D , time ) ; ;
float2 N = normalize( float2(-(P2-P1).y , (P2-P1).x ) );
float dist = DistToLine(P1 , P2 , float2(pos.x , pos.y) );
float3 vOut;
if (dist > 0 )
{
float distFromEnd = DistToLine(C , B , float2(pos.x , pos.y) ) ;
float R = lerp( .1 , .13 , distFromEnd );
float2 p = pos - N * dist;
float alpha = dist / R;
float sinAlpha = R * sin(alpha);
vOut.x = p.x + N.x * sinAlpha;
vOut.y = p.y + N.y * sinAlpha;
vOut.z = (1 - cos(alpha)) * R;
}
else
{
vOut.x = pos.x;
vOut.y = pos.y;
vOut.z = 0;
}
return vOut;
}

c++ DirectX 11 - 3rd person camera

I'm trying to set a third person camera, but i'm lost with rotations. My rotation are working for the Y axis, but the others are moving strangely. This is my code :
XMMATRIX Camera2::Render()
{
return XMMatrixLookAtLH( XMLoadFloat3( &m_vPosition ), XMLoadFloat3( &m_vTargetPos ), XMLoadFloat3( &( XMFLOAT3( 0.0f, 1.0f, 0.0f ) ) ) );
}
void Camera2::Rotate( float fAngle, int nAxe )
{
float fToRad = 0.0174532925f;
fAngle *= fToRad;
if( nAxe == 0 )
{
XMFLOAT3 vPosition = m_vPosition;
m_vPosition.y = vPosition.y * cos( fAngle ) - vPosition.z * sin( fAngle );
m_vPosition.z = vPosition.y * sin( fAngle ) + vPosition.z * cos( fAngle );
}
else if( nAxe == 1 )
{
XMFLOAT3 vPosition = m_vPosition;
m_vPosition.z = vPosition.z * cos( fAngle ) - vPosition.x * sin( fAngle );
m_vPosition.x = vPosition.z * sin( fAngle ) + vPosition.x * cos( fAngle );
}
else if( nAxe == 2 )
{
XMFLOAT3 vPosition = m_vPosition;
m_vPosition.x = vPosition.x * cos( fAngle ) - vPosition.y * sin( fAngle );
m_vPosition.y = vPosition.x * sin( fAngle ) + vPosition.y * cos( fAngle );
}
}
And the code calling the camera functions ( x = 0, y = 1, z = 2 ) :
if( event.IsPushedKey( VK_F1 ) )
m_pCamera->Rotate( -3.0f, 0 );
else if( event.IsPushedKey( VK_F2 ) )
m_pCamera->Rotate( -3.0f, 1 );
else if( event.IsPushedKey( VK_F3 ) )
m_pCamera->Rotate( -3.0f, 2 );
else if( event.IsPushedKey( VK_F4 ) )
m_pCamera->Rotate( 3.0f, 0 );
else if( event.IsPushedKey( VK_F5 ) )
m_pCamera->Rotate( 3.0f, 1 );
else if( event.IsPushedKey( VK_F6 ) )
m_pCamera->Rotate( 3.0f, 2 );
Another question : When i start with XMFLOAT3( 0.0f, 0.0f, 0.0f ) as lookAt variable and have an x and y position equal to 0, nothing is draw. I need to set one of the axe of lookAt to 1.0f to see something. Why?
Your rotation matrix was wrong for rotation around Y-axis and Z-axis, here is the matrix.
Rotation around X-axis by theta(in radian)
Rotation around Y-axis by theta(in radian)
Rotation around Z-axis by theta(in radian)
Imagine the real world.
What happens when you try to focus on your own eye?
It's not possible.

Trying draw cylinder in directx through D3DXCreateCylinder

I am very novice in directx and want to know more, I was trying the code from directxtutorial.comI sthere any example\sample for D3DXCreateCylinder? Thanks
Alright then,
D3DXCreateCylinder can be used as such
LPD3DXMESH cylinder; // Define a pointer to the mesh.
D3DXCreateCylinder(d3ddev, 2.0f, 0.0f, 10.0f, 10, 10, &cylinder, NULL);
So what is going on?
d3ddev should be your device context that I will assume you have created.
The radius on the Negative Z.
The radius on the Positive Z.
The length of the shape on the Z axis.
The amount of polygons (or subdivisions) around the Z.
The amount of polygons on the Z axis.
The address of the pointer which holds the created mesh.
Tinker around with the values, experimenting can't hurt.
These resources will help supplement the answer provided:
https://directxtutorial.com/Tutorial11/B-A/BA2.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ff476880(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/hh780339(v=vs.85).aspx
By default, D3DXCreateCylinder API don't generate the texture coordinates for mapping a texture above the created cylindrical mesh.
Alternate you can formulate your own cylindrical Geometry like below for texture mapping:
for( DWORD i = 0; i < Sides; i++ )
{
FLOAT theta = ( 2 * D3DX_PI * i ) / ( Sides - 1 );
pVertices[2 * i + 0].position = D3DXVECTOR3(radius*sinf( theta ), -height, radius*cosf( theta ) );
pVertices[2 * i + 0].color = 0xffffffff;
pVertices[2 * i + 0].tu = ( ( FLOAT )i ) / ( Sides - 1 );
pVertices[2 * i + 0].tv = 1.0f;
pVertices[2 * i + 1].position = D3DXVECTOR3( radius*sinf( theta ), height, radius*cosf( theta ) );
pVertices[2 * i + 1].color = 0xff808080;
pVertices[2 * i + 1].tu = ( ( FLOAT )i ) / ( Sides - 1 );
pVertices[2 * i + 1].tv = 0.0f;
}