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

如何在p5.js中结合UV坐标使用bezierVertex?

在p5.js中为贝塞尔曲线顶点(bezierVertex)添加UV纹理映射

问题背景

开发需要将UV坐标映射到自定义贝塞尔形状的项目时,发现vertex()函数支持传入u、v参数实现纹理映射,但bezierVertex()的官方文档并未提及UV参数。在GitHub相关讨论中看到的多参数写法实际测试不生效,当前代码仅能实现带UV映射的可拖拽矩形,需要替换为贝塞尔曲线并保留UV映射功能。

解决方案

p5.js中bezierVertex()的UV参数需要为每个贝塞尔控制点单独指定u、v值,正确的2D格式如下:

bezierVertex(控制点2x, 控制点2y, 控制点2u, 控制点2v, 控制点3x, 控制点3y, 控制点3u, 控制点3v, 目标点x, 目标点y, 目标点u, 目标点v)

注意事项:

  • 必须先调用vertex()定义形状的起始顶点(需包含UV参数)
  • 确保已启用textureMode(NORMAL),UV值保持在0-1的标准区间内
  • 若使用3D场景,可在每个坐标参数后添加z值,格式为x, y, z, u, v

修改后的完整代码

sketch.js

let initVariables = {
    mP: false,
};

const mM = [];

class Measurement {
    constructor(initVariables, _ref) {
        this.initVariables = initVariables;
        this.ref = _ref;
        this.pointActive = false;
        this.activePoint = createVector(0, 0);
    }

    checkPoints() {
        // 转换WEBGL坐标为屏幕坐标
        const screenX = this.ref.x + width/2;
        const screenY = this.ref.y + height/2;
        if (dist(mouseX, mouseY, screenX, screenY) < 26) {
            this.pointActive = true;
            if (this.initVariables.mP) {
                this.ref.x = mouseX - width/2;
                this.ref.y = mouseY - height/2;
            }
        } else {
            this.pointActive = false;
        }
    }

    drawMeasurement() {
        if (this.pointActive) {
            noStroke();
            fill(0, 20);
            circle(this.ref.x, this.ref.y, 26);
        }
        stroke(255, 0, 0);
        fill(255, 0, 0);
        strokeWeight(2);
        circle(this.ref.x, this.ref.y, 5);
        noFill();
    }
}

let img;

function preload() {
    img = loadImage('https://t3.ftcdn.net/jpg/02/77/30/98/360_F_277309825_h8RvZkoyBGPDocMtippdfe3497xTrOXO.jpg');
}
 
function setup() {
    createCanvas(600, 500, WEBGL);
    
    // 定义贝塞尔形状的控制点(含UV):起始点+4组贝塞尔控制点
    const measurements = [
        // 起始点
        { x: -150, y: -100, u: 0, v: 0 },
        // 第一组贝塞尔控制点(控制点2、控制点3、目标点)
        { x: -50, y: -150, u: 0.2, v: 0 },
        { x: 50, y: -150, u: 0.8, v: 0 },
        { x: 150, y: -100, u: 1, v: 0 },
        // 第二组贝塞尔控制点
        { x: 200, y: 0, u: 1, v: 0.3 },
        { x: 200, y: 100, u: 1, v: 0.7 },
        { x: 150, y: 150, u: 1, v: 1 },
        // 第三组贝塞尔控制点
        { x: 50, y: 200, u: 0.8, v: 1 },
        { x: -50, y: 200, u: 0.2, v: 1 },
        { x: -150, y: 150, u: 0, v: 1 },
        // 第四组贝塞尔控制点(闭合形状)
        { x: -200, y: 100, u: 0, v: 0.7 },
        { x: -200, y: 0, u: 0, v: 0.3 },
        { x: -150, y: -100, u: 0, v: 0 },
    ];
    
    for(let measurement of measurements){
        const m = new Measurement(initVariables, measurement);
        mM.push(m);
    }
}

function draw() {
    background(237, 239, 237);
    
    textureMode(NORMAL);
    texture(img);
    
    stroke(0);
    strokeWeight(2);
    beginShape();
        // 起始顶点
        vertex(mM[0].ref.x, mM[0].ref.y, mM[0].ref.u, mM[0].ref.v);
        
        // 绘制贝塞尔曲线段,每3个控制点为一组
        for(let i = 1; i < mM.length; i += 3){
            const ctrl2 = mM[i];
            const ctrl3 = mM[i+1];
            const target = mM[i+2];
            bezierVertex(
                ctrl2.ref.x, ctrl2.ref.y, ctrl2.ref.u, ctrl2.ref.v,
                ctrl3.ref.x, ctrl3.ref.y, ctrl3.ref.u, ctrl3.ref.v,
                target.ref.x, target.ref.y, target.ref.u, target.ref.v
            );
        }
    endShape();
    
    // 绘制并检测可拖拽控制点
    for (let dimension of mM) {
        dimension.drawMeasurement();
        dimension.checkPoints();
    }
}

mousePressed = () => {
    initVariables.mP = true;
};

mouseReleased = () => {
    initVariables.mP = false;
};

style.css

html, body {
  margin: 0;
  padding: 0;
}
canvas {
  display: block;
}

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />
  </head>
  <body>
    <main></main>
    <script src="sketch.js"></script>
  </body>
</html>

代码说明

  • 重构了控制点数据结构,将贝塞尔曲线的每组控制点(控制点2、控制点3、目标点)与对应的UV值绑定
  • 在draw()函数中,先通过vertex()定义起始点,再循环调用bezierVertex()绘制完整的贝塞尔形状,每个控制点都传入对应的u、v参数
  • 优化了坐标转换逻辑,统一使用width/2和height/2计算屏幕坐标,提升代码通用性

内容的提问来源于stack exchange,提问作者mrconcerned

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 06:12:09