Jump to content
  • Advertisement
  • entries
    707
  • comments
    1173
  • views
    436430

3D Picking Demo

Sign in to follow this  
Programmer16

369 views

This demo isn't the greatest. First, there is no lighting, so you can't tell that the right triangle has been turned. Second, the right triangle is hanging half way off the screen.

Sorry!
Picking Demo

Heres the code:

#include
#include
#include
#pragma comment(lib, "d3d9")
#pragma comment(lib, "d3dx9")

#define SAFE_RELEASE(pCom) if(pCom){pCom->Release();pCom = 0;}

class Vertex
{
public:
float m_fX, m_fY, m_fZ;

Vertex(){}
Vertex(float fX, float fY, float fZ)
{
m_fX = fX;
m_fY = fY;
m_fZ = fZ;
}

static const float SIZE;
static const float FVF;
};

const float Vertex::SIZE = sizeof(Vertex);
const float Vertex::FVF = D3DFVF_XYZ;

HWND g_WndHandle = 0;
IDirect3D9* g_pDirect3D = 0;
IDirect3DDevice9* g_pDevice = 0;
D3DXMATRIX g_ViewMtx;
D3DXMATRIX g_ProjMtx;
D3DPRESENT_PARAMETERS g_PresentParams;
bool g_bSelected1 = false, g_bSelected2 = false;
float g_fMouseX = 0.0f, g_fMouseY = 0.0f;
bool g_bLButtonDown = false;

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);

void CreateRay(float fMouseX, float fMouseY, float fWidth, float fHeight, IDirect3DDevice9* pDevice, D3DXVECTOR3* pRayOrigin, D3DXVECTOR3* pRayDirection);
bool IntersectsTriangle(void* pVertices, unsigned int nOffset, const D3DXVECTOR3* pRayOrigin, const D3DXVECTOR3* pRayDirection, float* pHitDistance, IDirect3DDevice9* pDevice);

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
WNDCLASS WndClass;
ZeroMemory(&WndClass, sizeof(WNDCLASS));
WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WndClass.hCursor = LoadCursor(0, IDC_ARROW);
WndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
WndClass.hInstance = GetModuleHandle(0);
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = "PickingDemoV1";
if(!RegisterClass(&WndClass))
return 0;

g_WndHandle = CreateWindowEx(0, WndClass.lpszClassName, "Picking Demo", WS_POPUP | WS_VISIBLE, 0, 0, 800, 600, 0, 0, GetModuleHandle(0), 0);
if(!g_WndHandle)
return 0;

g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
if(!g_pDirect3D)
return 0;

ZeroMemory(&g_PresentParams, sizeof(D3DPRESENT_PARAMETERS));
g_PresentParams.BackBufferFormat = D3DFMT_A8R8G8B8;
g_PresentParams.BackBufferWidth = 800;
g_PresentParams.BackBufferHeight = 600;
g_PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_PresentParams.hDeviceWindow = g_WndHandle;
g_PresentParams.Windowed = true;
g_PresentParams.EnableAutoDepthStencil = true;
g_PresentParams.AutoDepthStencilFormat = D3DFMT_D16;
if(FAILED(g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_WndHandle, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_PresentParams, &g_pDevice)))
{
if(FAILED(g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_WndHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_PresentParams, &g_pDevice)))
{
g_pDirect3D->Release();
return 0;
}
}

D3DXMatrixIdentity(&g_ViewMtx);
D3DXMatrixIdentity(&g_ProjMtx);
D3DXMatrixLookAtLH(&g_ViewMtx, &D3DXVECTOR3(0.0f, 0.0f, -1.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
D3DXMatrixPerspectiveFovLH(&g_ProjMtx, D3DX_PI / 4.0f, 800 / 600, 1.0f, 1000.0f);
g_pDevice->SetTransform(D3DTS_VIEW, &g_ViewMtx);
g_pDevice->SetTransform(D3DTS_PROJECTION, &g_ProjMtx);
g_pDevice->SetFVF(D3DFVF_XYZ);

MSG Msg;
ZeroMemory(&Msg, sizeof(MSG));
while(1)
{
if(PeekMessage(&Msg, 0, 0, 0, PM_REMOVE))
{
if(Msg.message == WM_QUIT)
break;

TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
else
{
Vertex Polys1[] =
{
Vertex(-0.25f, -0.25f, 1.0f),
Vertex(-0.0f, 0.25f, 1.0f),
Vertex(0.25f, -0.25f, 1.0f),
};

Vertex Polys2[] =
{
Vertex(1.0f, -0.25f, 1.0f),
Vertex(1.25f, 0.25f, 3.0f),
Vertex(1.50f, -0.25f, 2.0f),
};

g_pDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff00ff00, 1.0f, 0);
g_pDevice->BeginScene();

D3DXVECTOR3 RayOrigin = D3DXVECTOR3(0.0f, 0.0f, 0.0f), RayDir = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
CreateRay(g_fMouseX, g_fMouseY, 800.0f, 600.0f, g_pDevice, &RayOrigin, &RayDir);
if(g_bLButtonDown)
g_bSelected1 = IntersectsTriangle(Polys1, 0, &RayOrigin, &RayDir, 0, g_pDevice);
if(g_bSelected1)
{
g_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
}
else
g_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
g_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 1, Polys1, Vertex::SIZE);

if(g_bLButtonDown)
g_bSelected2 = IntersectsTriangle(Polys2, 0, &RayOrigin, &RayDir, 0, g_pDevice);

if(g_bSelected2)
{
g_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
}
else
g_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
g_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 1, Polys2, Vertex::SIZE);
g_pDevice->EndScene();
g_pDevice->Present(0, 0, 0, 0);
}
}
SAFE_RELEASE(g_pDevice);
SAFE_RELEASE(g_pDirect3D);
return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
switch(nMsg)
{
case WM_KEYDOWN:
{
PostQuitMessage(0);
return 0;
}

case WM_LBUTTONDOWN:
{
g_fMouseX = LOWORD(lParam);
g_fMouseY = HIWORD(lParam);
g_bLButtonDown = true;
return 0;
}

case WM_LBUTTONUP:
{
g_bLButtonDown = false;
return 0;
}
}
return DefWindowProc(hWnd, nMsg, wParam, lParam);
}

void CreateRay(float fMouseX, float fMouseY, float fWidth, float fHeight, IDirect3DDevice9* pDevice, D3DXVECTOR3* pRayOrigin, D3DXVECTOR3* pRayDir)
{
D3DXMATRIX ViewMtx, ProjMtx;
pDevice->GetTransform(D3DTS_VIEW, &ViewMtx);
pDevice->GetTransform(D3DTS_PROJECTION, &ProjMtx);

D3DXMATRIX Matrix;
D3DXVECTOR3 Vector = D3DXVECTOR3(0.0f, 0.0f, 0.0f);

Vector.x = (((2.0f * fMouseX) / fWidth) - 1.0f) / ProjMtx._11;
Vector.y = -(((2.0f * fMouseY) / fHeight) - 1.0f) / ProjMtx._22;
Vector.z = 1.0f;

D3DXMatrixInverse(&Matrix, 0, &ViewMtx);
pRayDir->x = Vector.x * Matrix._11 + Vector.y * Matrix._21 + Vector.z * Matrix._31;
pRayDir->y = Vector.x * Matrix._12 + Vector.y * Matrix._22 + Vector.z * Matrix._32;
pRayDir->z = Vector.x * Matrix._13 + Vector.y * Matrix._23 + Vector.z * Matrix._33;
pRayOrigin->x = Matrix._41;
pRayOrigin->y = Matrix._42;
pRayOrigin->z = Matrix._43;
}

bool IntersectsTriangle(void* pVertices, unsigned int nOffset, const D3DXVECTOR3* pRayOrigin, const D3DXVECTOR3* pRayDirection, float* pHitDistance, IDirect3DDevice9* pDevice)
{
D3DXMATRIX InverseMtx;
D3DXMATRIX WorldMtx;
pDevice->GetTransform(D3DTS_WORLD, &WorldMtx);
D3DXMatrixInverse(&InverseMtx, 0, &WorldMtx);

D3DXVECTOR3 RayObjOrigin = D3DXVECTOR3(0.0f, 0.0f, 0.0f), RayObjDirection = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
D3DXVec3TransformCoord(&RayObjOrigin, pRayOrigin, &InverseMtx);
D3DXVec3TransformNormal(&RayObjDirection, pRayDirection, &InverseMtx);
D3DXVec3Normalize(&RayObjDirection, &RayObjDirection);

return D3DXIntersectTri((D3DXVECTOR3*)pVertices, &((D3DXVECTOR3*)pVertices)[nOffset + 1], &((D3DXVECTOR3*)pVertices)[nOffset + 2], &RayObjOrigin, &RayObjDirection, 0, 0, pHitDistance) != 0;
}





Thanks to ToyMaker for his tutorial.

Edit: Heres my updated code, with my new class :D

#include
#include
#include
#pragma comment(lib, "d3d9")
#pragma comment(lib, "d3dx9")

#define SAFE_RELEASE(pCom) if(pCom){pCom->Release();pCom = 0;}

class Vertex
{
public:
float m_fX, m_fY, m_fZ;

Vertex(){}
Vertex(float fX, float fY, float fZ)
{
m_fX = fX;
m_fY = fY;
m_fZ = fZ;
}

static const unsigned int SIZE;
static const unsigned int FVF;
};

const unsigned int Vertex::SIZE = sizeof(Vertex);
const unsigned int Vertex::FVF = D3DFVF_XYZ;

HWND g_WndHandle = 0;
IDirect3D9* g_pDirect3D = 0;
IDirect3DDevice9* g_pDevice = 0;
D3DXMATRIX g_ViewMtx;
D3DXMATRIX g_ProjMtx;
D3DPRESENT_PARAMETERS g_PresentParams;
bool g_bSelected1 = false, g_bSelected2 = false;
float g_fMouseX = 0.0f, g_fMouseY = 0.0f;
bool g_bLButtonDown = false;

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);

class MousePicker
{
IDirect3DDevice9* m_pDevice;
float m_fWidth, m_fHeight;
D3DXVECTOR3 m_RayOrigin, m_RayDirection;
public:
MousePicker()
{
m_pDevice = 0;
}

MousePicker(IDirect3DDevice9* pDevice)
{
m_pDevice = pDevice;
if(m_pDevice)
{
D3DVIEWPORT9 ViewPort;
IDirect3DDevice9* m_pDevice;
m_pDevice->GetViewport(&ViewPort);
m_fWidth = (float)ViewPort.Width;
m_fHeight = (float)ViewPort.Height;
}
}

void SetDevice(IDirect3DDevice9* pDevice)
{
m_pDevice = pDevice;
if(m_pDevice)
{
D3DVIEWPORT9 ViewPort;
m_pDevice->GetViewport(&ViewPort);
m_fWidth = (float)ViewPort.Width;
m_fHeight = (float)ViewPort.Height;
}
}

void CreateRay(float fMouseX, float fMouseY)
{
D3DXMATRIX ViewMtx, ProjMtx;
m_pDevice->GetTransform(D3DTS_VIEW, &ViewMtx);
m_pDevice->GetTransform(D3DTS_PROJECTION, &ProjMtx);

D3DXMATRIX Matrix;
D3DXVECTOR3 Vector = D3DXVECTOR3(0.0f, 0.0f, 0.0f);

Vector.x = (((2.0f * fMouseX) / m_fWidth) - 1.0f) / ProjMtx._11;
Vector.y = -(((2.0f * fMouseY) / m_fHeight) - 1.0f) / ProjMtx._22;
Vector.z = 1.0f;

D3DXMatrixInverse(&Matrix, 0, &ViewMtx);
m_RayDirection.x = Vector.x * Matrix._11 + Vector.y * Matrix._21 + Vector.z * Matrix._31;
m_RayDirection.y = Vector.x * Matrix._12 + Vector.y * Matrix._22 + Vector.z * Matrix._32;
m_RayDirection.z = Vector.x * Matrix._13 + Vector.y * Matrix._23 + Vector.z * Matrix._33;
m_RayOrigin.x = Matrix._41;
m_RayOrigin.y = Matrix._42;
m_RayOrigin.z = Matrix._43;
}

bool IntersectsTriangle(void* pVertices, unsigned int nOffset, float* pHitDistance)
{
D3DXMATRIX InverseMtx;
D3DXMATRIX WorldMtx;
m_pDevice->GetTransform(D3DTS_WORLD, &WorldMtx);
D3DXMatrixInverse(&InverseMtx, 0, &WorldMtx);

D3DXVECTOR3 RayObjOrigin = D3DXVECTOR3(0.0f, 0.0f, 0.0f), RayObjDirection = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
D3DXVec3TransformCoord(&RayObjOrigin, &m_RayOrigin, &InverseMtx);
D3DXVec3TransformNormal(&RayObjDirection, &m_RayDirection, &InverseMtx);
D3DXVec3Normalize(&RayObjDirection, &RayObjDirection);

return D3DXIntersectTri((D3DXVECTOR3*)pVertices, &((D3DXVECTOR3*)pVertices)[nOffset + 1], &((D3DXVECTOR3*)pVertices)[nOffset + 2], &RayObjOrigin, &RayObjDirection, 0, 0, pHitDistance) != 0;
}
};

MousePicker g_MousePicker;

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
WNDCLASS WndClass;
ZeroMemory(&WndClass, sizeof(WNDCLASS));
WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WndClass.hCursor = LoadCursor(0, IDC_ARROW);
WndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
WndClass.hInstance = GetModuleHandle(0);
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = "PickingDemoV1";
if(!RegisterClass(&WndClass))
return 0;

g_WndHandle = CreateWindowEx(0, WndClass.lpszClassName, "Picking Demo", WS_POPUP | WS_VISIBLE, 0, 0, 800, 600, 0, 0, GetModuleHandle(0), 0);
if(!g_WndHandle)
return 0;

g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
if(!g_pDirect3D)
return 0;

ZeroMemory(&g_PresentParams, sizeof(D3DPRESENT_PARAMETERS));
g_PresentParams.BackBufferFormat = D3DFMT_A8R8G8B8;
g_PresentParams.BackBufferWidth = 800;
g_PresentParams.BackBufferHeight = 600;
g_PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_PresentParams.hDeviceWindow = g_WndHandle;
g_PresentParams.Windowed = true;
g_PresentParams.EnableAutoDepthStencil = true;
g_PresentParams.AutoDepthStencilFormat = D3DFMT_D16;
if(FAILED(g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_WndHandle, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_PresentParams, &g_pDevice)))
{
if(FAILED(g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_WndHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_PresentParams, &g_pDevice)))
{
g_pDirect3D->Release();
return 0;
}
}

D3DXMatrixIdentity(&g_ViewMtx);
D3DXMatrixIdentity(&g_ProjMtx);
D3DXMatrixLookAtLH(&g_ViewMtx, &D3DXVECTOR3(0.0f, 0.0f, -1.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
D3DXMatrixPerspectiveFovLH(&g_ProjMtx, D3DX_PI / 4.0f, 800 / 600, 1.0f, 1000.0f);
g_pDevice->SetTransform(D3DTS_VIEW, &g_ViewMtx);
g_pDevice->SetTransform(D3DTS_PROJECTION, &g_ProjMtx);
g_pDevice->SetFVF(D3DFVF_XYZ);
g_MousePicker.SetDevice(g_pDevice);

MSG Msg;
ZeroMemory(&Msg, sizeof(MSG));
while(1)
{
if(PeekMessage(&Msg, 0, 0, 0, PM_REMOVE))
{
if(Msg.message == WM_QUIT)
break;

TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
else
{
Vertex Polys1[] =
{
Vertex(-0.25f, -0.25f, 1.0f),
Vertex(-0.0f, 0.25f, 1.0f),
Vertex(0.25f, -0.25f, 1.0f),
};

Vertex Polys2[] =
{
Vertex(1.0f, -0.25f, 1.0f),
Vertex(1.25f, 0.25f, 3.0f),
Vertex(1.50f, -0.25f, 2.0f),
};

g_pDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff00ff00, 1.0f, 0);
g_pDevice->BeginScene();

g_MousePicker.CreateRay(g_fMouseX, g_fMouseY);
if(g_bLButtonDown)
g_bSelected1 = g_MousePicker.IntersectsTriangle(Polys1, 0, 0);
if(g_bSelected1)
{
g_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
}
else
g_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
g_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 1, Polys1, Vertex::SIZE);

if(g_bLButtonDown)
g_bSelected2 = g_MousePicker.IntersectsTriangle(Polys2, 0, 0);

if(g_bSelected2)
{
g_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
}
else
g_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
g_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 1, Polys2, Vertex::SIZE);
g_pDevice->EndScene();
g_pDevice->Present(0, 0, 0, 0);
}
}
SAFE_RELEASE(g_pDevice);
SAFE_RELEASE(g_pDirect3D);
return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
switch(nMsg)
{
case WM_KEYDOWN:
{
PostQuitMessage(0);
return 0;
}

case WM_LBUTTONDOWN:
{
g_fMouseX = LOWORD(lParam);
g_fMouseY = HIWORD(lParam);
g_bLButtonDown = true;
return 0;
}

case WM_LBUTTONUP:
{
g_bLButtonDown = false;
return 0;
}
}
return DefWindowProc(hWnd, nMsg, wParam, lParam);
}

Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!