c++ DirectX 11 - 3rd person camera - c++

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.

Related

OpenGL Perspective Camera

I am not sure why why code doesn't show a rotating cube. I am looking for the reason why. I think it has something to do with the perspective or view but I am not sure. I just need to understand why I can't get a simple cube onto the screen.
#include <iostream>
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
#include "LoadShader.hpp" // just a function in a header that returns a GLuint for a shaderProgram
#define FS1 "shader1.frag"
#define VS1 "shader1.vert"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <assimp/cimport.h>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;
// The MAIN function, from here we start the application and run the game loop
int main()
{
// Init GLFW
glfwInit( );
// Set all the required options for GLFW
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
glfwWindowHint( GLFW_RESIZABLE, GL_FALSE );
// Create a GLFWwindow object that we can use for GLFW's functions
GLFWwindow *window = glfwCreateWindow( WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr );
int screenWidth, screenHeight;
glfwGetFramebufferSize( window, &screenWidth, &screenHeight );
if ( nullptr == window )
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate( );
return EXIT_FAILURE;
}
glfwMakeContextCurrent( window );
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
if ( GLEW_OK != glewInit( ) )
{
std::cout << "Failed to initialize GLEW" << std::endl;
return EXIT_FAILURE;
}
glEnable( GL_DEPTH_TEST ) ;
//glDepthFunc( GL_LESS ) ;
// Define the viewport dimensions
glViewport( 0, 0, screenWidth, screenHeight );
//glMatrixMode(GL_PROJECTION);
// Set up vertex data (and buffer(s)) and attribute pointers
GLfloat vertices[ ] =
{ // verticies a0 // colors a1
// front
-1.0, -1.0, 1.0, .70f , 0.32f , 0.31f ,
1.0, -1.0, 1.0, .20f , 0.4f , 0.21f ,
1.0, 1.0, 1.0, .50f , 0.32f , 0.71f ,
-1.0, 1.0, 1.0, .60f , 0.62f , 0.11f ,
// back
-1.0, -1.0, -1.0, .30f , 0.87f , 0.60f ,
1.0, -1.0, -1.0, .30f , 0.87f , 0.f ,
1.0, 1.0, -1.0, .10f , 0.f , 0.60f ,
-1.0, 1.0, -1.0, .20f , 0.87f , 0.60f ,
// side Right
1.0f , 1.0 , 1.0 , .45f , .3f , .4f ,
1.0 , -1.0 , 1.0 , .5f , .8f, .1f ,
1.0 , -1.0 , -1.0 , .3f , .6f , .0f ,
1.0 , 1.0 , -1.0 , .45f , .87f , .53f ,
// left Side
-1.0f , 1.0 , 1.0 , .45f , .23f , .54f ,
-1.0 , -1.0 , 1.0 , .51f , .84f, .81f ,
-1.0 , -1.0 , -1.0 , .6f , .4f , .78f ,
-1.0 , 1.0 , -1.0 , .45f , .87f , .53f ,
//top
-1.f , 1.f , 1.f , .35f , .87f , .54f ,
-1.f , 1.f , -1.f , .45f , .98f, .92f ,
1.f , 1.f , 1.f , .50f , 0.f , .32f ,
1.f , 1.f , -1.f , 1.f , .72f , .87f ,
// bottom
-1.f , -1.f , 1.f , .35f , .87f , .54f ,
-1.f , -1.f , -1.f , .45f , .98f, .92f ,
1.f , -1.f , 1.f , .50f , .89f , .32f ,
1.f , -1.f , -1.f , 0.f , .72f , .87f
};
GLuint indices[ ] =
{
0 , 1 , 2 , 0 , 2 , 3 ,
4 , 5 , 6 , 4 , 6 , 7 ,
8 , 9 , 10 , 8 , 10 , 11 ,
12 , 13 , 14 , 12 , 14 , 15 ,
16 , 19 , 18 , 16 , 17 , 19 ,
20 , 23 , 22 , 20 , 21 , 23
} ;
int numOfIndices = sizeof( indices ) / sizeof ( GLuint ) ;
std::cout << numOfIndices << std::endl ;
GLuint VAO , VBO , EBO ;
glGenVertexArrays( 1 , &VAO ) ;
glBindVertexArray( VAO ) ;
glGenBuffers( 1 , &VBO ) ;
glBindBuffer( GL_ARRAY_BUFFER , VBO ) ;
glBufferData( GL_ARRAY_BUFFER , sizeof( vertices ) , vertices , GL_STATIC_DRAW ) ;
glVertexAttribPointer( 0 , 3 , GL_FLOAT , GL_FALSE , 6 * sizeof(GLfloat) , ( GLvoid * ) 0 ) ;
glEnableVertexAttribArray( 0 ) ;
glVertexAttribPointer( 1 , 3 , GL_FLOAT , GL_FALSE , 6 * sizeof(GLfloat) , (GLvoid*)(3 * sizeof(GL_FLOAT)) ) ;
glEnableVertexAttribArray( 1 ) ;
glGenBuffers( 1 , &EBO ) ;
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER , EBO ) ;
glBufferData( GL_ELEMENT_ARRAY_BUFFER , sizeof( indices ) , indices , GL_STATIC_DRAW ) ;
GLuint program = LoadShaders( VS1 , FS1 ) ;
glUseProgram( program ) ;
float rotationDegrees = 1.f ;
float fov = 1.0f ;
glm::mat4 view;
view = glm::lookAt(glm::vec3( 0.0f, 1.0f, -3.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 projectionMatrix = glm::perspective( fov , ( ( float ) HEIGHT ) / WIDTH , 1.f , 10.0f ) ;
glm::mat4 modelTransform = glm::translate( glm::mat4( 1.f ) , glm::vec3( .0f , -3.0f , -3.0f ) ) ;
glm::mat4 rotation = glm::rotate( glm::mat4(1.f) , rotationDegrees , glm::vec3( 1.f , 1.f , 0.f ) ) ;
//glm::mat4 rotation = glm::rotate( rotation1 , 30.f , glm::vec3( 0.f , 2.f , 0.f ) ) ;
glm::mat4 fullTransform = projectionMatrix * modelTransform * rotation ;
GLuint transformLocation = glGetUniformLocation( program , "uModelTranslate" ) ;
GLuint projectionLocation = glGetUniformLocation( program , "uProjectionMatrix" ) ;
//modelTransform = modelTransform * rotation ;
glUniformMatrix4fv( transformLocation , 1 , GL_FALSE , &modelTransform[0][0] ) ;
glUniformMatrix4fv( projectionLocation , 1 , GL_FALSE , &fullTransform[0][0] ) ;
bool canUp , canDown , canL , canR , canW , canS ,canA , canD , canQ , canE ;
canQ = true ;
canE = true ;
canD= true ;
canA = true ;
canUp = true ;
canS = true ;
canDown = true ;
canR = true ;
canL = true ;
canW = true ;
float nearF = 0.1f ;
float zZ = -3.0 ;
float yY = 1.0f ;
float xX = 0.f ;
while ( !glfwWindowShouldClose( window ) )
{
// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents( );
rotationDegrees += .0001f ;
if( rotationDegrees >= 360 )
{
rotationDegrees =0 ;
}
view = glm::lookAt(glm::vec3( yY , xX, zZ),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 rotation = glm::rotate( glm::mat4(1.f) , rotationDegrees , glm::vec3( 1.f , 1.f , 0.f ) ) ;
glm::mat4 projectionMatrix = glm::perspective(glm::radians(fov), (float) WIDTH / (float)HEIGHT , nearF, 10.0f);
glm::mat4 fullTransform = projectionMatrix * view * rotation ;
glUniformMatrix4fv( projectionLocation , 1 , GL_FALSE , &fullTransform[0][0] ) ;
// Render
// Clear the colorbuffer
glClearColor( 0.f, 0.f, 0.f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
if (glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS )
{
glfwSetWindowShouldClose(window,true);
}
if (glfwGetKey(window,GLFW_KEY_UP) == GLFW_PRESS && canUp )
{
canUp = false ;
fov += 1.f ;
std::cout << fov << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_UP) != GLFW_PRESS && !canUp )
{
canUp = true ;
}
if (glfwGetKey(window,GLFW_KEY_DOWN) == GLFW_PRESS && canDown)
{
canDown = false ;
fov += -1.f ;
std::cout << fov << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_DOWN) != GLFW_PRESS && !canDown)
{
canDown = true ;
}
if (glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS )
{
glfwSetWindowShouldClose(window,true);
}
if (glfwGetKey(window,GLFW_KEY_LEFT) == GLFW_PRESS && canL )
{
canL = false ;
nearF += 1.f ;
std::cout << nearF << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_LEFT) != GLFW_PRESS && !canL )
{
canL = true ;
}
if (glfwGetKey(window,GLFW_KEY_RIGHT) == GLFW_PRESS && canR)
{
canR = false ;
nearF += -1.f ;
std::cout << nearF << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_RIGHT) != GLFW_PRESS && !canR)
{
canR = true ;
}
if (glfwGetKey(window,GLFW_KEY_W) == GLFW_PRESS && canW)
{
canW = false ;
zZ += -1.f ;
std::cout << zZ << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_W) != GLFW_PRESS && !canW)
{
canW = true ;
}
if (glfwGetKey(window,GLFW_KEY_S) == GLFW_PRESS && canS)
{
canS = false ;
zZ += +1.f ;
std::cout << zZ << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_S) != GLFW_PRESS && !canS)
{
canS = true ;
}
if (glfwGetKey(window,GLFW_KEY_A) == GLFW_PRESS && canA)
{
canA = false ;
xX += +1.f ;
std::cout << xX << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_A) != GLFW_PRESS && !canA)
{
canA = true ;
}
if (glfwGetKey(window,GLFW_KEY_D) == GLFW_PRESS && canD)
{
canD = false ;
xX += -1.f ;
std::cout << xX << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_D) != GLFW_PRESS && !canD)
{
canD = true ;
}
if (glfwGetKey(window,GLFW_KEY_Q) == GLFW_PRESS && canQ)
{
canQ = false ;
yY += -1.f ;
std::cout << yY << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_Q) != GLFW_PRESS && !canQ)
{
canQ = true ;
}
if (glfwGetKey(window,GLFW_KEY_E) == GLFW_PRESS && canE)
{
canE = false ;
yY += 1.f ;
std::cout << yY << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_E) != GLFW_PRESS && !canE)
{
canE = true ;
}
//glUseProgram( program ) ;
glDrawElements( GL_TRIANGLES , numOfIndices , GL_UNSIGNED_INT , 0 ) ;
// Swap the screen buffers
glfwSwapBuffers( window );
}
glfwTerminate( );
return EXIT_SUCCESS;
}
The unit of the angle for glm::perspective and glm::rotate is radians. A field of view of 1° is far to small.
The translation component of the modelTransform matrix moves the object out of the viewing frustum and has to be reduced.
Furthermore I recommend to enable the Depth Test.
e.g.:
float rotationDegrees = 0.0f;
float fov = 90.0f;
float nearF = 0.1f;
float zZ = -3.0;
float yY = 1.0f;
float xX = 0.0f;
glEnable(GL_DEPTH_TEST);
while (!glfwWindowShouldClose(wnd))
{
glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), glm::radians(rotationDegrees), glm::vec3(1.0f , 1.0f , 0.0f)) ;
glm::mat4 modelTransform = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.5f, 0.0f)) ;
glm::mat4 view = glm::lookAt(glm::vec3(yY , xX, zZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 modelview = view * modelTransform * rotation;
glm::mat4 projectionMatrix = glm::perspective(glm::radians(fov), (float)WIDTH / (float)HEIGHT, nearF, 10.0f);
rotationDegrees += 1.0f;
glUniformMatrix4fv(transformLocation, 1, GL_FALSE, glm::value_ptr(modelview));
glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
// [...]
}
Vertex shader:
#version 330 core
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inColor;
out vec3 vertCol;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelTranslate;
void main()
{
vertCol = inColor;
gl_Position = uProjectionMatrix * uModelTranslate * vec4(inPos.xyz, 1.0);
}

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 );
}
}

DirectX11 Billboard not showing

I'm trying billboarding, however the billboard doesn't show when i use 'newWorld' i've tested to see if it was the way i was drawing the billboard, but it isn't, as when i changed to it's own local world, it appeared on screen.
// Calculate the rotation that needs to be applied to the billboard model to face the current camera position using the arc tangent function.
XMFLOAT3 CarPos = XMFLOAT3(Billboards->GetPosition().x, Billboards->GetPosition().y, Billboards->GetPosition().z);
XMFLOAT3 CamPos = XMFLOAT3(fCam->GetEye().x, fCam->GetEye().y, fCam->GetEye().z);
float angle;
float BBrotation;
XMMATRIX newWorld = XMLoadFloat4x4(&Billboards->GetWorld());
angle = atan2(CarPos.x - CamPos.x, CarPos.z - CamPos.z) * (180 / XM_PI);
BBrotation = angle * 0.0174532925f;
XMMatrixRotationY(BBrotation);
XMMatrixTranslation(CarPos.x, CarPos.y, CarPos.z);
XMMATRIX bbRotMatix = XMMatrixRotationY(BBrotation);
XMMATRIX bbCarPos = XMMatrixTranslation(CarPos.x, CarPos.y, CarPos.z);
newWorld = bbCarPos + bbRotMatix;
XMMATRIX bilworld = XMLoadFloat4x4(&Billboards->GetWorld());
cb.World = XMMatrixTranspose(newWorld);
_pImmediateContext->UpdateSubresource(_pConstantBuffer, 0, nullptr, &cb, 0, 0);
Billboards->Draw(_pd3dDevice, _pImmediateContext, _pTreeRV, _pSpecRV);
Billboards->SetTranslation(30.0f, 0.0f, 0.0f);
Billboards->SetRotation(-90.0f, 0.0f, 0.0);
The SimpleMath DirectXMath wrapper from the Directx Tool Kit has right-handed billboard functions you might find useful as reference.
inline Matrix Matrix::CreateBillboard( const Vector3& object, const Vector3& cameraPosition, const Vector3& cameraUp, const Vector3* cameraForward )
{
using namespace DirectX;
XMVECTOR O = XMLoadFloat3( &object );
XMVECTOR C = XMLoadFloat3( &cameraPosition );
XMVECTOR Z = XMVectorSubtract( O, C );
XMVECTOR N = XMVector3LengthSq( Z );
if ( XMVector3Less( N, g_XMEpsilon ) )
{
if ( cameraForward )
{
XMVECTOR F = XMLoadFloat3( cameraForward );
Z = XMVectorNegate( F );
}
else
Z = g_XMNegIdentityR2;
}
else
{
Z = XMVector3Normalize( Z );
}
XMVECTOR up = XMLoadFloat3( &cameraUp );
XMVECTOR X = XMVector3Cross( up, Z );
X = XMVector3Normalize( X );
XMVECTOR Y = XMVector3Cross( Z, X );
XMMATRIX M;
M.r[0] = X;
M.r[1] = Y;
M.r[2] = Z;
M.r[3] = XMVectorSetW( O, 1.f );
Matrix R;
XMStoreFloat4x4( &R, M );
return R;
}
inline Matrix Matrix::CreateConstrainedBillboard( const Vector3& object, const Vector3& cameraPosition, const Vector3& rotateAxis,
const Vector3* cameraForward, const Vector3* objectForward )
{
using namespace DirectX;
static const XMVECTORF32 s_minAngle = { 0.99825467075f, 0.99825467075f, 0.99825467075f, 0.99825467075f }; // 1.0 - XMConvertToRadians( 0.1f );
XMVECTOR O = XMLoadFloat3( &object );
XMVECTOR C = XMLoadFloat3( &cameraPosition );
XMVECTOR faceDir = XMVectorSubtract( O, C );
XMVECTOR N = XMVector3LengthSq( faceDir );
if (XMVector3Less(N, g_XMEpsilon))
{
if (cameraForward)
{
XMVECTOR F = XMLoadFloat3( cameraForward );
faceDir = XMVectorNegate( F );
}
else
faceDir = g_XMNegIdentityR2;
}
else
{
faceDir = XMVector3Normalize( faceDir );
}
XMVECTOR Y = XMLoadFloat3( &rotateAxis );
XMVECTOR X, Z;
XMVECTOR dot = XMVectorAbs( XMVector3Dot( Y, faceDir ) );
if ( XMVector3Greater( dot, s_minAngle ) )
{
if ( objectForward )
{
Z = XMLoadFloat3( objectForward );
dot = XMVectorAbs( XMVector3Dot( Y, Z ) );
if ( XMVector3Greater( dot, s_minAngle ) )
{
dot = XMVectorAbs( XMVector3Dot( Y, g_XMNegIdentityR2 ) );
Z = ( XMVector3Greater( dot, s_minAngle ) ) ? g_XMIdentityR0 : g_XMNegIdentityR2;
}
}
else
{
dot = XMVectorAbs( XMVector3Dot( Y, g_XMNegIdentityR2 ) );
Z = ( XMVector3Greater( dot, s_minAngle ) ) ? g_XMIdentityR0 : g_XMNegIdentityR2;
}
X = XMVector3Cross( Y, Z );
X = XMVector3Normalize( X );
Z = XMVector3Cross( X, Y );
Z = XMVector3Normalize( Z );
}
else
{
X = XMVector3Cross( Y, faceDir );
X = XMVector3Normalize( X );
Z = XMVector3Cross( X, Y );
Z = XMVector3Normalize( Z );
}
XMMATRIX M;
M.r[0] = X;
M.r[1] = Y;
M.r[2] = Z;
M.r[3] = XMVectorSetW( O, 1.f );
Matrix R;
XMStoreFloat4x4( &R, M );
return R;
}

Arches (2D or 3D) in OpenGL

I am trying to draw the shape shown below (in black) in OpenGL (for desktops, not mobile). I'd prefer it in 3D, but 2D would suffice as well. I will be mapping a texture to it as well. I've used triangle fans/strips for other things in the past and I imagine that's what I'd need to use here but I'm just not sure where to start on it. I've drawn the WHITE part before, but never the inverse (the black part). Any thoughts or guidance on what to use (triangle fan, triangle strip, some other odd OpenGL shape I probably didn't know existed, etc...)
Final Solution:
void draw_arch(GLfloat width, GLfloat height, GLint slices)
{
glPushMatrix();
GLfloat offset = 0.5f;
glScalef(width/2,height/(1+offset),1.0f);
glBegin(GL_QUADS);
for( unsigned int i = 0; i < slices; ++i ) {
float curAngle = ( ( i + 0 ) / (float)slices ) * 3.14159;
float nxtAngle = ( ( i + 1 ) / (float)slices ) * 3.14159;
glVertex2f( cos( curAngle ), sin( curAngle ) );
glVertex2f( cos( curAngle ), 1.0f + offset );
glVertex2f( cos( nxtAngle ), 1.0f + offset );
glVertex2f( cos( nxtAngle ), sin( nxtAngle ) );
}
glEnd();
glPopMatrix();
}
I can adjust the "offset" variable to make different looking arches, however in this application, I choose 0.5 to make it look the way I wanted it to!
Generate the top half of a circle and an offset above it and link the two with quads/triangles:
#include <GL/glut.h>
#include <cmath>
void glShape( const float height, unsigned int segs )
{
glBegin( GL_QUADS );
for( unsigned int i = 0; i < segs; ++i )
{
float curAngle = ( ( i + 0 ) / (float)segs ) * 3.14159;
float nxtAngle = ( ( i + 1 ) / (float)segs ) * 3.14159;
glVertex2f( cos( curAngle ), sin( curAngle ) );
glVertex2f( cos( curAngle ), 1 + height );
glVertex2f( cos( nxtAngle ), 1 + height );
glVertex2f( cos( nxtAngle ), sin( nxtAngle ) );
}
glEnd();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
glShape( 0.1f, 20 );
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
Probably not the minimal number of quads/triangles but it's quick and easy :)

Draw 2D thick arc using polygon in OpenGL

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();
}