1. p5.js 2D绘图函数深度解析
p5.js作为一款创意编程库,其2D绘图功能是大多数初学者的第一站。我们先从最基础的形状绘制开始,逐步深入到高级技巧。
1.1 基础形状绘制实战
在p5.js中,所有2D图形都基于坐标系绘制。画布的左上角是原点(0,0),x轴向右延伸,y轴向下延伸。理解这一点对精确定位至关重要。
矩形绘制技巧:
javascript复制// 标准矩形绘制
rect(100, 100, 200, 150); // (x,y,width,height)
// 圆角矩形进阶用法
rect(100, 300, 200, 150, 20, 10, 30, 40); // 分别设置四个角的圆角半径
注意:默认情况下,rect()的坐标参考点是左上角。通过rectMode(CENTER)可以改为中心点参考,这在需要图形居中对齐时特别有用。
圆形与椭圆绘制差异:
javascript复制// 正圆绘制
circle(400, 200, 100); // (x,y,diameter)
// 椭圆绘制
ellipse(400, 400, 150, 80); // (x,y,width,height)
实际项目中,我经常遇到初学者混淆circle和ellipse的参数顺序。记住:circle使用直径,而ellipse使用宽高。当宽高相等时,ellipse就变成了圆。
1.2 高级形状绘制技巧
自定义多边形绘制:
javascript复制beginShape();
vertex(50, 50); // 顶点1
vertex(150, 25); // 顶点2
vertex(160, 75); // 顶点3
vertex(200, 80); // 顶点4
vertex(170, 120);// 顶点5
endShape(CLOSE); // CLOSE参数自动闭合图形
贝塞尔曲线实战:
javascript复制// 二次贝塞尔曲线
quadraticVertex(cx, cy, x2, y2);
// 三次贝塞尔曲线
bezierVertex(x2, y2, x3, y3, x4, y4);
在最近的一个数据可视化项目中,我使用贝塞尔曲线创建了平滑的连接线,相比直线更能引导用户视线。关键是要理解控制点的作用:
- 第一个控制点决定曲线起始方向
- 第二个控制点决定曲线结束方向
- 曲线一定会经过起点和终点,但不一定经过控制点
2. p5.js 3D图形开发指南
2.1 WEBGL模式基础配置
要使用3D功能,必须在createCanvas()中显式声明WEBGL渲染器:
javascript复制function setup() {
createCanvas(800, 600, WEBGL);
}
3D场景必备元素:
- 光源:没有光源,3D物体将不可见
- 材质:决定物体如何反射光线
- 相机控制:orbitControl()实现鼠标交互
2.2 3D基本形状详解
立方体与长方体:
javascript复制// 立方体
box(50); // 边长50
// 长方体
box(100, 60, 30); // 长宽高
球体参数优化:
javascript复制sphere(60, 24, 16); // (半径,经度分段,纬度分段)
分段数越高,球体越圆滑,但性能消耗越大。在VR项目中,我通常从低分段开始,根据设备性能逐步增加。
圆柱体与圆锥:
javascript复制// 圆柱体
cylinder(30, 80); // (半径,高度)
// 圆锥
cone(40, 100); // (底面半径,高度)
2.3 3D变换核心技巧
平移与旋转:
javascript复制push(); // 保存当前状态
translate(100, 50, -200); // 移动
rotateX(PI/4); // 旋转
box(50);
pop(); // 恢复状态
重要提示:一定要使用push()/pop()包裹变换操作,否则后续绘制都会受到影响。这是新手最常见的错误之一。
在开发3D产品展示时,我创建了这样的工具函数来简化重复定位:
javascript复制function drawAt(position, size) {
push();
translate(position.x, position.y, position.z);
box(size);
pop();
}
3. 文字处理高级技巧
3.1 2D文字渲染优化
多语言支持:
javascript复制textFont('SimHei'); // 中文字体
textSize(24);
text('你好,世界!', 100, 100);
文字测量与对齐:
javascript复制let txt = "测量文字宽度";
let w = textWidth(txt);
text(txt, (width - w)/2, height/2); // 水平居中
在信息图项目中,我经常需要动态调整文字大小以适应容器:
javascript复制function fitText(txt, maxWidth) {
let size = 32;
textSize(size);
while(textWidth(txt) > maxWidth && size > 8) {
size--;
textSize(size);
}
return size;
}
3.2 3D文字解决方案
贴图文字技术:
javascript复制let textGraphic;
function setup() {
createCanvas(800, 600, WEBGL);
textGraphic = createGraphics(400, 200);
// 在离屏画布上绘制文字
textGraphic.background(255, 0); // 透明背景
textGraphic.fill(255, 0, 0);
textGraphic.textSize(32);
textGraphic.text("3D文字", 200, 100);
}
function draw() {
background(240);
texture(textGraphic);
plane(400, 200);
}
性能优化建议:
- 预渲染静态文字
- 重用graphics对象
- 合理控制贴图分辨率
在AR应用中,我发现将文字贴图分辨率控制在1024x1024以内可以获得最佳性能平衡。
4. 颜色系统深度解析
4.1 颜色模式对比
RGB与HSL转换:
javascript复制colorMode(RGB); // 默认模式
fill(255, 0, 0); // 红色
colorMode(HSL, 360, 100, 100);
fill(0, 100, 50); // 也是红色
颜色混合技巧:
javascript复制let c1 = color(255, 0, 0);
let c2 = color(0, 0, 255);
let mixed = lerpColor(c1, c2, 0.5); // 50%混合
4.2 3D材质系统
常用材质类型:
javascript复制ambientMaterial(255,0,0); // 环境材质
specularMaterial(0,255,0); // 镜面材质
normalMaterial(); // 法线材质
在开发3D编辑器时,我创建了材质预览组件帮助用户选择:
javascript复制function showMaterialPreview(x, y, matFunc) {
push();
translate(x, y);
matFunc();
box(30);
pop();
}
5. 性能优化与调试技巧
5.1 常见性能瓶颈
- 过多的图形绘制调用
- 高分辨率贴图
- 复杂的3D几何体
- 频繁的内存分配
优化策略:
javascript复制// 使用beginShape/endShape批量绘制
beginShape();
for(let v of vertices) {
vertex(v.x, v.y);
}
endShape();
// 重用对象
let graphics = createGraphics(100,100);
// 而不是每次draw都新建
5.2 调试工具
控制台输出:
javascript复制console.log('当前帧率:', frameRate());
性能监视器:
javascript复制function draw() {
let start = millis();
// 绘制代码...
let duration = millis() - start;
if(duration > 16) console.warn('帧耗时过长:', duration);
}
在复杂项目中,我通常会实现一个简易的性能面板:
javascript复制let stats = {
fps: 0,
drawCalls: 0
};
function draw() {
stats.drawCalls = 0;
// ...绘制代码
stats.fps = frameRate();
if(frameCount % 60 === 0) {
console.table(stats);
}
}
6. 实战案例:创建一个交互式3D画廊
让我们综合运用所学知识,构建一个3D图片画廊:
javascript复制let images = [];
let angle = 0;
function preload() {
for(let i=0; i<6; i++) {
images[i] = loadImage(`image${i}.jpg`);
}
}
function setup() {
createCanvas(800, 600, WEBGL);
angleMode(DEGREES);
}
function draw() {
background(0);
orbitControl();
// 环境光
ambientLight(100);
// 定向光
directionalLight(255, 255, 255, -1, 1, -1);
// 旋转画廊
rotateY(angle);
angle += 0.5;
// 排列图片
for(let i=0; i<6; i++) {
push();
rotateY(i * 60);
translate(200, 0, 0);
texture(images[i]);
plane(150, 100);
pop();
}
}
实现要点:
- 使用preload确保图片加载完成
- 合理设置光源增强立体感
- 使用rotateY均匀分布图片
- 添加缓慢旋转创造动态效果
这个案例展示了如何将2D图片映射到3D空间,是电商产品展示的常见技术。在我的实际工作中,曾用类似技术为客户创建了虚拟展厅,获得了很好的用户反馈。