PShape

Daniel Shiffman

(本教程的源代码在处理示例中。在处理IDE中选择文件→示例,然后选择主题→创建形状。)

使用处理编程时,首先要学习的是如何在屏幕上绘制“原始”形状:矩形、椭圆、直线、三角形等。

rect(x,y,w,h);
ellipse(x,y,w,h);
line(x1,y1,x2,y2);
triangle(x1,y1,x2,y2,x3,y3);

更高级的绘图选项是使用beginShape()和endShape()指定自定义多边形的顶点

beginShape();vertex(x1,y1);vertex(x2,y2);vertex(x3,y3);vertex(x4,y4);// 等;
endShape();

通过将一组绘图函数组合在一起,甚至可以将它们组织到一个类中,可以构建更复杂的形状。

class MyWackyShape {//一些变量//构造器//一些功能//显示形状!void display() {rect(x,y,w,h);ellipse(x,y,w,h);beginShape();vertex(x1,y1);vertex(x2,y2);vertex(x3,y3);vertex(x4,y4);// 等等;endShape();}
}

这一切都很好,会让你走得很远。只有知道上面的情况,你才能画出很少的东西。然而,还有另一个步骤。在某些情况下,这一步骤可以提高渲染速度,并为代码PShape提供更高级的组织模型。

PShape是用于存储形状的数据类型。这些形状可以是由自定义几何图形生成的形状,也可以是从外部文件(如SVG)加载的形状。

原始形状

让我们从使用PShape的一个最简单的例子开始。下面是一个简单的处理draw()方法,它在鼠标后面绘制一个矩形。

void draw() {background(51);stroke(255);fill(127);rect(mouseX,mouseY,100,50);
}

基本的东西。如果这是我们所有的代码,不一定有一个很好的理由使用PShape,但我们将继续推进,并制作一个PShape矩形无论如何作为演示。我们的目标是要有一个变量来存储该变量的颜色和维度,允许我们的draw函数看起来像这样。

void draw() {background(51);shape(rectangle);
}

这个“矩形”是什么?这是个假象。

PShape rectangle;

要初始化PShape,请使用createShape()方法。createShape()的第一个参数是一个常量,该常量指定要生成的PShape的类型。正如我们将在本教程中看到的,有很多选项:椭圆、矩形、圆弧、三角形、球体、长方体、直线、组等等。在这里,我们创建一个基本形状,一个矩形,所以我们使用常量“RECT”,后面的参数是形状的(x,y)位置以及它的尺寸(宽度,高度)。所以现在我们的setup()应该是:

PShape rectangle;
void setup() {size(640,360,P2D);rectangle = createShape(RECT,mouseX,mouseY,100,50);
}

不过,有个大问题。是的,我们希望矩形显示在鼠标位置,但是当草图首先开始mouseX时,mouseY设置为零。在我们循环draw()之前,mouseX和mouseY是不会复活的。重要的是要记住,当使用PShape时,我们真正要做的是配置相对于原点(0,0)的几何体。然后使用translate()、rotate()等变换在屏幕上移动该形状通常是有利的

PShape rectangle;
void setup() {size(640,360,P2D);rectangle = createShape(RECT,0,0,100,50);
}

如果我们想从中心画出矩形:

PShape rectangle;
void setup() {size(640,360,P2D);rectangle = createShape(RECT,-50,-25,100,50);
}

然后我们可以根据鼠标移动它。

void draw() {background(51);translate(mouseX,mouseY);shape(rectangle);
}

PShape对象的一个优点是,除了几何图形外,它还可以存储颜色信息。创建形状以更改其填充或笔划后,请使用setFill()、setStroke()和setStrokeWeight()等方法。

void setup() {size(640,360,P2D);rectangle = createShape(RECT,-50,-25,100,50);rectangle.setStroke(color(255));rectangle.setStrokeWeight(4);rectangle.setFill(color(127));
}

如果要动态更改形状的颜色,也可以在draw()期间调用这些方法。

void draw() {background(51);translate(mouseX, mouseY);rectangle.setFill(color(map(mouseX, 0, width, 0, 255)));shape(rectangle);
}

需要注意的是,与fill()和stroke()不同,必须将全色作为参数传递。i、 e.对于红色填充,不要说“setFill(255,0,0)”,而是说“setFill(color(255,0,0))”。此外,set fill()和set stroke()可以使用布尔参数(例如setFill(false))来打开或关闭给定顶点的填充或笔划,也可以使用整数(例如setFill(i,color(255,0,0))来设置特定顶点的填充或笔划。

请参阅示例“PrimitivePShape”(在“文件”—“示例”—“主题”—“创建形状”下),以获取演示上述所有代码的示例。

自定义形状

pshape也可以配置为自定义顶点。您可能以前做过,没有PShape,只使用beginShape()和endShape()。例如,假设你想在处理过程中画一颗星星。您可能有以下代码:

void draw() {background(51);translate(mouseX, mouseY);fill(102);stroke(255);strokeWeight(2);beginShape();vertex(0, -50);vertex(14, -20);vertex(47, -15);vertex(23, 7);vertex(29, 40);vertex(0, 25);vertex(-29, 40);vertex(-23, 7);vertex(-47, -15);vertex(-14, -20);endShape(CLOSE);
}

在这里,与前面的示例一样,我们的目标是在draw()中将形状本身绘制为对象。

void draw() {background(51);translate(mouseX, mouseY);shape(star);
}

要使用自定义顶点生成PShape,必须首先调用createShape()来生成shape对象,然后对该对象调beginShape()和endShape():

PShape star;
void setup() {size(640,360,P2D);star = createShape();       // 首先创建形状star.beginShape();          // 现在调用beginShape();// 所有的顶点信息都在这里。star.endShape(CLOSE);       // 现在调用endShape(CLOSE);
}

然后,可以通过调用新PShape对象“star”上的函数来指定所有顶点(和颜色)。请注意,这里不需要setFill()和setStroke(),只有在最初创建形状后选择更改颜色。

void setup() {size(640,360,P2D);// 首先创建形状star = createShape();star.beginShape();// 可以设置填充和笔划star.fill(102);star.stroke(255);star.strokeWeight(2);// 这里,我们对一系列顶点进行硬编码star.vertex(0, -50);star.vertex(14, -20);star.vertex(47, -15);star.vertex(23, 7);star.vertex(29, 40);star.vertex(0, 25);star.vertex(-29, 40);star.vertex(-23, 7);star.vertex(-47, -15);star.vertex(-14, -20);star.endShape(CLOSE);
}

请参阅示例“PolygonPShape”(在“文件>示例>主题>创建形状”下),以获取演示上述所有代码的示例。

更多形状

如前所述,使用PShape的一个原因是帮助您组织几何图形。然而,还有另一个原因。假设您有一个星型类,其中有一个display()函数,如下所示:

void display() {pushMatrix();translate(x, y);fill(102);stroke(255);strokeWeight(2);beginShape();vertex(0, -50);vertex(14, -20);vertex(47, -15);vertex(23, 7);vertex(29, 40);vertex(0, 25);vertex(-29, 40);vertex(-23, 7);vertex(-47, -15);vertex(-14, -20);endShape(CLOSE);popMatrix();
}

在draw()中,您将遍历一个星形对象数组,显示每个对象。

void draw() {background(51);for (int i = 0; i < stars.length; i++) {stars[i].display();}
}

试着画500颗左右的星星,你的素描可能会跑得很慢,大约每秒10帧。这是因为这种画法,通常被称为“立即”模式,要求渲染器每次通过绘制每个星星来计算几何体。但这有必要吗?毕竟,一次又一次是同一颗星星。使用PShape可以让处理基本上“记住”恒星的几何结构。绘制存储的几何体(在较低级别的OpenGL语法中称为“顶点缓冲对象”)称为“保留”模式,速度要快得多。这500颗恒星可以用PShape代替以60 FPS的速度轻松渲染。这可以通过将PShape变量作为Star类的一部分来实现。

class Star {PShape s;float x, y;
//然后需要在构造函数中初始化该PShape。这可以直接做,就在课堂上。
Star() {// 首先创建形状s = createShape();s.beginShape();// 可以设置填充和笔划s.fill(102);s.stroke(255);s.strokeWeight(2);// Here, we are hardcoding a series of verticess.vertex(0, -50);s.vertex(14, -20);s.vertex(47, -15);s.vertex(23, 7);s.vertex(29, 40);s.vertex(0, 25);s.vertex(-29, 40);s.vertex(-23, 7);s.vertex(-47, -15);s.vertex(-14, -20);s.endShape(CLOSE);}

如果每个对象本身都有自己的几何体(通过算法生成),则此方法是有意义的。但是,如果每个对象都显示相同的PShape,那么在构造函数本身中传递对PShape的引用可能更有意义。让我们来看看这是如何工作的。假设我们创建了一个名为“Polygon”的泛型类,它引用了一个PShape(在display方法中绘制)。

class Polygon {PShape s;void display() {shape(s);}
}

在前面的例子中,形状是在对象的构造函数中创建的。在这里,我们将演示一种不同的方法来编写通过参数设置形状的构造函数。

Polygon(PShape s_) {s = s_;}

但是,要使其工作,必须在创建对象时传入PShape。下面是在带有setup()的主选项卡中的情况:

Polygon poly;                   // 多边形物体
void setup() {size(640,360,P2D);PShape star = createShape();  // 首先我们要做一个star.beginShape();star.noStroke();star.fill(0, 127);star.vertex(0, -50);star.vertex(14, -20);star.vertex(47, -15);star.vertex(23, 7);star.vertex(29, 40);star.vertex(0, 25);star.vertex(-29, 40);star.vertex(-23, 7);star.vertex(-47, -15);star.vertex(-14, -20);star.endShape(CLOSE);// 通过传入对PShape的引用来生成多边形对象poly = new Polygon(star);
}

这是一种非常灵活的方法。例如,如果有一个PShape对象数组,则可以使用随机PShape创建新的多边形对象。下面是一个简单的实现。

ArrayList polygons;
PShape[] shapes = new PShape[2];                 // An array of PShapes
void setup() {size(640, 360, P2D);smooth();shapes[0] = createShape(ELLIPSE,0,0,100,100);  // Two PShapesshapes[1] = createShape(RECT,0,0,100,100);polygons = new ArrayList();for (int i = 0; i < 25; i++) {int selection = int(random(shapes.length));  // Pick a random indexPolygon p = new Polygon(shapes[selection]);  // Use corresponding PShape to create Polygonpolygons.add(p);}
}

对于完整的示例,请查看“polygonpshapeop1”、“polygonpshapeop2”和“polygonpshapeop3”(在“文件→示例→主题→创建形状”下)。

更多自定义形状

pshape支持在即时模式下可以绘制的所有相同类型的形状。这些包括:点、线、三角形、三角形扇形、三角形条、四边形和四边形条。例如,如果要创建四边形条带,可以说:

/

PShape s = createShape();
s.beginShape(QUAD_STRIP);

如果未指定模式,则该形状可以是任何不规则多边形,如我们在上一个星形示例中看到的。通过不关闭形状,PShape也可以是路径。下面是一个将正弦波作为PShape对象的路径示例。

PShape path = createShape();path.beginShape();float x = 0;//将路径计算为正弦波for (float a = 0; a < TWO_PI; a += 0.1) {path.vertex(x,sin(a)*100);x+= 5;}// 如果你想让形状成为路径,就不要“关闭”它path.endShape();

有关完整实现,请参见示例“PathPShape”。

pshape还包括begincoutor()和endContour()方法。这些方法允许您从另一个形状中剪切一个形状,并在其中创建带有孔的形状。想想画一个字母的轮廓,比如P(用于处理)。P的轮廓可以绘制为一系列顶点,但是要从P的中间敲出相反的形状,需要开始/结束轮廓并绘制内部的路径。下面是一个简单的例子,它在一个外部正方形的内部绘制一个内部正方形。

// 成形
PShape s = createShape();
s.beginShape();
// 外形外部
s.vertex(-100,-100);
s.vertex(100,-100);
s.vertex(100,100);
s.vertex(-100,100);
s.vertex(-100,-100);
// 形状内部
s.beginContour();
s.vertex(-10,-10);
s.vertex(-10,10);
s.vertex(10,10);
s.vertex(10,-10);
s.endContour();
// 成品形状
s.endShape();

请注意,定义负形状的顶点必须与外部形状的方向相反。首先按顺时针顺序为外部形状绘制顶点,然后为内部形状逆时针绘制顶点。

有关完整实现,请参见示例“BeginedConteur”(在“文件→示例→主题→创建形状”下)。

PShape群

PShape的另一个便利之处是能够对形状进行分组。例如,如果你想从一组圆、矩形和自定义多边形中创建一个外星生物呢。如果头部是圆形,身体是矩形,你可能会认为你需要:

PShape head = createShape(ELLIPSE,0,0,50,50);
PShape body = createShape(RECT,0,50,50,100);
shape(head);
shape(body);

当然这是可行的,但如果你能把头部和身体组合成一个形状,那就方便多了。有了一个“小组”,你就可以了。

// 生成父形状
PShape alien = createShape(GROUP);
// 做两个形状
PShape head = createShape(ELLIPSE, 0, 0, 50, 50);
PShape body = createShape(RECT, 0, 50, 50, 100);
// 将两个“子”形状添加到父组
alien.addChild(head);
alien.addChild(body);
// 绘制组
translate(width/2, height/2);
shape(alien);

有关演示将基本形状、自定义多边形和路径组合在一起的PShape的完整示例,请参见“GroupPShape”(在“文件>示例>主题>创建形状”下)。

PShape组允许您构建复杂的形状层次结构。这又允许您通过在父级调用相应的方法来设置子形状的颜色和属性。类似地,通过在层次结构的给定级别调用转换函数,只会影响下面的形状。

加载外部形状文件

pshape还支持加载形状文件,例如SVG(用于2D形状)或OBJ(用于3D形状)。这可以通过loadShape()方法实现。

PShape svg;
void setup() {size(640, 360, P2D);svg = loadShape("star.svg");
}
void draw() {background(255);shape(svg);
}

实时操作PShape的顶点

在使用PShape大约五分钟后,不可避免地会出现一个问题:“如果我想晃动所有顶点,该怎么办?”PShape允许您通过getVertex()和setVertex()方法动态访问和更改顶点。

要在PShape的顶点上迭代,可以从0循环到顶点总数(getVertexCount())。假设一个PShape“s”,这看起来像:

for (int i = 0; i < s.getVertexCount(); i++) {
}//可以使用getVertex()将顶点检索为PVector对象。
for (int i = 0; i < s.getVertexCount(); i++) {PVector v = s.getVertex(i);
}//然后,可以通过操纵PVector并使用setVertex()设置新值来移动该顶点。
for (int i = 0; i < s.getVertexCount(); i++) {PVector v = s.getVertex(i);v.x += random(-1,1);v.y += random(-1,1);s.setVertex(i,v.x,v.y);
}

有关使用Perlin噪波摆动多边形顶点的示例,请参见“WigglePShape”(在“文件”—“示例”—“主题”—“创建形状”下)。

3D和纹理

本教程主要介绍在二维图形环境中使用PShape对象的基础知识。但是,PShape也提供了P3D教程中描述的所有3D功能。主要区别在于,在三维中,顶点是用x、y和z坐标指定的。此外,PShape对象可以使用setTexture()函数自动生成纹理。对于像球体这样的复杂形状,这使事情变得很容易。

PImage img;
PShape globe;void setup() {// 加载图像img = loadImage("earth.jpg");globe = createShape(SPHERE, 50);// 使用图像自动对形状进行纹理处理globe.setTexture(img);
}

【13】processing-平面(中文)相关推荐

  1. PL/SQL Developer 13.0设置中文

    PL/SQL Developer 13.0设置中文 PL/SQL Developer 13.0和之前的版本有些不一样Tools下找不到preferences,因为位置改变了,不在Toos下,它在最上面 ...

  2. 高通 Android 12/13 默认修改中文语言设置

    1.源码路径build/make/target/product/full_base.mk,修改参数PRODUCT_LOCALES:后面你要修改的语言修改其他默认语言一样,举一反三即可.如下图所示 2. ...

  3. qt5.13.2输出中文乱码

    qt5使用qDebug()输出中文乱码,可以在.pro文件中添加以下的代码: #解决中文编译没法通过,输出中文乱码 msvc {QMAKE_CFLAGS += /utf-8QMAKE_CXXFLAGS ...

  4. Processing如何打包导出中文字体

    Processing如何打包导出中文字体 文章目录 Processing如何打包导出中文字体 原理 步骤 用途 原理 使用Processing自带的字体创建工具,创建.vlw字体.该工具为每个char ...

  5. 计算机毕设分词,毕业设计(论文)+计算机科学与技术+中文分词方法研究与实现论文全文.doc...

    毕业论文 中文分词方法研究与实现 计算机工程系学生姓名: 学号: 计算机工程系 计算机科学与技术系 部: 计算机科学与技术 专 业: 指导教师: 诚信声明 本人郑重声明:本设计(论文)及其研究工作是本 ...

  6. 常用的开源中文分词工具

    转载自:  http://www.scholat.com/vpost.html?pid=4477 常用的开源中文分词工具 由于中文文本词与词之间没有像英文那样有空格分隔,因此很多时候中文文本操作都涉及 ...

  7. 对话系统中的中文自然语言理解 (NLU) 任务介绍

    每天给你送来NLP技术干货! 来自:看个通俗理解吧 Chinese Natural Language Understanding, NLU, in Dialogue Systems 1&2 T ...

  8. 开源中文切词工具介绍

    开源中文分词工具介绍 这里介绍常用的开源中文分词工具,大部分是java实现.如果是java生产环境,建议使用ansj.word或HanNlp. Bakeoff是一个国际中文处理比赛,有多个语料,所以每 ...

  9. 代码本色——雪梨的Processing探索·Chapter 0:随机游走

    概述 Chapter 0为我们介绍了随机数.概率和噪声在运动当中起到的变化作用,下面就让我们来好好的了解下这些数学名词,究竟可以起到怎样的公用,最后再让我们来发挥想象进行这些知识的运用创作. 原理介绍 ...

  10. 中文开源汉语分词工具

    本文转载自:http://www.scholat.com/vpost.html?pid=4477 由于中文文本词与词之间没有像英文那样有空格分隔,因此很多时候中文文本操作都涉及切词,这里整理了一些中文 ...

最新文章

  1. android第一天
  2. wxWidgets:wxFloatingPointValidator<T> 类模板用法
  3. Python中从头开始实现神经网络 - 介绍
  4. c++ char*初始化_C开发实战-深入理解指针
  5. php 位运算与权限,PHP中的二进制位运算和权限存储
  6. HTML在线颜色代码选取器源码
  7. 《C和指针》——C语言字符串操作
  8. 设计模式学习笔记——适配器(Adapter)模式
  9. 制作 docker 镜像
  10. 电脑键盘下划线怎么打_电脑键盘失灵怎么办?你应该学会的四种方法
  11. 转发网络《iOS网络编程与云端应用最佳实践》微博转发送书了
  12. python mysql res_python操作mysql(三)查询
  13. 【ubantu18.04 有线网络驱动安装 r8215-9.007.01】
  14. Linux搭建私人饥荒服务器(centos8-64位)
  15. matlab生成vcf,从VCF文件中提取样本数据
  16. 计算机网络p2p应用,[计算机网络-应用层] P2P应用
  17. 安卓软件定做-华为Mate7手机高配版和标准版的区别
  18. 使用安卓手机控制树莓派
  19. 纳尼?华为首席架构师只用434页笔记,就将网络协议给拿下了
  20. 【XSY3904】直线(分块)

热门文章

  1. 冷热分离之OTS表格存储实战
  2. 09-HTML5的多媒体支持
  3. 建立VLAN虚拟局域网
  4. matlab mamdani,模糊推理的Mamdani算法及其Matlab实现
  5. 面试题 JSP的内置对象
  6. 视频教程-实战Go语言:基于开源数据的成语应用-Go语言
  7. Linux —— yum更新时报错,依赖关系有问题
  8. 常见的HTML5开发工具都有哪些
  9. 2022-2028年全球与中国玻璃碎玻璃行业市场需求预测分析
  10. 学习记录:安卓苹果移动端口测点