在openGL中绘制可变宽度线(无glLineWidth)

时间:2008-09-19 13:13:32

标签: opengl

在不使用glLineWidth的情况下绘制可变宽度线的最佳方法是什么? 只画一个矩形? 各种平行线? 以上都不是吗?

7 个答案:

答案 0 :(得分:14)

您可以绘制两个三角形:

// 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();
}

答案 1 :(得分:9)

好的,这个:( Ozgar)


       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 :(得分:2)

对于那些希望找到一个好解决方案的人来说,这段代码是使用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();
}

答案 3 :(得分:1)

假设您的原始点是(x1,y1) - > (X2,Y2)。使用以下几点(x1-width / 2,y1),(x1 + width / 2,y1),(x2-width / 2,y2),(x2 + width / 2,y2)构造一个矩形然后使用quads / tris画它。这简单朴素的方式。请注意,对于较大的线宽,您将获得奇怪的端点行为。你真正想做的是使用矢量数学进行一些智能并行计算(不应该那么糟糕)。出于某种原因,我想到了点/叉产品和矢量投影。

答案 4 :(得分:1)

另一种方法,如果您正在编写软件光栅化器,则在像素着色阶段使用重心坐标,并在其中一个重心坐标接近0 时使用颜色像素。你做的津贴越多,线条越粗。

答案 5 :(得分:1)

我今天早些时候必须做同样的事情。

要创建跨越给定(x1,y1) -> (x2,y2)的{​​{1}}的行,一种非常简单的方法是使用以下内容转换width的简单单位大小的正方形:

  1. (0., -0.5) -> (1., 0.5)将其移至您想要的glTranslatef(...)位置;
  2. (x1,y1)将其缩放到右侧glScalef(...)并希望length:使用width或任何其他低复杂度近似值;
  3. length = sqrt( (x2-x1)^2 + (y2-y1)^2 )glRotatef(...)方向正确:使用angle
  4. 单位正方形非常简单地由双三角形条带angle = atan2(y2-y1, x2-x1)创建,在上述转换后变为实线。

    这里的负担主要放在OpenGL(和你的图形硬件)而不是你的应用程序代码上。通过围绕GL_TRIANGLE_STRIPglPushMatrix()来电,上述程序很容易转变为通用函数。

答案 6 :(得分:0)

一个矩形(即GL_QUAD或两个GL_TRIANGLES)听起来就是你最好的选择,不确定我能想到其他任何方式。