半径在 2 点之间的圆弧

Den*_*yer 0 c++ opengl

我需要找出如何使用 OpenGL 在给定半径的两个点之间绘制圆弧。有没有办法在 OpenGL 中执行此操作或找到我需要绘制圆弧的中心点,以便两个点都与给定半径 ? :)

附截图: https: //i.stack.imgur.com/cvsRR.png

Jon*_*ard 5

这是一个简单但完整且经过测试的 opengl 程序,它演示了您正在寻找的内容。请注意,对于半径为 x 的两点之间的圆弧是什么的问题没有单一的答案,因为圆弧可以在两个方向中的任意一个方向弯曲。

请仔细注意第二个 createArc函数重载,因为它代表了答案的核心,尽管它调用第一个 createArc函数重载来完成工作。

编辑:我意识到我在之前的回答中没有考虑到“两个角度之间的弧”的歧义(从0到90的弧可以是直接的或一直围绕)。我更新了代码来定义您是对较小的弧线还是对较大的弧线感兴趣。

#define GLEW_STATIC
#define _USE_MATH_DEFINES
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <gl/gl.h>
#include <math.h>
#include <iostream>

const int ARC_VERTEX_COUNT = 100;

// Don't use global variables at home, kids!
GLFWwindow* window;
GLuint shader;
GLint shaderLoc_pos;
GLuint vbo_circle;
GLuint vbo_arc;

float normalizeAngleToSmallestPositive(float angle) {
    while (angle < 0.0) { angle += M_PI*2; }
    while (angle >= M_PI*2) { angle -= M_PI*2; }
    return angle;
}

bool startApp() {
    if (!glfwInit()) {
        return false;
    }
    window = glfwCreateWindow(500, 500, "Hello World", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return false;
    }
    glfwMakeContextCurrent(window);
    glewInit();
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glLineWidth(10.0);
    return true;
}

void stopApp() {
    glfwTerminate();
}

void createShader() {
    const char* vsSrc =
        "#version 330 core\n"
        "in vec2 pos; void main() { gl_Position = vec4(pos, 0.0, 1.0); }";
    const char* fsSrc =
        "#version 330 core\n"
        "out vec4 color; void main() { color = vec4(1.0,1.0,1.0,0.5); }";

    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vsSrc, nullptr);
    glCompileShader(vs);

    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fsSrc, nullptr);
    glCompileShader(fs);

    shader = glCreateProgram();
    glAttachShader(shader, vs);
    glAttachShader(shader, fs);
    glLinkProgram(shader);

    shaderLoc_pos = glGetAttribLocation(shader, "pos");
}

// Create an arc between two given angles, based on the circle described by the given radius and
// center point
GLuint createArc(float angle1, float angle2, float radius, float x, float y, float useBiggerArc) {
    // Prepare angles
    angle1 = normalizeAngleToSmallestPositive(angle1);
    angle2 = normalizeAngleToSmallestPositive(angle2);
    if (angle1 > angle2) {
        float buffer = angle1;
        angle1 = angle2;
        angle2 = buffer;
    }
    if (useBiggerArc != angle2-angle1 > M_PI) {
        angle1 += M_PI*2;
    }

    // Create opengl geometry
    GLfloat pos[ARC_VERTEX_COUNT * 2];
    for (int i = 0; i < ARC_VERTEX_COUNT; i++) {
        pos[i*2] = sin((float)i / (ARC_VERTEX_COUNT-1) * (angle2 - angle1) + angle1) * radius + x;
        pos[i*2+1] = cos((float)i / (ARC_VERTEX_COUNT-1) * (angle2 - angle1) + angle1) * radius + y;
    }
    GLuint result;
    glGenBuffers(1, &result);
    glBindBuffer(GL_ARRAY_BUFFER, result);
    glBufferData(GL_ARRAY_BUFFER, sizeof(pos), pos, GL_STATIC_DRAW);
    return result;
}

GLuint createCircle(float radius, float x, float y) {
    return createArc(M_PI*0, M_PI*2, radius, x, y, true);
}

// Create an arc between two given points that is based on a circle with the given radius.
GLuint createArc(
    float x1, float y1, float x2, float y2, float radius, bool arcDirection, bool useBiggerArc)
{
    // distance between points
    float distance = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
    // halfway point
    float xAverage = (x1+x2)/2.0;
    float yAverage = (y1+y2)/2.0;
    // circle center
    float xCenter = sqrt(radius*radius - distance*distance/4.0) * (y1-y2) / distance;
    float yCenter = sqrt(radius*radius - distance*distance/4.0) * (x2-x1) / distance;
    xCenter = xAverage + (arcDirection ? xCenter : -xCenter);
    yCenter = yAverage + (arcDirection ? yCenter : -yCenter);
    // angles
    float angle1 = atan2(x1-xCenter, y1-yCenter);
    float angle2 = atan2(x2-xCenter, y2-yCenter);
    // create the arc
    return createArc(angle1, angle2, radius, xCenter, yCenter, useBiggerArc);
}

void runMainLoop() {
    while (!glfwWindowShouldClose(window)) {
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shader);
        glEnableVertexAttribArray(shaderLoc_pos);

        glBindBuffer(GL_ARRAY_BUFFER, vbo_circle);
        glVertexAttribPointer(shaderLoc_pos, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glDrawArrays(GL_LINE_STRIP, 0, ARC_VERTEX_COUNT);

        glBindBuffer(GL_ARRAY_BUFFER, vbo_arc);
        glVertexAttribPointer(shaderLoc_pos, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glDrawArrays(GL_LINE_STRIP, 0, ARC_VERTEX_COUNT);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
}

int main(void) {
    if (startApp())
    {
        createShader();
        vbo_circle = createCircle(0.75, 0.0, 0.0);
        vbo_arc = createArc(0.0, 0.75, 0.75, 0.0, 0.75, false, false);

        runMainLoop();
        stopApp();
        return 0;
    }
    else
    {
        return -1;
    }
}
Run Code Online (Sandbox Code Playgroud)