语言设定

坐标和变换

p5.js 是创建 2D 图形的强大工具,同时也能够实现 3D 图形。 要开始使用 3D,需要学习一些新概念,本文档将介绍一些对于任何 3D 程序都非常重要的想法。

What is WebGL

WebGL 是一个库,为我们在 Web 浏览器中创建 3D 图形提供了所需的工具。 简单地说,它允许我们做各种数学运算,帮助排列和显示 3D 对象。 通过其特殊的 WebGL 模式,p5.js 可以更容易地与 WebGL 一起使用。

在 3D 中工作引入了许多复杂性,尤其是当一个画面涉及到运动、纹理、光照等方面。 幸运的是,计算机有专门的硬件,非常适合执行这些计算,即图形处理单元(GPU)。 GPU 能够同时处理许多事情,这在处理像素和空间中的许多形状时特别重要。

让我们开始设置 p5.js 来使用 WebGL, 通过将第三个参数传递到 createCanvas()


      function setup() {
        createCanvas(windowWidth, windowHeight, WEBGL);
        describe('a red box on a white background');
      }

      function draw(){
        background(255);
        fill(255,0,0);
        box();
      }
      

3D 坐标空间:在 3D 中定位

如果坐标系统不太清楚,可以重新查看名为 坐标系和形状 的教程。坐标系和形状.

在 2D 和 3D 中工作最基本的区别之一是最明显的:多了一个维度。 除了我们图纸中元素的水平和垂直位置(x 和 y 轴)之外,3D 还增加了深度,即 z 轴。

When drawing in 2D, the point (0,0) is located at the top left corner of the screen. In WebGL mode, the origin of the sketch (0,0,0) is located in the middle of the screen. By default, the x-axis goes left-to-right, y-axis goes up-to-down, and the z-axis goes from further-to-closer.

an illustration showing a 2D coordinate system on the left, showing an origin of (0,0) and a 3D coordinate system on the right, showing an origin of (0,0,0)

变换:3D 图形的位置和大小

p5.js 有一些方法,translate()rotate()scale(),可以用来在空间中定位和定向对象。每个方法都会影响所谓的模型矩阵,它们的集合被称为对象的变换。这些方法对于 2D 和 3D 绘制都可用。translate(), rotate(), 和 scale(), 我们可以使用一些方法在空间中定位和定向对象。每种方法都会影响所谓的模型矩阵。 这些方法的集合被称为对象的变换。这些方法适用于2D和3D绘图。

translate():将对象移动到指定位置

translate() translate() 可以将原点沿指定方向移动, 调用translate()之后绘制的任何内容都将相对于该点定位。 translate() 接受x、y和z值的参数。使用上面的滑块更改盒子的平移量,看看它沿每个轴如何移动。 下面的代码演示了如何在box() 形状上进行简单的平移。


      ...
      // draw a box 100 units to the right
      translate(100,0,0);
      box();
      ..
      

rotate():将对象定向到指定位置

rotate() rotate()可以将之后绘制的内容重新定向方向。

有几种方法可以使对象在3D中旋转。大多数情况下,最简单的方法是调用像rotateX()rotateY()rotateZ()这样的方法rotateX(), rotateY(), 和 rotateZ() 它们分别允许围绕特定轴进行旋转。每种方法都接受一个指定旋转角度的参数。 尝试在上面的示例中移动滑块,查看如何在每个轴上执行旋转。 以下代码展示了这些方法的使用。


      ...
      // rotate X, Y, and Z axes by 45 degrees
      rotateX(QUARTER_PI);
      rotateY(QUARTER_PI);
      rotateZ(QUARTER_PI);
      box();
      ..
      

默认情况下,p5.js将期望角度以弧度为单位。 弧度使用从0- TWO_PI的数字来指定角度。 要使用度数,可以使用radians()将度数转换为弧度, 或使用angleMode(DEGREES)


      ...
      // rotate each axis by 45 degrees
      rotateX(radians(45));
      box();
      //or
      angleMode(DEGREES);
      rotateY(45);
      box();
      ..
      

您还可以使用rotate(), 它允许您使用向量作为第二个参数指定要围绕哪个轴旋转。

rotate() , 它允许您使用向量作为第二个参数指定要围绕哪个轴旋转。

scale(): 空间尺寸

scale() scale()会改变其后绘制的任何内容的大小。 与迄今为止描述的其他方法一样,它接受x、y和z值的参数。

变换的顺序很重要!

一开始可能感觉难以预测的是变换的顺序。每个变换都会影响下一个变换。例如,如果调用 rotate(),然后是 translate(),那么该平移的方向将受到旋转的影响。整个坐标系在旋转和移动,不仅仅是形状本身。

变换可以以任何顺序执行,但是使用translaterotate,然后scale会是最直观的。 先进行平移,然后进行旋转,产生将形状移动到新位置并围绕该位置旋转的效果。

在下面的例子中,尝试改变translate()rotateY()的顺序,看看它如何影响对象的绘制位置。

p5.js还有一些方法可以控制何时应用变换:push()pop()push()pop()使单独移动对象更容易。 push()方法保存并设置当前变换,pop()方法恢复这些变换。 在push()pop()之间进行的任何变换都将隔离到代码的该部分。 如果不使用push()pop(),则必须跟踪已经发生的任何变换,这可能会变得复杂并且难以理解。 考虑下面的示例,在我们的草图中放置了两个盒子。 如果不使用push()pop()来定位第二个盒子,则必须考虑第一个变换。 在更复杂的3D场景中,这可能会很难跟踪。push()pop() push()pop()使单独移动对象更容易。 push()方法保存当前变换和样式设置。 然后,在执行新的变换之后,使用pop()方法将我们恢复到原始变换。 结果是,在push()pop()之间进行的任何变换或样式更改都会隔离到代码的该部分。 如果不使用push()pop(),则必须跟踪已经发生的任何变换,这可能会变得复杂并且难以理解。 考虑下面的示例,在我们的草图中放置了两个盒子。如果不使用push()pop()来定位第二个盒子,则必须考虑第一个变换。 在更复杂的3D场景中,这可能会很难跟踪。


      // draw a box 100 units to the right
      translate(100,0,0);
      box();

      // now, to draw another box 100 units to the left
      // since transformations accumulate, we have to
      // subtract 200 to do this
      translate(-200,0,0);
      box();
      

现在让我们尝试使用push()pop()来做同样的事情。 现在,我们可以将对象平移至想要的位置,而无需记住坐标系统的位置。


      push(); // detach our coordinate system
      // draw a box 100 units to the right
      translate(100,0,0);
      box();
      pop(); // return to our original coordinate system

      push(); // detach our coordinate system
      // draw a box 100 units to the left
      translate(-100,0,0);
      box();
      pop(); // return to our original coordinate system
      
尽管这是一个更高级的主题,但每个变换都会影响到所谓的模型矩阵。 变换矩阵与视图矩阵和投影矩阵相结合,这两个矩阵帮助模拟相机的视图, 这种组合结果形成了我们的3D场景!了解有关模型视图投影的更多信息

在下面的示例中,尝试删除push()pop(),看看这些变换如何影响绘制的第二个对象。

3D中的基本形状

到目前为止,我们只使用了box(),但p5.js还有七个不同的预定义几何形状,您可以在您的草图中使用这些基本的预定义几何形状,这些基本的预定义几何形状通常被称为“原语”。

an illustration showing each of the available primitives in p5.js

这些原语形状方法包括:box()plane()sphere()ellipsoid()cone()cylinder()torus()box(), plane(), sphere(), ellipsoid(), cone(), cylinder(), and torus().

可以从头开始或从另一个程序创建的3D模型创建自定义几何体。有关自定义几何体的更多信息,请参阅 自定义几何体教程.自定义几何体教程 .

结论

通过掌握基本的 3D 坐标空间控制、变换和基本形状,您应该能够开始创建基本的 3D 场景。在《WebGL 入门》系列中,本教程后面的教程将介绍自定义几何、允许您调整场景外观,并向您介绍一些基本着色器编程,以推进您的草图更进一步。

其他教程

这个教程是关于使用 p5.js 中 WebGL 基础的系列之一。以下是其他教程:

词汇表

GPU(图形处理单元)

GPU(图形处理单元)是一种特别适合并行计算的硬件,使其在3D图形方面非常强大。

模型

可以从文件中保存和加载的自定义3D几何图形。

矩阵

一种特殊的数组,可以保存关于几何变换的信息。

相机

3D场景的视点。

变换

也称为 transformation,这指的是几何体的组合缩放、旋转和平移。

顶点

3D空间中的一个点,具有 x、y、z 位置。

由三个点组成的实体表面。