这节教程是关于Pick(拾取技术的),程序的结构如下:
在看这节教程前先弄懂:(1)大概了解D3D11的渲染流水线
(2) D3D11教程三十七之FrustumCulling(视截体裁剪)上半节教程, 弄不懂也没关系,两节教程之间有一些联系,但是由于我们的教程简化模型,就算看不懂D3D11教程三十七之FrustumCulling(视截体裁剪)上半节教程也不影响这节教程的理解。
bool PickRayClass::Frame(int mouseX, int mouseY)
{
//计算在相机空间的射线
float vx = (2.0f*(float)mouseX / mScreenWidth - 1.0f) / mProjMatrix._11;
float vy = (-2.0f*(float)mouseY / mScreenHeight + 1.0f) / mProjMatrix._22;
mViewSpaceRayOrigin = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
mViewSpaceRayDir = XMFLOAT3(vx, vy, 1.0f); //是单位向量?
return true;
}
XMMATRIX ViewMatrix, InvViewMatrix,WorldMatrix,InvWorldMatrix;
XMVECTOR mLocalSpaceRayOrigin;
XMVECTOR mLocalSpaceRayRayDir;
//更新相机矩阵
mCamera->Render();
//获取相机矩阵和世界矩阵
ViewMatrix = mCamera->GetViewMatrix();
WorldMatrix = mD3D->GetWorldMatrix()*XMMatrixTranslation(SpherePosX, SpherePosY, SpherePosZ);
//获取相机矩阵的逆矩阵和世界矩阵的逆矩阵
InvViewMatrix = XMMatrixInverse(&XMMatrixDeterminant(ViewMatrix), ViewMatrix);
InvWorldMatrix = XMMatrixInverse(&XMMatrixDeterminant(WorldMatrix), WorldMatrix);
//将相机矩阵的逆矩阵与世界矩阵的逆矩阵相乘,得注意相机逆矩阵在前,世界逆矩阵在后
XMMATRIX InvMa = XMMatrixMultiply(InvViewMatrix, InvWorldMatrix);
//将射线的原点和方向向量从相机空间变到局部空间,局部空间物体的中心为(0.0f,0.0f,0.0f)
mLocalSpaceRayOrigin = XMVector3TransformCoord(ViewSpaceRayOrigin,InvMa);
mLocalSpaceRayRayDir = XMVector3TransformNormal(ViewSpaceRayDir, InvMa);
mLocalSpaceRayRayDir = XMVector3Normalize(mLocalSpaceRayRayDir);
float a, b, c,discriminant; //二次方程式系数和判别式
XMFLOAT3 m;
XMFLOAT3 dir;
XMStoreFloat3(&m, mLocalSpaceRayOrigin);
XMStoreFloat3(&dir, mLocalSpaceRayRayDir);
a = dir.x*dir.x + dir.y*dir.y + dir.z*dir.z; //a>0 二次系数为正
b = 2 * (m.x*dir.x + m.y*dir.y + m.z*dir.z);
c = (m.x*m.x + m.y*m.y + m.z*m.z)-radius*radius;
discriminant = b*b - 4 * a*c;
bool GraphicsClass::TestIntersection(FXMVECTOR ViewSpaceRayOrigin, FXMVECTOR ViewSpaceRayDir, float SpherePosX, float SpherePosY, float SpherePosZ, float radius)
{
XMMATRIX ViewMatrix, InvViewMatrix,WorldMatrix,InvWorldMatrix;
XMVECTOR mLocalSpaceRayOrigin;
XMVECTOR mLocalSpaceRayRayDir;
//更新相机矩阵
mCamera->Render();
//获取相机矩阵和世界矩阵
ViewMatrix = mCamera->GetViewMatrix();
WorldMatrix = mD3D->GetWorldMatrix()*XMMatrixTranslation(SpherePosX, SpherePosY, SpherePosZ);
//获取相机矩阵的逆矩阵和世界矩阵的逆矩阵
InvViewMatrix = XMMatrixInverse(&XMMatrixDeterminant(ViewMatrix), ViewMatrix);
InvWorldMatrix = XMMatrixInverse(&XMMatrixDeterminant(WorldMatrix), WorldMatrix);
//将相机矩阵的逆矩阵与世界矩阵的逆矩阵相乘,得注意相机逆矩阵在前,世界逆矩阵在后
XMMATRIX InvMa = XMMatrixMultiply(InvViewMatrix, InvWorldMatrix);
//将射线的原点和方向向量从相机空间变到局部空间,局部空间物体的中心为(0.0f,0.0f,0.0f)
mLocalSpaceRayOrigin = XMVector3TransformCoord(ViewSpaceRayOrigin,InvMa);
mLocalSpaceRayRayDir = XMVector3TransformNormal(ViewSpaceRayDir, InvMa);
mLocalSpaceRayRayDir = XMVector3Normalize(mLocalSpaceRayRayDir);
//下面计算世界空间,射线是否与球体相交
float a, b, c,discriminant; //二次方程式系数和判别式
XMFLOAT3 m;
XMFLOAT3 dir;
XMStoreFloat3(&m, mLocalSpaceRayOrigin);
XMStoreFloat3(&dir, mLocalSpaceRayRayDir);
a = dir.x*dir.x + dir.y*dir.y + dir.z*dir.z; //a>0 二次系数为正
b = 2 * (m.x*dir.x + m.y*dir.y + m.z*dir.z);
c = (m.x*m.x + m.y*m.y + m.z*m.z)-radius*radius;
discriminant = b*b - 4 * a*c;
if (discriminant >= 0) //至少一个交点
{
return true;
}
else
{
return false;
}
}