#opengl #catmull-rom-curve
#opengl #catmull-rom-curve
Вопрос:
Я пытаюсь создать программу OpenGL, которая позволяет пользователю щелкать в любом месте окна, создавая точку в этой точной координате курсора для каждого щелчка, а затем рисовать кривую через эти точки. Мне удалось реализовать эту часть и провести прямую линию через каждую точку, но теперь я должен сделать эту линию изогнутой с помощью catmull-rom. Я новичок в этой концепции, и я нашел примеры того, как работает функция glm:CatmullRom() , но я не могу найти пример того, как она работает с остальной частью программы для рисования кривой. Я попытался использовать его, но теперь я получаю прямую линию, которая отрезана от окна. Мне нужно знать, как правильно подойти к этой настройке. В принципе, это то, что я сделал до сих пор:
double* cursorX = new double;
double* cursorY = new double;
vector<GLfloat>controlPoints = {0.0, 0.0, 0.0}; // Default value (can't pass in an empty vector to VBO)
glm::vec3 point1;
glm::vec3 point2;
glm::vec3 point3;
glm::vec3 point4;
vector<glm::vec3>interpolatedPoints;
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT amp;amp; action == GLFW_PRESS)
{
glfwGetCursorPos(window, cursorX, cursorY);
controlPoints.push_back(*cursorX); // X-coordinate
controlPoints.push_back(*cursorY); // Y-coordinate
controlPoints.push_back(0); // Z-coordinate (always fixed at 0)
}
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ENTER amp;amp; action == GLFW_PRESS)
{
// Test with 8 points, each point having X,Y, and Z, meaning 24 indices in total!
point1 = { controlPoints[1], controlPoints[2], controlPoints[3] };
point2 = { controlPoints[4], controlPoints[5], controlPoints[6] };
point3 = { controlPoints[7], controlPoints[8], controlPoints[9] };
point4 = { controlPoints[10], controlPoints[11], controlPoints[12] };
interpolatedPoints.push_back(glm::catmullRom(point1, point2, point3, point4, 0));
point1 = { controlPoints[13], controlPoints[14], controlPoints[15] };
point2 = { controlPoints[16], controlPoints[17], controlPoints[18] };
point3 = { controlPoints[19], controlPoints[20], controlPoints[21] };
point4 = { controlPoints[22], controlPoints[23], controlPoints[24] };
interpolatedPoints.push_back(glm::catmullRom(point1, point2, point3, point4, 0.5));
}
}
// Initialize VAO and VBO
GLuint VAO, VBO;
glGenVertexArrays(1, amp;VAO);
glGenBuffers(1, amp;VBO);
// Bind VAO
glBindVertexArray(VAO);
// Bind and implement VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, controlPoints.size() * sizeof(GLfloat), amp;controlPoints.front(), GL_STATIC_DRAW);
// Connecting coordinates to shader
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
while (!glfwWindowShouldClose(window))
{
// Check if any events have been activated (key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents();
// Render
// Clear the colorbuffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
// Update VBO
glBufferData(GL_ARRAY_BUFFER, interpolatedPoints.size() * sizeof(glm::vec3), amp;interpolatedPoints.front(), GL_STATIC_DRAW);
glDrawArrays(GL_LINE_STRIP, 0, interpolatedPoints.size() * sizeof(glm::vec3));
// ...
}
// ...
}
Ответ №1:
std::vector
индексы начинаются с 0, но ваш код начинает индексироваться с 1. Так что исправьте это соответствующим образом. Также по какой-то причине вы вводите фиктивную точку, controlPoints
что означает, что она фактически начинается с 3:
point1 = { controlPoints[3], controlPoints[4], controlPoints[5] };
point2 = { controlPoints[6], controlPoints[7], controlPoints[8] };
// ...
Лучшим решением является изменение его на вектор glm::vec3
и удаление этого фиктивного элемента. Вы делаете это следующим образом:
vector<glm::vec3> controlPoints;
и
controlPoints.push_back(glm::vec3(*cursorX, *cursorY, 0));
и
interpolatedPoints.push_back(glm::catmullRom(controlPoints[0],
controlPoints[1], controlPoints[2], controlPoints[3], 0));
и
glBufferData(GL_ARRAY_BUFFER, controlPoints.size() * sizeof(glm::vec3), controlPoints.data(), GL_STATIC_DRAW);
Также не выделяйте cursorX
и cursorY
в куче. Для этого просто нет причин:
double cursorX, cursorY;
glfwGetCursorPos(window, amp;cursorX, amp;cursorY);
controlPoints.push_back(glm::vec3(cursorX, cursorY, 0));
Комментарии:
1. Ваши предложения имеют смысл, за исключением вашего вызова glBufferData. Разве он не должен брать данные из интерполированных точек, а не контрольных точек? Имейте в виду, что у меня есть два вызова glBufferData; один, который привязывает VBO в начале, и один, который постоянно обновляется в игровом цикле. Кроме того, правильно ли мой вызов glDrawArrays? Я не был слишком уверен, беру ли я размер interpolatedPoints или контрольных точек. Редактировать: когда я использую glBufferBata с interpolatedPoints, я получаю прямую линию (независимо от точек). Если с контрольными точками, линия соединяется через точки, но не изогнута.