You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于p5.js的3D画布网格对齐问题及网格图片添加需求

透视网格对齐与网格内2D图片实现方案

一、修复Y轴透视网格对齐问题

透视下的网格横线不能用均分间距,近大远小的视觉效果要求横线间距从远到近逐步递增。结合你已有的四个顶点坐标,可通过非线性插值调整Y轴分割点的位置:

核心思路

放弃均分的t值(即t = i / 行数),改用增长速率先慢后快的函数生成t,比如平方根函数Math.sqrt(i / 行数),以此模拟透视效果。如果匹配度不够,可调整指数(如Math.pow(i / 行数, 0.6)或Math.pow(i / 行数, 1.5)),直到横线与背景图完全对齐。

代码示例(React + p5.js)

// 假设你已定义四个顶点坐标
const topLeft = createVector(100, 50);
const topRight = createVector(700, 50);
const bottomLeft = createVector(50, 550);
const bottomRight = createVector(750, 550);

const numRows = 14; // Y轴14格
const numCols = 12; // X轴12格

function draw() {
  background(0);
  // 先绘制背景图(你已实现的部分)
  // image(backgroundImg, 0, 0, width, height);

  // 绘制透视横线
  for (let i = 0; i <= numRows; i++) {
    // 用平方根函数生成透视化的t值,可按需调整指数
    const t = Math.sqrt(i / numRows);
    // 计算当前横线的左右端点
    const leftX = lerp(topLeft.x, bottomLeft.x, t);
    const leftY = lerp(topLeft.y, bottomLeft.y, t);
    const rightX = lerp(topRight.x, bottomRight.x, t);
    const rightY = lerp(topRight.y, bottomRight.y, t);
    // 绘制横线
    line(leftX, leftY, rightX, rightY);
  }

  // 保留你已对齐的竖线绘制逻辑
  for (let j = 0; j <= numCols; j++) {
    const t = j / numCols;
    const topX = lerp(topLeft.x, topRight.x, t);
    const topY = lerp(topLeft.y, topRight.y, t);
    const bottomX = lerp(bottomLeft.x, bottomRight.x, t);
    const bottomY = lerp(bottomLeft.y, bottomRight.y, t);
    line(topX, topY, bottomX, bottomY);
  }
}

二、在网格框中添加2D图片

完全可以实现,利用p5.js的texture()方法将图片映射到透视网格框的四边形上,步骤如下:

1. 预加载图片

确保图片在绘制前加载完成,可通过p5的preload函数或React状态管理加载状态:

let gridImg; // 单张示例图片,多图可改用数组存储

function preload() {
  gridImg = loadImage('path/to/your/image.png');
}

2. 绘制带图片的网格框

在draw函数中遍历每个网格框,计算其四个顶点坐标后,用纹理映射绘制图片:

function draw() {
  // ... 先绘制背景图和网格线 ...

  // 遍历所有网格框
  for (let i = 0; i < numRows; i++) {
    for (let j = 0; j < numCols; j++) {
      // 计算当前网格上下两行的透视t值
      const tTop = Math.sqrt(i / numRows);
      const tBottom = Math.sqrt((i + 1) / numRows);
      // 计算当前网格左右两列的插值s值
      const sLeft = j / numCols;
      const sRight = (j + 1) / numCols;

      // 计算网格框的四个顶点坐标
      const tl = createVector(
        lerp(lerp(topLeft.x, topRight.x, sLeft), lerp(bottomLeft.x, bottomRight.x, sLeft), tTop),
        lerp(lerp(topLeft.y, topRight.y, sLeft), lerp(bottomLeft.y, bottomRight.y, sLeft), tTop)
      );
      const tr = createVector(
        lerp(lerp(topLeft.x, topRight.x, sRight), lerp(bottomLeft.x, bottomRight.x, sRight), tTop),
        lerp(lerp(topLeft.y, topRight.y, sRight), lerp(bottomLeft.y, bottomRight.y, sRight), tTop)
      );
      const br = createVector(
        lerp(lerp(topLeft.x, topRight.x, sRight), lerp(bottomLeft.x, bottomRight.x, sRight), tBottom),
        lerp(lerp(topLeft.y, topRight.y, sRight), lerp(bottomLeft.y, bottomRight.y, sRight), tBottom)
      );
      const bl = createVector(
        lerp(lerp(topLeft.x, topRight.x, sLeft), lerp(bottomLeft.x, bottomRight.x, sLeft), tBottom),
        lerp(lerp(topLeft.y, topRight.y, sLeft), lerp(bottomLeft.y, bottomRight.y, sLeft), tBottom)
      );

      // 绘制带纹理的网格框
      push();
      beginShape();
      texture(gridImg);
      // 对应图片的UV坐标(0,0为左上角,1,1为右下角)
      vertex(tl.x, tl.y, 0, 0);
      vertex(tr.x, tr.y, 0, 1);
      vertex(br.x, br.y, 0, 1);
      vertex(bl.x, bl.y, 0, 0);
      endShape(CLOSE);
      pop();
    }
  }
}

说明

  • 如果每个网格需要不同图片,可将图片存入数组,通过i和j索引获取对应图片。
  • 若图片拉伸效果不符合预期,可调整UV坐标(比如vertex(tl.x, tl.y, 0, 0)改为vertex(tl.x, tl.y, 0.2, 0.2))实现局部裁剪。

内容的提问来源于stack exchange,提问作者mr.asahd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 22:20:46