Рисование линии переменной ширины в openGL (без glLineWidth) - PullRequest
9 голосов
/ 19 сентября 2008

Каков наилучший способ нарисовать линию переменной ширины без использования glLineWidth? Просто нарисовать прямоугольник? Различные параллельные линии? Ничего из перечисленного?

Ответы [ 7 ]

14 голосов
/ 19 сентября 2008

Вы можете нарисовать два треугольника:

// Draws a line between (x1,y1) - (x2,y2) with a start thickness of t1 and
// end thickness t2.
void DrawLine(float x1, float y1, float x2, float y2, float t1, float t2)
{
    float angle = atan2(y2 - y1, x2 - x1);
    float t2sina1 = t1 / 2 * sin(angle);
    float t2cosa1 = t1 / 2 * cos(angle);
    float t2sina2 = t2 / 2 * sin(angle);
    float t2cosa2 = t2 / 2 * cos(angle);

    glBegin(GL_TRIANGLES);
    glVertex2f(x1 + t2sina1, y1 - t2cosa1);
    glVertex2f(x2 + t2sina2, y2 - t2cosa2);
    glVertex2f(x2 - t2sina2, y2 + t2cosa2);
    glVertex2f(x2 - t2sina2, y2 + t2cosa2);
    glVertex2f(x1 - t2sina1, y1 + t2cosa1);
    glVertex2f(x1 + t2sina1, y1 - t2cosa1);
    glEnd();
}
9 голосов
/ 23 июля 2010

Хорошо, как насчет этого: (Озгар)


       A
      / \
     /      \
    . p1        \
   /                \
  /                    D
 B -                 .p2
      -   -    -    C

Итак, AB - width1, а CD - width2.

Тогда

// find line between p1 and p2
Vector p1p2 = p2 - p1 ;

// find a perpendicular
Vector perp = p1p2.perpendicular().normalize()

// Walk from p1 to A
Vector A = p1 + perp*(width1/2)
Vector B = p1 - perp*(width1/2)

Vector C = p2 - perp*(width2/2)
Vector D = p2 - perp*(width2/2)

// wind triangles
Triangle( A, B, D )
Triangle( B, D, C )

Обратите внимание, что в этом алгоритме потенциально есть проблема обмотки CW / CCW - если perp вычислено как (-y, x) на приведенной выше диаграмме, то это будет обмотка CCW, если (y, -x), то она будет CW обмотка.

2 голосов
/ 04 мая 2011

Для тех, кто ищет хорошее решение, этот код написан с использованием LWJGL, но его легко адаптировать к любой реализации OpenGL.

import java.awt.Color;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector2f;
public static void DrawThickLine(int startScreenX, int startScreenY, int endScreenX, int endScreenY, Color color, float alpha, float width) {

    Vector2f start = new Vector2f(startScreenX, startScreenY);
    Vector2f end = new Vector2f(endScreenX, endScreenY);

    float dx = startScreenX - endScreenX;
    float dy = startScreenY - endScreenY;

    Vector2f rightSide = new Vector2f(dy, -dx);
    if (rightSide.length() > 0) {
        rightSide.normalise();
        rightSide.scale(width / 2);
    }
    Vector2f leftSide = new Vector2f(-dy, dx);
    if (leftSide.length() > 0) {
        leftSide.normalise();
        leftSide.scale(width / 2);
    }

    Vector2f one = new Vector2f();
    Vector2f.add(leftSide, start, one);

    Vector2f two = new Vector2f();
    Vector2f.add(rightSide, start, two);

    Vector2f three = new Vector2f();
    Vector2f.add(rightSide, end, three);

    Vector2f four = new Vector2f();
    Vector2f.add(leftSide, end, four);

    GL11.glBegin(GL11.GL_QUADS);
    GL11.glColor4f(color.getRed(), color.getGreen(), color.getBlue(), alpha);
    GL11.glVertex3f(one.x, one.y, 0);
    GL11.glVertex3f(two.x, two.y, 0);
    GL11.glVertex3f(three.x, three.y, 0);
    GL11.glVertex3f(four.x, four.y, 0);
    GL11.glColor4f(1, 1, 1, 1);
    GL11.glEnd();
}
1 голос
/ 08 ноября 2010

Сегодня я должен был сделать то же самое раньше.

Для создания линии, охватывающей (x1,y1) -> (x2,y2) заданного width, очень простым методом является преобразование простого квадратного охвата размером в единицу (0., -0.5) -> (1., 0.5) с использованием:

  1. glTranslatef(...), чтобы переместить его в нужное вам (x1,y1) местоположение;
  2. glScalef(...) для масштабирования вправо length и желаемого width: используйте length = sqrt( (x2-x1)^2 + (y2-y1)^2 ) или любое другое приближение низкой сложности;
  3. glRotatef(...) до angle вправо: используйте angle = atan2(y2-y1, x2-x1).

Единица-квадрат очень просто создается из полоски из двух треугольников GL_TRIANGLE_STRIP, которая после указанных преобразований превращается в вашу сплошную линию.

Бремя здесь лежит в основном на OpenGL (и на вашем графическом оборудовании), а не на коде вашего приложения. Вышеуказанная процедура очень легко превращается в общую функцию, окружая вызовы glPushMatrix() и glPopMatrix().

1 голос
/ 23 июля 2010

Другой способ сделать это, если вы пишете программный растеризатор случайно, - это использовать барицентрические координаты на стадии окрашивания пикселей и цветные пиксели , когда одна из барицентрических координат близка к 0 . Чем больше вы сделаете, тем толще будут линии.

1 голос
/ 19 сентября 2008

Предположим, что ваши исходные точки (x1, y1) -> (x2, y2). Используйте следующие точки (x1-width / 2, y1), (x1 + width / 2, y1), (x2-width / 2, y2), (x2 + width / 2, y2), чтобы построить прямоугольник, а затем используйте Quads / Tris, чтобы нарисовать его. Это простой наивный способ. Обратите внимание, что при большой ширине линии вы получите странное поведение конечной точки. То, что вы действительно хотите сделать, это некоторые умные вычисления параллельных линий (которые не должны быть такими плохими) с использованием векторной математики. По какой-то причине на ум приходят точка / кросс-произведение и векторная проекция.

0 голосов
/ 19 сентября 2008

Прямоугольник (т. Е. GL_QUAD или два GL_TRIANGLES) звучит как ваша лучшая ставка по звукам этого, не уверен, что я могу придумать какой-либо другой способ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...