我现在被我的 RubiksCube 项目困住了。
我想要实现的目标:在左键单击时检查是否单击了单个 Mini-Cubie。 (点击时立方体可能会旋转)
其他魔方类的代码可以正常工作。 我们需要自己用数学公式计算函数。
当前问题:
我的总体想法是保护每一层的 4 个角点的坐标,在旋转时更新它们的位置并在这些位置的帮助下检查射线的交点
void MergedCube::Render(float aspectRatio)
{
m_viewProject = glm::perspective(glm::radians(45.0f), aspectRatio, 0.1f, 100.0f) *
glm::lookAt(glm::vec3(0.0f, 0.0f, -9.0f),
glm::vec3(0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)) *
glm::mat4_cast(m_orientationQuaternion);
compound = glm::translate(m_viewProject, (glm::vec3(1, 1, 1) - 1.0f));
// Updating the local Corner Points of every Layer for a single Cubie (Added local Corner Points have x y z values of -0.5 or 0.5)
for (auto layer : layers) {
for (int i = 0; i < 4; i++) {
layer[i] = compound * glm::vec4(layer[i], 1.0);
}
}
m_cubieRenderer.Render(compound);
// Calling LayerCalculation() for every Layer with direction -1 or 1
}
这个方法应该计算我的辅助向量,2个方向向量 和每一层的归一化向量
void MergedCube::LayerCalculation(std::vector<glm::vec3>& points, int normDirection) {
while (points.size() > 4) {
points.erase(points.end()-1);
}
glm::vec3 middlePoint = (points[0] + points[2]) / 2.0f;
glm::vec3 firstPoint = (points[0] + points[1]) / 2.0f;
glm::vec3 secondPoint = (points[0] + points[3]) / 2.0f;
glm::vec3 vecA = glm::normalize(firstPoint - middlePoint);
glm::vec3 vecB = glm::normalize(secondPoint - middlePoint);
glm::vec3 normalVector = glm::cross(vecA,vecB) * glm::vec3(direction);
points.push_back(middlePoint);
points.push_back(vecA);
points.push_back(vecB);
points.push_back(normalVector);
}
现在是 RayAndCubeIntersection 方法。
bool MergedCube::RayAndCubeIntersection(glm::vec3 startingPoint, glm::vec3 direction,
std::vector<glm::vec3> Pts) {
glm::vec3 helperVec = pts[4];
glm::vec3 normVec = pts[7];
glm::vec3 directionVecA = pts[5];
glm::vec3 directionVecB = pts[6];
if (glm::dot(rayDirection, normVec) < 0) {
float res = normVec[0] * helperVec[0] + normVec[1] * helperVec[1] + normVec[2] * helperVec[2];
float directionMultiplikator = (res - normVec[0] * rayStartingPoint[0] - normVec[1] * rayStartingPoint[1] - normVec[2] * rayStartingPoint[2]) /
(normVec[0] * rayDirection[0] + normVec[1] * rayDirection[1] + normVec[2] * rayDirection[2]);
glm::vec3 crosspoint = rayStartingPoint + rayDirection * glm::vec3(directionMultiplikator);
if (glm::dot(crosspoint - helperVec,normVec) == 0) {
float x = glm::dot(directionVecA,crosspoint - helperVec);
float y = glm::dot(directionVecB, crosspoint - helperVec);
if (x > -0.5001 && x < 0.5001) {
if (y > -0.5001 && y < 0.5001) {
return true;
}
}
}
}
return false;
}
编辑:我改变了我的代码,现在在很多情况下都检测到点击立方体。
好吧,我想是时候回答我自己的问题了。 我的代码的实际问题是检查
glm::dot(crosspoint - helperVec,normVec) == 0
。
但是相反,我应该用非常小的 EPSILON 值检查glm::abs(glm::dot(crosspoint - helperVec,normVec)) < EPSILON
。
我自己注意:使用浮点数时永远不要检查 0