【问题标题】:How to create jigsaw puzzle pieces using openGL and bezier curve?如何使用 openGL 和贝塞尔曲线创建拼图?
【发布时间】:2015-03-16 21:44:05
【问题描述】:

我正在尝试创建一个拼图演示,我想知道在不使用蒙版的情况下创建拼图的其他方法。目前,我通过拍摄完整图像来拼图,将该图像分成四块(假设拼图是 2x2),然后存储并为每块应用蒙版。如下图所示

    // create standard puzzle pieces
    arryPieceEndPos = new int[mCols][mRows];
    arryPieceImg = new Bitmap[mCols * mRows];
    arryIsPieceLocked = new boolean[mCols * mRows];

    int pos = 0;
    for (int c = 0; c < mCols; c++) {
        for (int r = 0; r < mRows; r++) {
            arryPieceImg[pos] = Bitmap.createBitmap(mBitmap,
            c * mPieceWidth, r * mPieceHeight,
            mPieceWidth, mPieceHeight);

            arryIsPieceLocked[pos] = false;
            arryPieceEndPos[c][r] = pos;
            pos++;
        }
    }

然后我使用辅助方法为每个部分应用蒙版

private Bitmap maskMethod(Bitmap bmpOriginal, Bitmap bmpMask) {

    // adjust mask bitmap if size is not the size of the puzzle piece
    if (bmpMask.getHeight() != mPieceHeight ||
        bmpMask.getWidth() != mPieceWidth) {
        Log.e("TEST", "Resize Error :: H (mask): " + bmpMask.getHeight() + " // W (mask): " +
            bmpMask.getWidth());
        Log.d("TEST", "Resize Error :: H (norm): " + mPieceHeight + " // W (norm): " +
            mPieceWidth);

    }

    Canvas canvas = new Canvas();
    Bitmap combine = Bitmap.createBitmap(bmpOriginal.getWidth(), bmpOriginal.getHeight(), Bitmap.Config.ARGB_8888);
    canvas.setBitmap(combine);
    Paint paint = new Paint();
    paint.setFilterBitmap(false);

    canvas.drawBitmap(bmpOriginal, 0, 0, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    canvas.drawBitmap(bmpMask, 0, 0, paint);
    paint.setXfermode(null);

    return combine;
}

我一直在阅读贝塞尔曲线和 openGL。这些我都不是很熟悉,而且非常复杂。我想在拼图方面得到一些帮助,以便我可以举一个例子来说明它是如何完成的。

【问题讨论】:

    标签: java android opengl-es bezier


    【解决方案1】:

    贝塞尔曲线可能很复杂,但我们可以“作弊”,首先使用 Catmul-Rom 曲线定义拼图头(它具有实际通过其控制点的良好特性),然后将它们简单地转换为贝塞尔曲线(因为它们都是普通的 Hermite 样条)。

    所以:让我们这样做。示例图片:

    到目前为止,我们所做的只是使用相当简单的规则将其拆分。在某种代码中(技术上:Processing):

    int hx = width/4;
    int hy = height/4;
    for(int x = hx; x<width; x+=hx) {
      line(x,0,x,height);
      for(int y = hy; y<height; y+=hy) {
        line(0,y,width,y);
      }
    }
    

    除了一个有趣的图像,它不是很令人兴奋,所以让我们发明一些拼图连接。首先,我们标记这些切口的中心:

    又不是很令人兴奋:

    for(int x = hx/2; x<width; x+=hx) {
      for(int y = hy/2; y<height; y+=hy) {
        ellipse(x + hx/2,y,5,5);
        ellipse(x,y + hy/2,5,5);
      }
    }
    

    但是,我们可以让它变得令人兴奋。对于这些中心中的每一个,我们可以选择向左/向右或向上/向下(取决于边缘)的点,并决定是向左还是向右延伸,然后在“中心”周围创造一些点来给我们我们的 Catmull-Rom 曲线:

    for(int x = hx/2; x<width; x+=hx) {
      for(int y = hy/2; y<height; y+=hy) {
        // horizontal
        ellipse(x-5, y+hy/2, 2,2);
        ellipse(x+5, y+hy/2, 2,2);
    
        boolean up = random(1) < 0.5;
        if(up) {
          ellipse(x-random(5,10), y+hy/2 - random(10,20), 2,2);
          ellipse(x+random(5,10), y+hy/2 - random(10,20), 2,2);
        } else {
          ellipse(x-random(5,10), y+hy/2 + random(10,20), 2,2);
          ellipse(x+random(5,10), y+hy/2 + random(10,20), 2,2);
        } 
    
        // vertical
        ellipse(x+hx/2, y-5, 2,2);
        ellipse(x+hx/2, y+5, 2,2);
        boolean left = random(1) < 0.5;
        if(left) {
          ellipse(x+hx/2-random(10,20), y-random(5,10), 2,2);
          ellipse(x+hx/2-random(10,20), y+random(5,10), 2,2);
        } else {
          ellipse(x+hx/2+random(10,20), y-random(5,10), 2,2);
          ellipse(x+hx/2+random(10,20), y+random(5,10), 2,2);
        }       
      }
    }
    

    我们在这里过度生成,所以我会留给你弄清楚如何防止为最右边和最下面的边缘计算“块连接器”坐标(这应该很容易)。

    那么现在:让我们把它变成一个坐标网格,因为它看起来很不错,我们应该使用 Catmull-Rom 得到相当不错的拼接:

    美丽。

    for (int x = hx/2; x<width; x+=hx) {
      for (int y = hy/2; y<height; y+=hy) {
        // horizontal
        int xs = x-hx/2, 
            ym = y+hy/2, 
            xe = x+hx/2;
        float x3, x4, y1, y2,
              x1 = x-5, 
              x2 = x+5;
    
        boolean up = random(1) < 0.5;
        x3 = x - random(5, 10);
        x4 = x + random(5, 10);
        if (up) {
          y1 = y+hy/2 - random(10, 20);
          y2 = y+hy/2 - random(10, 20);
        } else {
          y1 = y+hy/2 + random(10, 20);
          y2 = y+hy/2 + random(10, 20);
        } 
    
        curve(xs, ym, x1, ym, x3, y1, x4, y2);         
        curve(x1, ym, x3, y1, x4, y2, x2, ym);         
        curve(x3, y1, x4, y2, x2, ym, xe, ym);
    
        // vertical
        int ys = y-hy/2, 
            xm = x+hx/2, 
            ye = y+hy/2;
    
        y1 = y-5; 
        y2 = y+5; 
    
        float y3, y4;
    
        boolean left = random(1) < 0.5;
        y3 = y - random(5, 10);
        y4 = y + random(5, 10);
        if (left) {
          x1 = x+hx/2 - random(10, 20);
          x2 = x+hx/2 - random(10, 20);
        } else {
          x1 = x+hx/2 + random(10, 20);
          x2 = x+hx/2 + random(10, 20);
        }
    
        curve(xm, ys, xm, y1, x1, y3, x2, y4);         
        curve(xm, y1, x1, y3, x2, y4, xm, y2);         
        curve(x1, y3, x2, y4, xm, y2, xm, ye);         
      }
    }
    

    现在您需要在哪里执行剪切以最终得到这些片段应该是相对明显的,但是如果您使用的系统不能执行 Catmull-Rom 但只能执行 Bezier 曲线,则转换真的很简单。前面的代码一直在使用

    curve(x1,x2,y1,y2,x3,y3,x4,y4);
    

    但这是一条 Catmull-Rom 曲线。要得到等效曲线,we can use a Bezier segment of the form:

    bezier(
      x2, y2,
      x2 - (x3-x1)/6, y2 - (y3-y1)/6, 
      x3 + (x4-x2)/6, y3 + (y4-y2)/6, 
      x3, y3
    )
    

    让我们变得令人费解。

    【讨论】:

    • 很好的答案迈克,抱歉我现在才看到这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多