Я занимался разработкой 3D шахматной доски и застрял, пытаясь перетащить фигуры на несколько дней.
После того, как я выбрал объект, используя мой луч-кастер, я запускаю функцию перетаскивания, которая вычисляет разницу между текущим местоположением мыши (в мировых координатах) и ее предыдущим местоположением, а затем переводю свой объект по разности этих координат.
Я отлаживаю свой луч-заклинатель, рисуя линии, поэтому я уверен, что эти координаты точны.
Перевод моего объекта на основе координат заклинателя лучей только перемещает объект на часть расстояния, которое он должен фактически пройти.
Я пропускаю шаг?
-Кальвин
Я считаю, что моя проблема в этой строке кода ….
glm::vec3 World_Delta = Current_World_Location - World_Start_Location;
Если я умножу уравнение на 20, объект начнет двигаться больше, чем я ожидал, но он никогда не будет абсолютно точным.
Ниже приведен некоторый подходящий код
RAY-ЛИТЬЕ:
void CastRay(int mouse_x, int mouse_y) {
int Object_Selected = -1;
float Closest_Object = -1;
//getWorldCoordinates calls glm::unproject
nearPoint = Input_Math.getWorldCoordinates(glm::vec3(mouse_x, Window_Input_Info.getScreenHeight()-mouse_y, 0.0f));
farPoint = Input_Math.getWorldCoordinates(glm::vec3(mouse_x, Window_Input_Info.getScreenHeight()-mouse_y, 1.0f));
glm::vec3 direction = Input_Math.normalize(farPoint - nearPoint);
//getObjectStack() Retrieves all objects in the current scene
std::vector<LoadOBJ> objectList = Object_Input_Info.getObjectStack();
for (int i = 0; i < objectList.size(); i++) {
std::vector<glm::vec3> Vertices = objectList[i].getVertices();
for(int j = 0; j < Vertices.size(); j++) {
if ( ( j + 1 ) % 3 == 0 ) {
glm::vec3 face_normal = Input_Math.normalize(Input_Math.CrossProduct(Vertices[j-1] - Vertices[j-2], Vertices[j] - Vertices[j-2]));
float nDotL = glm::dot(direction, face_normal);
if (nDotL <= 0.0f ) { //if nDotL == 0 { Perpindicular } else if nDotL < 0 { SameDirection } else { OppositeDirection }
float distance = glm::dot(face_normal, (Vertices[j-2] - nearPoint)) / nDotL;
glm::vec3 p = nearPoint + distance * direction;
glm::vec3 n1 = Input_Math.CrossProduct(Vertices[j-1] - Vertices[j-2], p - Vertices[j-2]);
glm::vec3 n2 = Input_Math.CrossProduct(Vertices[j] - Vertices[j-1], p - Vertices[j-1]);
glm::vec3 n3 = Input_Math.CrossProduct(Vertices[j-2] - Vertices[j], p - Vertices[j]);
if( glm::dot(face_normal, n1) >= 0.0f && glm::dot(face_normal, n2) >= 0.0f && glm::dot(face_normal, n3) >= 0.0f ) {
if(p.z > Closest_Object) {
//I Create this "dragplane" to be used by my dragging function.
Drag_Plane[0] = (glm::vec3(Vertices[j-2].x, Vertices[j-2].y, p.z ));
Drag_Plane[1] = (glm::vec3(Vertices[j-1].x, Vertices[j-1].y, p.z ));
Drag_Plane[2] = (glm::vec3(Vertices[j].x , Vertices[j].y , p.z ));
//This is the object the we selected in the scene
Object_Selected = i;
//These are the coordinate the ray intersected the object
World_Start_Location = p;
}
}
}
}
}
}
if(Object_Selected >= 0) { //If an object was intersected by the ray
//selectObject -> Simply sets the boolean "dragging" to true
selectObject(Object_Selected, mouse_x, mouse_y);
}
ПЕРЕТАСКИВАНИЕ
void DragObject(int mouse_x, int mouse_y) {
if(dragging) {
//Finds the Coordinates where the ray intersects the "DragPlane" set by original object intersection
farPoint = Input_Math.getWorldCoordinates(glm::vec3(mouse_x, Window_Input_Info.getScreenHeight()-mouse_y, 1.0f));
nearPoint = Input_Math.getWorldCoordinates(glm::vec3(mouse_x, Window_Input_Info.getScreenHeight()-mouse_y, 0.0f));
glm::vec3 direction = Input_Math.normalize(farPoint - nearPoint);
glm::vec3 face_normal = Input_Math.normalize(Input_Math.CrossProduct(Drag_Plane[1] - Drag_Plane[0], Drag_Plane[2] - Drag_Plane[0]));
float nDotL = glm::dot(direction, face_normal);
float distance = glm::dot(face_normal, (Drag_Plane[0] - nearPoint)) / nDotL;
glm::vec3 Current_World_Location = nearPoint + distance * direction;
//Calculate the difference between the current mouse location and its previous location
glm::vec3 World_Delta = Current_World_Location - World_Start_Location;
//Set the "start location" to the current location for the next loop
World_Start_Location = Current_World_Location;
//get the current object
Object_Input_Info = Object_Input_Info.getObject(currentObject);
//adds a translation matrix to the stack
Object_Input_Info.TranslateVertices(World_Delta.x, World_Delta.y, World_Delta.z);
//calculates the new vertices
Object_Input_Info.Load_Data();
//puts the new object back
Object_Input_Info.Update_Object_Stack(currentObject);
}
}
Я уже сталкивался с проблемами, аналогичными тем, о которых говорится в вашей отчетности.
Вместо отслеживания перевода во время движения мыши, вы можете сделать следующее:
При обратном вызове кнопки мыши сохраните вектор «Delta» от положения мыши (в мировых координатах) (P_mouse) до положения вашего объекта (P_object). Это было бы что-то вроде:
Delta = P_object - P_mouse;
Для каждого вызова вашего обратного вызова движения мышью вам просто нужно обновить позицию объекта:
P_object = P_mouse + Delta;
Обратите внимание, что дельта постоянна в течение всего процесса перетаскивания.