【问题标题】:Drawing app on iPad using OpenGL使用 OpenGL 在 iPad 上绘图应用程序
【发布时间】:2011-01-05 16:43:02
【问题描述】:

我正在使用 OpenGL 为 iPad 创建一个绘图应用程序(文本)。我已经看过 Apple 的示例 GLPaint,我的应用程序现在基于该代码。我的应用应该只用于绘制文本,而不是用于绘制图片。

嗯,我的应用程序可以工作,我可以写一些文字。但是文笔不好,写的不好玩。绘图路径不平滑,它是有角度的,因为我正在从一个点到另一个点画一条线。并且路径到处都有相同的宽度。我的想法是:当你写得快时,线条比你写得慢时更细。这应该是和用真正的笔书写一样的体验。

如何使路径看起来更平滑?如何根据书写速度改变线条的宽度?

在这里你可以明白我的意思:

【问题讨论】:

    标签: iphone xcode ipad opengl-es drawing


    【解决方案1】:

    平滑绘图的最佳方法是使用贝塞尔曲线。这是我的代码。这是我在苹果开发网站上找到的修改版本,但我不记得原始链接:

    CGPoint drawBezier(CGPoint origin, CGPoint control, CGPoint destination, int segments)
    {
     CGPoint vertices[segments/2];
     CGPoint midPoint;
     glDisable(GL_TEXTURE_2D);
     float x, y;
    
     float t = 0.0;
     for(int i = 0; i < (segments/2); i++)
     {
      x = pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x;
      y = pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y;
      vertices[i] = CGPointMake(x, y);
      t += 1.0 / (segments);
    
     }
     //windowHeight is the height of you drawing canvas.
     midPoint = CGPointMake(x, windowHeight - y);
     glVertexPointer(2, GL_FLOAT, 0, vertices);
     glDrawArrays(GL_POINTS, 0, segments/2);
     return midPoint;
    }
    

    这将基于三点绘制。控件是您需要返回的中点。新的中点将不同于以前的中点。另外,如果你浏览上面的代码,它只会画出一半的线。下一个笔画将填充它。这是必需的。我调用这个函数的代码(上面是C,这个是Obj-C):

       //Invert the Y axis to conform the iPhone top-down approach
       invertedYBegCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i] CGPointValue].y;
       invertedYEndCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i+1] CGPointValue].y;
       invertedYThirdCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i+2] CGPointValue].y;
       //Figure our how many dots you need
       count = MAX(ceilf(sqrtf(([[currentStroke objectAtIndex:i+2] CGPointValue].x - [[currentStroke objectAtIndex:i] CGPointValue].x) 
             * ([[currentStroke objectAtIndex:i+2] CGPointValue].x - [[currentStroke objectAtIndex:i] CGPointValue].x) 
             + ((invertedYThirdCoord - invertedYBegCoord) * (invertedYThirdCoord - invertedYBegCoord))) / pointCount), 1);
    
       newMidPoint = drawBezier(CGPointMake([[currentStroke objectAtIndex:i] CGPointValue].x, invertedYBegCoord), CGPointMake([[currentStroke objectAtIndex:i+1] CGPointValue].x, invertedYEndCoord), CGPointMake([[currentStroke objectAtIndex:i+2] CGPointValue].x, invertedYThirdCoord), count);
    
       int loc = [currentStroke count]-1;
       [currentStroke insertObject:[NSValue valueWithCGPoint:newMidPoint] atIndex:loc];
       [currentStroke removeObjectAtIndex:loc-1];
    

    该代码将根据倒置的 iPad 点获取中点,并将“控件”设置为当前点。

    这将使边缘变得平滑。现在关于线宽,您只需要找到该绘图的速度即可。最简单的方法就是找到你的线的长度。使用分量数学很容易做到这一点。我没有任何代码,但here 是来自物理站点的组件数学入门。或者您可以简单地将(以上)计数除以某个数字,以找出您需要的线有多粗(计数使用组件数学)。

    我将点数据存储在一个名为 currentStroke 的数组中,以防不明显。

    这应该就是你所需要的。

    编辑:

    要存储积分,您应该使用 touchesBegin 和 touchesEnd:

    - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
    {
        self.currentStroke = [NSMutableArray array];
        CGPoint point = [ [touches anyObject] locationInView:self];
        [currentStroke addObject:[NSValue valueWithCGPoint:point]];
        [self draw];
    
    }
    
    - (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
    {
        CGPoint point = [ [touches anyObject] locationInView:self];
        [currentStroke addObject:[NSValue valueWithCGPoint:point]];
        [self draw];
    }
    
    
    - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        CGPoint point = [ [touches anyObject] locationInView:self];
        [currentStroke addObject:[NSValue valueWithCGPoint:point]];
        [self draw];
    }
    

    这几乎是一个完整的绘图应用程序。如果您使用的是 GL_Paint,那么您已经在使用点精灵,该系统是在此基础上构建的。

    【讨论】:

    • 非常感谢,这真的很有帮助。但我不确定在哪里实现代码的第二部分。在 GLPaint 示例中,有一个函数 renderLineFromPoint:toPoint:,每次用户移动手指时都会调用该函数。我需要将您的代码的第二部分放入该函数中吗?
    • 或者你能添加整个代码吗?我的意思是完整的方法。那将是非常友好的。
    • 添加了 touchesBegin、touchesMoved 和 touchesEnd。这几乎是一个完整的 openGL 绘图应用程序。
    • 在代码的第二部分分配了 'invertedYBegCoord' 变量时,'i' 变量代表什么?
    • @icnivad 以防万一你想循环你的线来重绘。这是没有必要的。实际上,我忘了在这个例子中删除它。无论如何,只要假设 i=0。
    【解决方案2】:

    关于你问题的第二部分(如何根据写作速度改变线的宽度),你应该能够通过利用UITouchtimestamp属性来实现这一点你的touchesBegan:withEvent:touchesMoved:withEvent: 方法。

    您可以通过存储最近的UITouch 对象的时间戳并将其与新对象进行比较来计算两个后续触摸事件之间的时间差。将滑动动作的距离除以时间差应该可以测量出移动速度。

    现在您需要做的就是想出一种将写入速度转换为线宽的方法,这可能会归结为选择任意值并对其进行调整,直到您对结果满意为止。

    【讨论】:

    • 谢谢。我已经想到了这样的事情。如果您知道如何解决我的第一个问题,那就太好了。希望您对 upvote 感到满意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多