从4个角落创建一个透视的网格



我正在尝试从其四个角落生成一个点网格。由于可以自由地放置此角落,因此将看起来像网格具有视角。

我已经编写了处理中的以下代码,其中弯道按顺时针顺序(从左上开始)

PVector[][] setGrid(PVector[] corners, int cols, int rows) {
    PVector[][] grid = new PVector[rows][cols];
    for(int y = 0; y < rows; y++) {
        float fY = (float)y / (rows - 1);
        PVector p1 = PVector.lerp(corners[0], corners[3], fY);
        PVector p2 = PVector.lerp(corners[1], corners[2], fY);
        for(int x = 0; x < cols; x++) {
            grid[y][x] = PVector.lerp(p1, p2, (float)x / (cols-1));
        }
    }
    return grid;
}

这会生成带有插值点的网格,但与透视网格不符。所有在线点都是等距的,而在透视上最接近的点应该比最远的点更分开。

,如果可能的话,我将在Java/Processing

中获得一些方向

编辑

澄清我的答案。我定义了4个随机的角点,我想获得创建一个透视变形网格的所有点。请注意,由于透视图DX1!= DX2以及DY1!= DY2。我编写的代码没有这种效果(我知道这一点,但我不知道该怎么做),因为点是插值的DX1 = dx2 = ... = dxi和dy1 = dy2 = ... = dyi

我已经阅读了有关透视转换的信息,但是我不需要转换图像,我只需要获得网格点坐标。

在您的示例图像中,透视效果是通过沿不同长度的边缘保持线的数量来实现的。这就是您的实施,所以老实说我没有看到问题。

这是一个素描,调用您的setGrid():

PVector[] corners;
void setup(){
  size(150,100);
  corners = new PVector[4];
  corners[0] = new PVector(35,20);
  corners[1] = new PVector(15,height-30);
  corners[2] = new PVector(width-10,height-10);
  corners[3] = new PVector(width-30,10);
  noLoop();
}
void draw(){
  background(255);
  PVector[][] results = setGrid(corners, 9, 9);
  for(PVector[] pvs : results){
    for(PVector pv : pvs){
      ellipse(pv.x,pv.y,5,5);
    }
  }
}
PVector[][] setGrid(PVector[] corners, int cols, int rows) {
    PVector[][] grid = new PVector[rows][cols];
    for(int y = 0; y < rows; y++) {
        float fY = (float)y / (rows - 1);
        PVector p1 = PVector.lerp(corners[0], corners[3], fY);
        PVector p2 = PVector.lerp(corners[1], corners[2], fY);
        for(int x = 0; x < cols; x++) {
            grid[y][x] = PVector.lerp(p1, p2, (float)x / (cols-1));
        }
    }
    return grid;
}

...,结果看起来几乎就像您的目标图像。如果您看到不同的东西,也许您正在创建具有非常相似的边缘长度的网格?

如果您想在常规梯形上投射透视图 - 就像一条向远距离的人行道一样 - 请考虑这种方法:

  • https://math.stackexchange.com/questions/337056/a-controlled-trapezoid-transformation-with-perspective-projective-projecton

我已经解决了它采用几何方法:识别来自角落的网格消失点,并从翻译的地平线线插值。我已经为这个网格表演创建了一个课程。

只有2个要求:

  1. 拐角必须以顺时针顺序为顺序。

  2. 网格侧不能平行(无限的消失点)

处理代码:

GridPerspective grid;
void setup() {
    size(600, 600, P2D);
    grid = new GridPerspective(10, 10);
}

void draw() {
    background(0);
    grid.draw();
}
void mouseClicked() {
    grid.addCorner(new PVector(mouseX, mouseY));
}
public class GridPerspective {
    int cols, rows;
    PVector[] corners = new PVector[4];
    int selC;
    PVector[][] points;
    public GridPerspective(int cols, int rows) {
        this.cols = cols;
        this.rows = rows;
    }
    public void addCorner(PVector corner) {
        if(selC < 4) {
            corners[selC++] = corner;
            if(selC == 4) update();
        }
    }
    public void update() {
        if(corners[0] == null || corners[1] == null || corners[2] == null || corners[3] == null) return;
        PVector[] vanishing = new PVector[] {
            linesIntersection(corners[0], corners[3], corners[1], corners[2]),
            linesIntersection(corners[0], corners[1], corners[3], corners[2])
        };
        PVector topHorizon = PVector.sub(vanishing[1], vanishing[0]);
        PVector bottomHorizon = PVector.add(corners[3], topHorizon);
        PVector[] bottomLimits = new PVector[] {
            linesIntersection(corners[3], bottomHorizon, vanishing[0], corners[1]),
            linesIntersection(corners[3], bottomHorizon, vanishing[1], corners[1])
    };
        points = new PVector[rows][cols];
        for(int r = 0; r < rows; r++) {
            PVector bpr = PVector.lerp(corners[3], bottomLimits[0], (float)r / (rows-1));
            for(int c = 0; c < cols; c++) {
                PVector bpc = PVector.lerp(corners[3], bottomLimits[1], (float)c / (cols-1));
            points[r][c] = linesIntersection(bpr, vanishing[0], bpc, vanishing[1]);
            }
        }
    }
    public void draw() {
        if(points != null) {    
            fill(255);
            for(int r = 0; r < rows; r++) {
                for(int c = 0; c < cols; c++) {
                    ellipse(points[r][c].x, points[r][c].y, 4, 4);
                }
            }   
        }
    }
    private PVector linesIntersection(PVector p1, PVector p2, PVector p3, PVector p4) {
        float d = (p2.x-p1.x) * (p4.y - p3.y) - (p2.y-p1.y) * (p4.x - p3.x);
        if(d == 0) return null;
        return new PVector(p1.x+(((p3.x - p1.x) * (p4.y - p3.y) - (p3.y - p1.y) * (p4.x - p3.x)) / d)*(p2.x-p1.x), p1.y+(((p3.x - p1.x) * (p4.y - p3.y) - (p3.y - p1.y) * (p4.x - p3.x)) / d)*(p2.y-p1.y));
    }
}

相关内容

  • 没有找到相关文章

最新更新