簡體   English   中英

通過 DirectX12 工具包進行挑選

[英]Picking via DirectX12 Tool Kit

我在嘗試使 3d 對象可通過鼠標單擊時遇到問題。 對於交叉點檢查,我使用光線投射。 找到的代碼,為我的解決方案移植:

准確采摘

bool RaySphereIntersect(Vector3, Vector3, float);

bool TestIntersection(Matrix projectionMatrix, Matrix viewMatrix, Matrix worldMatrix, Vector3 origin, float radius, int m_screenWidth, int m_screenHeight, int mouseX, int mouseY)
{
float pointX, pointY;
Matrix inverseViewMatrix, translateMatrix, inverseWorldMatrix;
Vector3 direction, rayOrigin, rayDirection;

bool intersect, result;

// Move the mouse cursor coordinates into the -1 to +1 range.
pointX = ((2.0f * (float)mouseX) / (float)m_screenWidth) - 1.0f;
pointY = (((2.0f * (float)mouseY) / (float)m_screenHeight) - 1.0f) * -1.0f;

// Adjust the points using the projection matrix to account for the aspect ratio of the viewport.
pointX = pointX / projectionMatrix._11;
pointY = pointY / projectionMatrix._22;

// Get the inverse of the view matrix.
inverseViewMatrix=XMMatrixInverse(NULL, viewMatrix);

// Calculate the direction of the picking ray in view space.
direction.x = (pointX * inverseViewMatrix._11) + (pointY * inverseViewMatrix._21) + inverseViewMatrix._31;
direction.y = (pointX * inverseViewMatrix._12) + (pointY * inverseViewMatrix._22) + inverseViewMatrix._32;
direction.z = (pointX * inverseViewMatrix._13) + (pointY * inverseViewMatrix._23) + inverseViewMatrix._33;

// Get the origin of the picking ray which is the position of the camera.
// Get the world matrix and translate to the location of the sphere.
// Now get the inverse of the translated world matrix.
inverseWorldMatrix= XMMatrixInverse(NULL, worldMatrix);

// Now transform the ray origin and the ray direction from view space to world space.
rayOrigin=XMVector3TransformCoord(origin, inverseWorldMatrix);
rayDirection=XMVector3TransformNormal(direction, inverseWorldMatrix);

// Normalize the ray direction.
rayDirection=XMVector3Normalize(rayDirection);



// Now perform the ray-sphere intersection test.
intersect = RaySphereIntersect(rayOrigin, rayDirection, radius);

if (intersect == true)
 return true;
else
 return false;

}



 bool RaySphereIntersect(Vector3 rayOrigin, Vector3 rayDirection, float radius)
 {
 float a, b, c, discriminant;
 // Calculate the a, b, and c coefficients.
 a = (rayDirection.x * rayDirection.x) + (rayDirection.y * rayDirection.y) + (rayDirection.z * rayDirection.z);
 b = ((rayDirection.x * rayOrigin.x) + (rayDirection.y * rayOrigin.y) + (rayDirection.z * rayOrigin.z)) * 2.0f;
 c = ((rayOrigin.x * rayOrigin.x) + (rayOrigin.y * rayOrigin.y) + (rayOrigin.z * rayOrigin.z)) - (radius * radius);

// Find the discriminant.
discriminant = (b * b) - (4 * a * c);

// if discriminant is negative the picking ray missed the sphere, otherwise it intersected the sphere.
 if (discriminant < 0.0f)
 return false;
 else
 return true;

 }

如何創建球體

D3DSphere(float x, float y, float z, float radius, float r, float g, float b, float a)  
{
this->x = x;
this->y = y;
this->z = z;

this->radius = radius;

this->shape = GeometricPrimitive::CreateSphere(radius*2.0f);

this->world = Matrix::Identity;
this->world = XMMatrixMultiply(this->world, Matrix::CreateTranslation(x, y, z));
this->index = vsphere;

d3dsphere[vsphere] = this;
vsphere++;
}

我如何調用 raycaster

void Game::LButtonUp(int x, int y)
{
Vector3 eye(camx, camy, camz);
Vector3 at(Vector3::Zero);
m_view = Matrix::CreateLookAt(eye, at, Vector3::UnitY);
for (int i = 0; i < vsphere; i++)
{
if (TestIntersection(m_projection, m_view, d3dsphere[i]->world, eye, d3dsphere[i]->radius, 800, 600, x, y))
{
MessageBoxW(NULL, L"LOL", L"It works", MB_OK);

break;
}
}

}

單擊沒有任何反應,但是如果我垂直於 XOY 旋轉相機,有時在球體附近單擊,會出現消息框。


更新

MessageBox 在攝像機角度上獨立出現,並且似乎正確地檢測到交叉點,但相對於 window 中心是鏡像的。 例如,如果球體位於(0, window.bottom-20)點,那么如果單擊(0, 20)點,我將獲得 MessageBox。

如果拾取射線的方向計算錯誤,如果它是為左手系統編寫的,而我使用右手系統怎么辦?

可能是因為右手系統,DirectX Tool Kit 中默認使用的系統 下一節來自 caster

pointX = ((2.0f * (float)mouseX) / (float)m_screenWidth) - 1.0f;
pointY = (((2.0f * (float)mouseY) / (float)m_screenHeight) - 1.0f) * -1.0f; 

應改為

pointX = (((2.0f * (float)mouseX) / (float)m_screenWidth) - 1.0f) * -1.0f;
pointY = (((2.0f * (float)mouseY) / (float)m_screenHeight) - 1.0f); 

重要的

由於深度獨立,該代碼也將出錯,即您可能位於您單擊的球體后面的 select 球體。 為了解決我更改了代碼:

float distance3(float x1, float y1, float z1, float x2, float y2, float z2)
{
float dx=x1-x2;
float dy=y1-y2;
float dz=z1-z2;
return sqrt(dx*dx+dy*dy+dz*dz);
}

void Game::LButtonUp(int x, int y)
{
Vector3 eye(camx, camy, camz);
Vector3 at(Vector3::Zero);
m_view = Matrix::CreateLookAt(eye, at, Vector3::UnitY);
int last_index=-1;
float last_distance=99999.0f;//set the obviously highest value, may happen in your scene

for (int i = 0; i < vsphere; i++)
{
if (TestIntersection(m_projection, m_view, d3dsphere[i]->world, eye, d3dsphere[i]->radius, 800, 600, x, y))
{
float distance=distance3(camx,camy,camz, d3dsphere[i]->x, d3dsphere[i]->y, d3dsphere[i]->z);
if(distance<last_distance)
{
last_distance=distance;
last_index=i;
}
}
}

d3dsphere[last_index];//picked sphere 
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM