processing一个作品_代码检查 | 如何用Processing搭建一个emoji文字构成的球体?

c0d3ed52c62e7b7661c8ac215a811be4.png

球体一直被称为最完美的几何体,它是只有一个面并且连续曲面的立体图形,用肉眼看来球体在各个位置观看都是完全一致的。

用Processing画一个球体是再简单不过了,只需要下面几行短短的代码,就可以绘制一个球体。

void setup(){

       size(500, 500, P3D);

}

void draw(){

       background(0);

       translate(width / 2, height / 2);

       sphere(200);

}

以上代码的效果如下:

9cd21ad152d1859535f3587ebe570378.png

但今天我们要绘制的球体是与众不同的,因为它是由文字构成的。请大家看下面的效果。这个作品是[作者](https://observablehq.com/@andrewtian/geodesic-rainbow)用JavaScript写的,我在这个基础上做了相应的简化,用Processing近似模拟了这个效果,接下来就给大家讲解如何用代码实现。

准备:球体方程

对于球体上的任何的一个点P来说, 我们可以用三个变量来描述:第一个是点P到球心的长度,也就是该球体的半径;第二个是点P和球心的连线与x、y轴所构成的平面所成的夹角的角度;第三个就是点P在x、y轴所构成的平面的投影点与球心的连线和x轴所成夹脚的角度。

上面所说的三个变量分别对应下面的r、B、A。

198568586ae2b12aeded17e662a7f674.png

那么接下来我们要做的就是求点P在直角坐标系下的坐标(x,y,z),根据上图我们不难得出以下的等式。

x = r * cos(B) * cos(A)

y = r * cos(B) * sin(A)

z = r * sin(B)

那么在理解了如何表示球体上的一个点,并且如何求得该点在直角坐标系下的坐标后,我们就可以开始看代码了。

# 代码

## 大体结构

代码的大体结构非常的简单。

首先,在setup函数中将作品设置成3D模式,同时初始化一个球体,并且将这个球体的球心设置为屏幕的中心,然后将该球体的半径设置为500。

这之后在draw函数中对这个球进行更新和绘制。update函数主要用于对球体进行旋转,display函数主要用于将球体绘制在屏幕上。

该作品只自定义了一个Ball类,那么接下来我们就看看这个类具体是怎样的。

Ball b;

void setup() {

  fullScreen(P3D);

  b = new Ball(width / 2, height / 2, 500);

}

void draw() {

  background(255);

  b.update();

  b.display();

}

class Ball{}

构造函数

第一步我们来看看Ball类的构造函数。

首先是设置了球体的位置,这里需要注意的是我们将球体到屏幕的距离设置成了半径的长度。然后是设置了球体的半径。

这之后是设置了绘制球体的起始角度和球体转动的角速度。

  Ball(float x, float y, float _r) {

    location = new PVector(x, y, -_r);

    r = _r;

    startAngle = 0;

    angleVelocity = -0.1;

  }

看完了Ball构造函数需要的参数,下面就来看看Ball需要的成员变量。

  // 位置

  PVector location;

  // 半径、起始角度、角速度

  float r, startAngle, angleVelocity;

第二步我们来看看update函数。

前面提到了,update的函数的作用是让球体进行旋转,所以在这个函数中我们要不断的更新绘制球体的初始角度。具体实现如下,在看了接下来的display函数后,大家应该能更加理解update函数的作用。

void update() {

    startAngle += angleVelocity;

  }

最后我们来看这个作品中最关键的地方:display 函数,也就是如何绘制这个球体。

大体思路非常的简单:我们首先在球体上取一些点,然后在这些点绘制相应的文字即可。

在该函数中首先我们把坐标原点设置为球心,然后将字体设置为黑色,并设置字体的大小和对其方式。

接下来我们开始在球体上取点。取样的方法很简单,我们每隔一定的间隔从0到360度枚举角度A,然后每隔一定的间隔从-90到90度枚举角度B,至于枚举的间隔由变量step决定,step越大那么点越稀疏,step越小那么点越密集。

offset的作用是让同一个角度B的点有一个向上或者向下的偏移,让它们不再同一条水平线上(下图中的红线),形成错落有致的效果。

a80f0cfd037dc6be9785d99036b7c1ce.png

因为注意到该作品中球体上只有朝向屏幕这一半有文字,所以只有当这个点的z大于零的时候才绘制文字。

讲解到这里,大家看懂下面的代码应该就没有问题了。

void display() {

    translate(location.x, location.y, location.z);

    fill(0);

    textSize(40);

    textAlign(CENTER);

    float step = 10; // 控制字的疏密程度

    float offset = step / 4;//

    for (int i = 0; i < 360; i+=step) {

      offset *= -1;

      for (int j = -90; j < 90; j+=step) {

          // startAngle控制绘制球体的起始角度

          // offset让文字不再一条直线上

        float theta1 = radians(i + startAngle), theta2 = radians(j + offset);

        float x = r * cos(theta2) * cos(theta1);

        float y = r * sin(theta2);

        float z = r * cos(theta2) * sin(theta1);

        // 绘制一半的球体

        if (z > 0)

          text("lmao", x, y, z);

      }

    }

  }

小结

该作品同样也有很多可以拓展的地方,比如改变在球体上取点的方式,在每一个点绘制不同的图案等。我就在这个作品的基础上,绘制了一个印有不同表情包的彩虹球,效果如下:

同时球体彩条的颜色还可以有更多的拓展, 比如参考大名鼎鼎的苹果的logo。

c99606199ecb6d094232d9330b376e9f.png

获得效果如下:

感兴趣的同学可以去作者的openprocessing观看在线效果。

(https://www.openprocessing.org/sketch/741123)

P.s. 跟大家说个喜剧故事:还有三天开学啦!


 近期内容  2e8a50c444524ff198d46497b4d883f6.png c63ff5b68abbed859c59aced973804bf.png 78cce25773f48f4c9432f0c341bbafff.png 欢迎加入OF COURSE,一个想到当然可以做到的全球数字创意平台。 作为中国最早的科技艺术教育平台之一, 与全球顶尖大学教授、交互设计师、新媒体艺术家以及创意工程师合作,共同研发前沿科技艺术课程,致力于让中国学员快速成长为全球科技艺术领军者! 476e47d19a10add6b50dd7bc5fb776c6.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值