Cocos2d-x - Error drawing cubic bezier curves
Asked Answered
V

2

13

I'm trying to draw a cubic bezier path with a certain thickness, but the curve appears like a sequence of disconnected segments (3 in my case). This is a screenshot (the blue circles are the control points of the curve).

Cubic bezier curve

I noticed that the same effect occurs in the 'draw primitives' in the cocos2d-x tests. Anyway I'm pretty sure there should be a workaround but I'm not able to find it by myself. Furthermore the line is affected by the aliasing effect and I am not sure how to apply an alpha shadow to avoid it.

This is the code I used:

glLineWidth(24.0f);

Vec2 cp1 = Vec2(200, 200);
Vec2 cp2 = Vec2(1300, 150);
Vec2 cp3 = Vec2(170, 1200);
Vec2 cp4 = Vec2(1400, 1000);

//Draw control points
DrawPrimitives::setDrawColor4B(0, 0, 255, 255);
DrawPrimitives::drawSolidCircle(cp1, 50, 360, 120, 1, 1);
DrawPrimitives::drawSolidCircle(cp2, 50, 360, 120, 1, 1);
DrawPrimitives::drawSolidCircle(cp3, 50, 360, 120, 1, 1);
DrawPrimitives::drawSolidCircle(cp4, 50, 360, 120, 1, 1);

//Draw cubic red bezier curve
DrawPrimitives::setDrawColor4B(255, 0, 0, 255);
DrawPrimitives::drawCubicBezier(cp1, cp2, cp3, cp4, 50);
Vey answered 6/4, 2015 at 16:55 Comment(1)
If the effect does not visually occur when you're specifying a "normal" line width (like 1.0f), then what you are seeing is a limitation of OpenGL. the 'gaps' you're seeing are the caps of the three lines used to draw the bezier curve. Since OpenGL does not allow you to specify line caps, you'll likely have to implement those yourself...Cuspidate
F
1

That broken effect is caused by a lack of path joining between endpoints of the line strips.

OpenGL is designed for fast scanline rasterization first and foremost and isn't always so beautiful if you want to use it this way.

There could be quick and dirty workaround ways to kind of get a reasonable result, like drawing circles at the endpoints to try to fill things in.

A proper library where drawing paths beautifully is important will often offer join options between lines/curves like rounded, beveled, or a miter joint along with options for the end caps where segments aren't joining together. It might be easier and efficient enough for the kind of work you're doing to use, say, a decent SVG rasterizer for this kind of work. If you need to composite the results over elements rasterized by OGL, you could transfer the image results into a texture and render that.

You could also get pretty elaborate and roll a pretty sophisticated solution (or possibly find one elsewhere) through OpenGL. Here's an example: https://www.mapbox.com/blog/drawing-antialiased-lines/

Foulmouthed answered 19/11, 2015 at 6:36 Comment(0)
T
0

i have another solution, but i do not know whether it make the performance slow down? anyone please give me advise!!

void DrawNode::drawCubicBezier(const Vec2 &origin, const Vec2 &control1, const Vec2 &control2, const Vec2 &destination, unsigned int segments, const Color4F &color)

{

Vec2* vertices = new (std::nothrow) Vec2[segments + 1];
if( ! vertices )
    return;

float t = 0;
for (unsigned int i = 0; i < segments; i++)
{
    vertices[i].x = powf(1 - t, 3) * origin.x + 3.0f * powf(1 - t, 2) * t * control1.x + 3.0f * (1 - t) * t * t * control2.x + t * t * t * destination.x;
    vertices[i].y = powf(1 - t, 3) * origin.y + 3.0f * powf(1 - t, 2) * t * control1.y + 3.0f * (1 - t) * t * t * control2.y + t * t * t * destination.y;

    t += 1.0f / segments;
    **///begin  adddd
    drawLine(Vec2(vertices[i].x, vertices[i].y - 3), Vec2(vertices[i].x, vertices[i].y + 3), color);
    /// end addddd**
}
vertices[segments].x = destination.x;
vertices[segments].y = destination.y;
**drawLine(Vec2(vertices[segments].x, vertices[segments].y - 3), Vec2(vertices[segments].x, vertices[segments].y + 3), color);**

CC_SAFE_DELETE_ARRAY(vertices);


}

here is my result Special Cubic Bezier

Tragopan answered 20/11, 2015 at 6:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.