📄 mouseray.cpp
字号:
#include "d3dUtility.h"
HWND g_hwnd=0;
IDirect3DDevice9* Device = 0;
const int Width = 640;
const int Height = 480;
struct Ray // 射线结构
{
D3DXVECTOR3 _origin; // 射线起点
D3DXVECTOR3 _dirction; // 射线方向
};
struct BoundSphere // 绑定球
{
D3DXVECTOR3 _center; // 中心点
float radius; // 半径
};
LPD3DXMESH Sphere[2]; // 球mesh Mesh object.
bool m_bRotate[2]; // 2个旋转开关
float m_fAngle[2]; // 2个角度
BoundSphere m_boundSphere[2]; // 2个绑定球
Ray CalculateRay(int x, int y)// 计算拾取射线,传入鼠标的x和y,返回射线结构
{
float px=0.0f;
float py=0.0f;
//获取视口大小
D3DVIEWPORT9 vp;
//////////////////////////////////////////////////////////////////////////
//typedef struct _D3DVIEWPORT9 {
// DWORD X;
// DWORD Y; /* Viewport Top left */
// DWORD Width;
// DWORD Height; /* Viewport Dimensions */
// float MinZ; /* Min/max of clip Volume */
// float MaxZ;
//} D3DVIEWPORT9;
//////////////////////////////////////////////////////////////////////////
Device->GetViewport(&vp);
D3DXMATRIX proj;
Device->GetTransform(D3DTS_PROJECTION,&proj);//获取投影矩阵
//计算拾取射线,以下为数学公式转换而来
px=(((2.0f*x)/vp.Width)-1.0f)/proj._11;
py=(((-2.0f*y)/vp.Height)+1.0f)/proj._22;
Ray ray;
ray._origin = D3DXVECTOR3(0.0f,0.0f,0.0f); // 射线源点在中心
ray._dirction = D3DXVECTOR3(px,py,1.0f); // 方向指向通过xy转换的pxpy
return ray;
}
Ray TransformRay(Ray ray, D3DXMATRIX* T) // 转换射线,将射线转换到世界空间中
{
Ray transRay;
D3DXVec3TransformCoord(&transRay._origin,&ray._origin,T); //转换射线的起点,起点是按照点变换的w=1
D3DXVec3TransformNormal(&transRay._dirction,&ray._dirction,T);//转换射线的方向,方向是按照向量变换的w=0
D3DXVec3Normalize(&transRay._dirction,&transRay._dirction);//标准化向量
return transRay;
}
BOOL CheckIntersection(Ray* ray, BoundSphere* sphere) // 计算与球的相交
{
//计算t0与t1的值
D3DXVECTOR3 v = ray->_origin-sphere->_center; // 建立从原点指向球中心的向量
float b = 2.0f*D3DXVec3Dot(&ray->_dirction,&v);
float c = D3DXVec3Dot(&v,&v)-(sphere->radius*sphere->radius);
float n = (b*b)-(4.0f*c);
if (n<0.0f)
{
return false;
}
n = sqrtf(n);
float t0 = (-b+n)/2.0f;
float t1 = (-b-n)/2.0f;
//判断是否相交
if (t0>=0||t1>=0)
{
return true;
}
return false;
}
bool Setup()
{
D3DXMATRIX matRroj;
D3DXMatrixPerspectiveFovLH( &matRroj, D3DX_PI/4, 4.f/3.f, 1.f, 500.0f );
Device->SetTransform(D3DTS_PROJECTION, &matRroj);
// 更新视矩阵
D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3(13.0f, 13.0f, 13.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f) );
Device->SetTransform(D3DTS_VIEW, &matView);
Device->SetRenderState( D3DRS_LIGHTING, false ); // 关灯
Device->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);// 改为线框绘制
// 创建球 To create the sphere we simple call D3DXCreateSphere and the rest is done for us.
if(FAILED(D3DXCreateSphere(Device, 3.0f, 15, 15, &Sphere[0], NULL))) // 参数3,4是经纬度线条数量
return false;
// 创建球 To create the sphere we simple call D3DXCreateSphere and the rest is done for us.
if(FAILED(D3DXCreateSphere(Device, 3.0f, 25, 25, &Sphere[1], NULL)))
return false;
for(int i=0; i<2; ++i)
{
m_boundSphere[i]._center = D3DXVECTOR3(-5.0f + i*10.0f, 0.0f, 0.0f); // 设置绑定球中心点,与绘制球mesh的位置相同
m_boundSphere[i].radius = 3.0f; // 设置绑定球半径,应与上面的球模型半径相同
m_bRotate[i] = false; // 关闭旋转
m_fAngle[i] = 0.0f; // 赋值旋转角度为0
}
return true;
}
void Cleanup()
{
SAFE_RELEASE(Sphere[0]);
SAFE_RELEASE(Sphere[1]);
}
bool Display(float timeDelta)
{
if( Device )
{
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00888888, 1.0f, 0);
Device->BeginScene();
D3DXMATRIX matWorld;
for(int i=0; i<2; ++i)
{
if(m_bRotate[i])
m_fAngle[i] += 1.5f * timeDelta; // 更新角度
D3DXMatrixRotationY(&matWorld, m_fAngle[i]);
matWorld._41 = -5.0f + i*10.0f; // x 更新位置,也可使用平移矩阵只不过麻烦些,在这就直接改了
matWorld._42 = 0.0f; // y
matWorld._43 = 0.0f; // z
Device->SetTransform( D3DTS_WORLD, &matWorld );
Sphere[i]->DrawSubset(0);
}
Device->EndScene();
Device->Present(0, 0, 0, 0);
}
return true;
}
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_DESTROY:
::PostQuitMessage(0);
break;
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
::DestroyWindow(hwnd);
break;
case WM_LBUTTONDOWN:
{
POINT pt; // 定义点结构
GetCursorPos(&pt); // 获取当前鼠标位置
ScreenToClient(g_hwnd, &pt); // 屏幕位置转到窗口位置
Ray ray = CalculateRay(pt.x, pt.y); // 通过鼠标位置计算射线
D3DXMATRIX mat;
Device->GetTransform(D3DTS_VIEW, &mat); // 获取摄像机矩阵
D3DXMatrixInverse(&mat, NULL, &mat); // 取得摄像机矩阵的逆矩阵
ray = TransformRay(ray, &mat); // 将射线转换到世界空间中
for(int i=0; i<2; ++i)
{
if( CheckIntersection(&ray, &m_boundSphere[i]) )
m_bRotate[i] = true;
else
m_bRotate[i] = false;
}
}
break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE prevInstance,
PSTR cmdLine,
int showCmd)
{
if(!d3d::InitD3D(hinstance,
Width, Height, true, D3DDEVTYPE_HAL, &Device,g_hwnd))
{
::MessageBox(0, "InitD3D() - FAILED", 0, 0);
return 0;
}
if(!Setup())
{
::MessageBox(0, "Setup() - FAILED", 0, 0);
return 0;
}
d3d::EnterMsgLoop( Display );
Cleanup();
Device->Release();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -