P3D

Daniel Shiffman

有五种渲染模式: 默认渲染器、 P2D 、 P3D 、 PDF 和 SVG。要使用非默认渲染器,可以通过 size() 函数指定。

void setup() {size(200,200,P3D);
}

现在,你可能会想: “我应该选择哪种渲染模式,为什么?” 模式本身告诉处理在绘制显示窗口时幕后要做什么。例如,默认渲染器使用现有的 Java 2D 库来绘制形状、设置颜色、显示文本等。在决定使用哪个渲染器时,您正在平衡许多因素: 速度、准确性和可用功能的一般有用性。在大多数情况下,特别是当您第一次学习处理时,您将需要使用默认渲染器设置。在 2D 绘图时,它提供了最优雅和准确的结果。

如果出现以下情况之一,建议切换到 P2D 或 P3D:

  • Y您正在 3D 绘图!在三维空间中,第三个轴 (z轴) 是指任何给定点的深度。像素在窗户前面或后面生存多远?现在,我们都知道在你的屏幕前面或后面没有实际的像素漂浮在空中!我们在这里谈论的是如何使用理论 z轴在您的处理窗口中创建三维空间的错觉。这需要 P3D。
  • 你希望你的草图运行得更快!P2D 和 P3D 利用兼容 OpenGL 的图形硬件。换句话说,在窗口中绘制所有像素所需的一些工作可能发生在计算机的显卡上,这通常更有效。请记住,OpenGL 不是让任何草图更快的魔法精灵尘埃 (尽管它很接近),你还需要仔细考虑你用来绘图的技术。特别是,使用 PShape 中可用的新 “形状记录” 功能 (请参阅 PShape 教程) 可以大大提高 P3D 模式下的速度。
  • 您正在 2D 绘图,但希望使用默认渲染器中不可用的特定图形效果!某些图形功能仅在 P3D 中可用,例如纹理和照明 (见下文)。

3D 转换

在我们开始 3D 绘图之前,重要的是要注意,一旦我们放弃 3D 空间的错觉,一定程度的控制必须放弃给 P3D 渲染器。您再也无法像使用 2D 形状那样知道精确的像素位置,因为 2D 位置将被调整以产生 3D 透视的错觉。

为了在三维点绘制一些东西,坐标按照你期望的顺序指定: x,y,z笛卡尔 3D 系统通常被描述为 “左撇子” 或 “右撇子”。如果你的食指指向正 y 方向 (向下),拇指指向正 x 方向 (向右),你手指的其余部分将指向正 z 方向。如果你用左手做同样的事情,那是左手。在处理中,系统是左撇子,如下所示:

换句话说,积极正在向你袭来,消极正在远离你。假设我们想使用 P3D 绘制一个向查看器移动的矩形。我们知道,要绘制一个矩形,rect() 函数需要四个参数: x 位置、 y 位置、宽度和高度。

rect(x,y,w,h);

我们的第一本能可能是在 rect() 函数中添加另一个参数。

rect(x,y,z,w,h);

然而,这是不正确的。为了在处理中为形状指定 3D 坐标,必须使用 translate()。现在,translate() 并不仅限于 3D 草图,并且在 2D 中非常常用。事实上,有一个完整的 2D 转换教程,我建议你现在就停下来阅读,除非你已经习惯了处理中平移 (和旋转) 的概念。然而,假设您已经熟悉 translate() 在 2D 中的工作方式,除了添加一个参数之外,这里没有很多东西可以学习。在 2D 中,翻译看起来像: “翻译 (x,y)”,3D 我们再添加一个参数:"translate(x,y,z)".

float x,y,z;
void setup() {size(200,200,P3D);x = width/2;y = height/2;z = 0;
}
void draw() {translate(x,y,z);rectMode(CENTER);rect(0,0,100,100);z++; //矩形随着 z 的增量向前移动。
}

第三维度也打开了围绕不同轴旋转的可能性。当我们在处理中说普通的旧旋转 () 时,我们真正说的是围绕 z轴旋转 (即在窗户本身的平面上旋转)。在 3D 中,等效的是 rotateZ()。

size(200, 200, P3D);
background(100);
rectMode(CENTER);
fill(51);
stroke(255);
translate(100, 100, 0);
rotateZ(PI/8);
rect(0, 0, 100, 100);

我们也可以围绕 x 轴和 y 轴旋转。

rotateX(PI/8);

rotateY(PI/8);

以及一次多个轴。

translate(100, 100, 0);
rotateX(PI/8);
rotateY(PI/8);
rotateZ(PI/8);
rect(0, 0, 100, 100);

3D 形状

一旦你知道如何平移和围绕三维坐标系旋转,你就可以绘制一些三维形状。您可能对在 2D 中绘制形状非常满意,无论是基元 (line(),rect(),椭圆 (),三角形 () 等) 还是自定义 (beginShape(),结束形状 () 和顶点 ())。

好消息是 3D 中的形状以几乎相同的方式工作。您可以免费获得一些原始形状,例如 box() 和 sphere(),以及可以通过调用顶点 () 来制作的自定义形状。

size(640,360,P3D);
background(0);
lights();
pushMatrix();translate(130, height/2, 0);rotateY(1.25);rotateX(-0.4);noStroke();box(100);popMatrix();pushMatrix();translate(500, height*0.35, -200);noFill();stroke(255);sphere(280);
popMatrix();

另请参阅: 原始 3d

在上面的示例中,请注意函数 box() 和 sphere() 分别只使用一个参数: size。这些 3D 形状不能通过参数定位,而是应该使用前面描述的 translate() 和 rotate() 方法。

通过并排放置多个多边形,使用 beginShape() 、 endShape() 和顶点 () 绘制自定义 3D 形状。在 3D 中,顶点 () 函数采用 3 个参数: x 、 y 和 z。假设我们想画一个由四个三角形组成的四边金字塔,所有三角形都连接到一个点 (“顶点”) 和一个平面 (“底部”)。

size(640, 360, P3D);
background(0);
translate(width/2, height/2, 0);
stroke(255);
rotateX(PI/2);
rotateZ(-PI/6);
noFill();
beginShape();vertex(-100, -100, -100);vertex( 100, -100, -100);vertex(   0,    0,  100);vertex( 100, -100, -100);vertex( 100,  100, -100);vertex(   0,    0,  100);vertex( 100, 100, -100);vertex(-100, 100, -100);vertex(   0,   0,  100);vertex(-100,  100, -100);vertex(-100, -100, -100);vertex(   0,    0,  100);
endShape();

注意以上如何往往更指定顶点位置使用标准化单位 (即。1 像素) 和相对于原点 (0,0,0)。然后使用矩阵变换设置形状的大小和位置: translate() 、 rotate() 和 scale()。有关在 3D 中构建的更复杂的自定义形状的一些示例,请查看这些示例: RGB 立方体、顶点、环面、等深线。

纹理

使用 P3D 渲染器,您可以像在 2D 中一样加载和显示图像 (请参阅: 图像和像素教程)。变换下涵盖的所有内容都可以应用于图像; 它们可以在虚拟 3D 空间中进行翻译、旋转和缩放。然而,除了以老式的方式绘制图像之外,图像还可以制成 “纹理” 并应用于形状。当您希望 3D 形状类似于真实世界的对象时,这特别有用。例如,在球体上应用地球图像作为纹理将产生一个球体。要将图像作为纹理应用于形状,我们首先需要使用 beginShape() 和 endShape() 定义形状,如上一节所示。假设您正在绘制一个矩形,如下所示:

size(640, 360, P3D);
background(0);
translate(width/2, height/2);
stroke(255);
fill(127);
beginShape();
vertex(-100, -100, 0);
vertex( 100, -100, 0);
vertex( 100,  100, 0);
vertex(-100,  100, 0);
endShape(CLOSE);

上面的例子是一个简单的正方形,有四个顶点,一个白色的轮廓,一个灰色的填充。要将图像应用于形状,我们必须遵循三个步骤。

1) 将图像加载到 PImage 对象中。

PImage img;
void setup() {size(640, 360, P3D);img = loadImage("berlin-1.jpg");
}

2) 调用纹理 ()。纹理 () 函数必须在 beginShape() 和 endShape() 之间以及对顶点 () 的任何调用之前调用。纹理 () 函数只接收一个参数,即将作为纹理应用的 PImage。

void draw() {background(0);  translate(width / 2, height / 2);stroke(255);fill(127);beginShape();texture(img);
}

一旦我们指定了纹理本身,我们就必须定义图像到形状本身的映射。这是一个简单的问题,当形状是矩形 (形状的四个角映射到图像的四个角),但是当形状中有更多的顶点时 (例如在上面的 globe 示例中),会变得更加复杂。为了定义映射,在对顶点 () 的每次调用中增加两个参数 (通常称为 u 和 v)。默认情况下,用于 u 和 v 的坐标是根据图像的像素大小指定的,但是可以使用 textureMode() 更改此关系。此外,当使用纹理时,填充颜色将被忽略。相反,使用 tint() 指定纹理应用于形状时的颜色。

示例: 纹理四边形

void draw() {background(0);translate(width / 2, height / 2);beginShape();texture(img);vertex(-100, -100, 0, 0,   0);vertex( 100, -100, 0, 400, 0);vertex( 100,  100, 0, 400, 400);vertex(-100,  100, 0, 0,   400);endShape();
}

如果以上似乎是一个微不足道的例子,那是因为它是。毕竟,如果我们只是要纹理一个正方形,我们可以使用 image() 绘制图像。然而,理解上述过程打开了一个可能性的世界,因为我们现在可以将图像纹理应用于任意 2D 和 3D 形状。有关更复杂映射的一些示例,请查看纹理三角形、纹理圆柱体、纹理立方体和纹理球体。

如 PShape 教程中所述,您还可以使用 setTexture() 函数对 PShape 对象进行纹理处理。PShape 的 setTexture() 自动纹理形状,而无需指定 uv 坐标,对于简单的场景很有用,比如纹理化球体 (使用 beginShape() 和 endShape() 将非常复杂 (如纹理球体所示)。下面的代码演示了使用 PShape 进行纹理处理是多么容易。

PImage img;
PShape globe;void setup() {img = loadImage("earth.jpg");globe = createShape(SPHERE, 50);globe.setTexture(img);
}

照明

在 P3D 中,您还可以操作场景中元素的照明。当然,就像三维绘图是一种错觉一样,在加工草图中添加照明是对现实世界照明理念的模拟,目的是创造各种效果。这是特别有用的,因为一些物体 (如球体) 在被照亮之前不会出现三维。

如果您不想深入了解为 3D 场景设置自定义照明的细节,您可以使用处理的灯光 () 功能来设置默认照明。请看下面的示例,其中球体仅在按下鼠标时以默认照明点亮。

void setup() {size(200, 200, P3D);
}
void draw() {background(0);translate(100, 100, 0);if (mousePressed) {lights();}noStroke();fill(255);sphere(50);
}

注意在 draw() 中如何包含对 lights() 函数的调用。就像矩阵变换一样,每次通过 draw() 重置 3D 场景,因此必须包括任何照明以保持持久性。

为了为场景设置自定义照明,有四种不同的灯光。

  • ambientLight() --环境光不是来自特定的方向,光线在周围反弹得太多,以至于物体从四面八方均匀发光。环境灯几乎总是与其他类型的灯结合使用。环境光是用 RGB 颜色指定的,也可以用灯的 xyz 位置指定。例如,可以将蓝色环境光添加到场景中,如下所示:

ambientLight(0,0,255);
  • directionalLight() -- 定向光来自一个方向,当直接撞击表面时,它会更强,如果以温和的角度撞击,它会更弱。撞击表面后,定向光向各个方向散射。使用 RGB 颜色和定义灯光方向的 xyz 向量指定方向灯光。例如,可以将来自场景下方的绿灯添加到场景中,如下所示:

directionalLight(0, 255, 0, 0, -1, 0);
  • spotLight()-- 聚光灯类似于定向光,但允许您以更大的特异性控制照明效果。就像以前一样,光线是用颜色和方向定义的。然而,它也需要光线的 xyz 位置以及控制聚光灯锥的角度。小角度值将导致高度聚焦的光线,较大角度将导致更多的光线清洗。最后,最后一个参数决定了光线的浓度,光线朝向聚光灯锥中心的偏差有多大。以下是集中红灯所需的参数,位于处理窗口的前面,并直接指向后面。

    • 红色: 255, 0, 0
    • 位于处理窗口的前面: width/2, height/2, 400
    • 向后直指: 0, 0, -1
    • 小角度: PI/4
    • 浓度: 2

总的来说,它看起来像:

spotLight(255, 0, 0, width/2, height/2, 400, 0, 0, -1, PI/4, 2);
  • pointLight() -- 点光源是 180 度锥的聚光灯。要创建点光源,只需要 RGB 颜色和位置。
pointLight(255, 0, 0, width/2, height/2, 400);

有关处理中照明的其他示例,请查看: Lights on off, Spot, Directional, Reflection.

透视

P3D 模式由两种不同的 “投影” 模式组成,它们控制渲染器创建 3D 错觉的方式。“透视” 模式是默认模式,它使用的技巧是显示更远的更小的对象。这种效应通常被称为 “缩短”。在大多数情况下,您不需要指定透视投影的参数,但是您可以使用透视 () 函数。函数的参数定义具有截断金字塔形状的查看体积。靠近体积前部的对象显示其实际大小,而更远的对象显示更小。三角形有一个视野 (弧度角),一个纵横比,以及定义裁剪平面的最大和最小 z 位置 (处理实际上会费心去渲染东西的距离和距离)。一个示例 (重新创建默认透视图) 如下所示:

float fov = PI/3;
float cameraZ = (height/2.0) / tan(fov/2.0);
perspective(fov, float(width)/float(height), cameraZ/10.0, cameraZ*10.0);

你并不经常需要改变这些参数,但是如果你改变了,改变视野 (“fov”) 往往具有放大和缩小对象的效果 (随着观看量的增长和缩小)并且更改纵横比会扭曲对象的渲染,使对象看起来更胖或更瘦。举个例子,看看: 透视。

P3D 中可用的其他投影模式称为 “正交” 投影。在正交模式下,所有具有相同尺寸的对象都显示相同的大小,无论它们是靠近相机还是远离相机。这通常用于实现某种视觉风格,例如在像 Q 伯特这样的早期视频游戏中发现的那种。要启用正投影,您需要做的就是调用正交 () 不需要任何参数,尽管您会看到有一些可选的参数来定义裁剪平面。以下示例显示了两种投影模式下的场景,具体取决于是否按下鼠标。

(左图像为透视,右图像为正投影)

void setup()  {size(640, 360, P3D);noStroke();fill(204);
}
void draw()  {background(0);lights();if(mousePressed) {float fov = PI/3.0; float cameraZ = (height/2.0) / tan(fov/2.0); perspective(fov, float(width)/float(height), cameraZ/2.0, cameraZ*2.0); } else {ortho(-width/2, width/2, -height/2, height/2);}translate(width/2, height/2, 0);rotateX(-PI/6); rotateY(PI/3); box(160);
}

相机

当在处理窗口中查看 3D 场景时,我们可以将我们对场景的视图视为相机。放大到离物体更近的地方,我们可以想象一个相机放大。围绕场景旋转,相机旋转。当然,没有实际的相机,这只是一个方便的设备,帮助我们了解如何遍历 3D 场景。通过使用 translate() 、 rotate() 和 scale() 来操纵我们的场景视图,可以在 draw() 的开头通过巧妙的变换来模拟相机。然而,为了方便起见,还有一个 camera() 函数,其目的也是模拟相机。该函数将相机定义为具有 “眼睛位置”,即相机位置,一个场景 “中心”,告诉相机指向哪条路,以及垂直对齐相机的向上轴。

默认的相机位置基本上就在你的眼睛之间: 窗口前面的一个位置直接向上对齐,指向屏幕。这是默认位置的数字。

  • 眼睛位置: width/2, height/2, (height/2) / tan(PI/6)
  • 场景中心: width/2, height/2, 0
  • 向上轴: 0, 1, 0

当用代码编写时,这看起来像:

camera(width/2, height/2, (height/2) / tan(PI/6), width/2, height/2, 0, 0, 1, 0);

Camera () 函数中的任何参数都可以变成一个变量来模拟相机的运动。例如,通过根据鼠标移动眼睛的 x 位置,你可以围绕一个物体旋转,从不同的角度看到它。

void setup() {size(640, 360, P3D);
}
void draw() {background(0);camera(mouseX, height/2, (height/2) / tan(PI/6), width/2, height/2, 0, 0, 1, 0);translate(width/2, height/2, -100);stroke(255);noFill();box(200);
}

如果根据鼠标移动眼睛位置和场景中心,则可以创建平移效果。

void setup() {size(640, 360, P3D);
}
void draw() {background(0);camera(mouseX, height/2, (height/2) / tan(PI/6), mouseX, height/2, 0, 0, 1, 0);translate(width/2, height/2, -100);stroke(255);noFill();box(200);
}

【24】processing-立体(中文)相关推荐

  1. 以太坊燃烧第一个24小时,中文社区在关心什么?

    8月5日,在区块高度#12965000(北京时间8月5日20:33),备受瞩目的以太坊伦敦升级完成.伦敦升级涉及众多提案,其中最令人关注的是EIP-1559.该提案引入销毁机制,让链上费用更合理,同时 ...

  2. 【历史上的今天】10 月 24 日:1024 程序员节;中文维基百科上线;苹果发布 iPad mini

    整理 | 王启隆 透过「历史上的今天」,从过去看未来,从现在亦可以改变未来. 今天是 2021 年 10 月 24 日,大概在 2014 - 2015 年间,中国互联网兴起了一个全新的概念:10 月 ...

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

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

  4. 点阵字体显示系列补记2:关于24点阵汉字显示程序及其修改版本

    自从写完16点阵后,由于没啥事做,就继续看看24点阵是如何显示的.这种规格的点阵是使用UCDOS(虽然下载了,但用不了)中的汉字字库.又千辛万苦找到ASCII码的24点阵,再修改前面的程序,生成24点 ...

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

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

  6. python翻译成中文_Python调用有道智云文本翻译API接口实现“智能”伪原创

    >> 开始伪原创中..\")"],[20,"\n","24:\"OL7j\"|36:131"],[20,&q ...

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

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

  8. 创新杯论文——面向中文专利信息的关系数据库检索优化策略研究及应用

    面向中文专利信息的关系数据库检索优化策略研究及应用 目 录 1     引言... 3 2     中文专利信息检索优化概述... 4 2.1      中文信息检索的概念... 4 2.2      ...

  9. figure字体 latex_如何在 Mac 下的 LaTeX 中使用中文字体?

    提供一个比较全的模板供参考,编译用xelatex: \documentclass[11pt,a4paper]{article} % \documentclass[11pt,a4paper]{repor ...

  10. centos7 postgresql13 安装 zhparser,配置中文全文检索

    目录 安装postgresql13数据库 安装中文检索组件 使用全文检索 使用帮助 自定义中文字典 高亮显示检索匹配内容 控制检索结果数目 待完善内容 问题总结 需求:使用postgresql13版本 ...

最新文章

  1. Angular应用中配置全局路径映射
  2. pandas KeyError [‘1‘] not found in axis 错误的解决方法
  3. Juniper批量新增用户命令工具
  4. RocketMQ Broker的最佳实践
  5. 标准正弦波变频电源调制方式的实现
  6. SciSharpCube:容器中的SciSharp,.NET机器学习开箱即用
  7. jzoj3382-七夕祭【贪心,中位数】
  8. java - 菱形输出
  9. PAT甲级1017 (模拟排序)
  10. Javascript第四章匿名函数第七课
  11. Typecho中的gravatar头像无法加载
  12. 小D课堂 - 新版本微服务springcloud+Docker教程_4-04 高级篇幅之服务间调用之负载均衡策略调整实战...
  13. 原生 JS 撸一个轮播图(支持拖拽切屏)
  14. Atitit.软件开发的最终的设计 dsl化,ast化(建立ast, 解析执行ast)
  15. C语言爱心动态生日快乐代码
  16. 解决XeLaTex编译后中文出现乱码的问题
  17. (C语言) 用牛顿迭代法求方程2x^3 - 4x^2 + 3x - 6 = 0在1.5附近的根
  18. 色环电阻阻值如何识别
  19. 34%的出轨率是怎么算的
  20. 美通企业日报 | 2020年中国薪酬预期涨幅6.5%;巴西将对中国游客免签

热门文章

  1. 树莓派4B安装Opencv4.5及配置(无脑式操作)
  2. rfid卡的读写c语言,RFID超高频桌面式USB发卡器
  3. 大规模排行榜系统实践及挑战
  4. 计算机性能测评实验原理,水泵性能试验机测试系统工作原理及试验过程
  5. Python会议室、酒店预订系统源代码
  6. C# 依赖注入 MEF
  7. 服务器搭建本地局域网下载文件(sz下载大文件总是出问题)
  8. 电脑软件:国内最好用解压缩软件 7-Zip 新版本发布
  9. Vue.prototype的使用
  10. Java实训项目--小型书店管理系统(ssm框架)