模拟巴西奥运火炬台-代码浅析( Test-184 )
分享一段代码练习,使用的工具是 Processing / Openframeworks。
前段时间大家都被巴西的奥运火炬台惊艳到了。我也不例外。当天在网上看到图片和视频,就被它的韵律美所打动。晚上回去就立刻用 Openframeworks 做了模拟。
第一张是奥运火炬的正面图
后面是作者的其他雕塑作品
(图片来源:Anthony Howe/youtube.com)
这是当时所能找到的参考资料。根据这些图片,下面是最终用代码实现的效果
源码与思路浅析
下面开始分析实现思路,同时做了 P5 和 OF 两个版本。从篇幅上考量,文中只放 Processing 的完整代码。
int num;
int lineVertexNum; // 单个元件的线段数
void setup() {
size(1000, 800, P3D);
pixelDensity(2);
lineVertexNum = 8;
}
void draw() {
background(0);
camera(30.0, 30, 1750, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
ambientLight(101, 0, 0);
pointLight(255, 215, 0, 0, 0, 0);
pointLight(255, 0, 0, -700, 0, 0);
pointLight(255, 0, 0, 700, 0, 0);
rotateY(millis()/1800.0);
num = int(mouseY/(float)height * 50);
for (int i = 0; i < 4; i++) {
fireLine(PI/2 * i);
}
}
void fireLine(float interval) {
pushMatrix();
rotateY(PI/2);
randomSeed(1);
for (int j = 0; j < num; j++) {
pushMatrix();
float angle = j/(float)num;
rotateX(j/(float)num * 2 * PI);
strokeWeight(2);
translate(0, 400);
float sinInterval, rotateInterval;
// rotateInterval 决定每个旋转部件间的偏移量
rotateInterval = 4 * mouseX/(float)width;
float speed = 2 * PI / 6; // 控制旋转速度
rotate(-millis()/1000.0 * speed + j/(float)num * 2 * PI * rotateInterval + interval);
for (int i = 0; i < lineVertexNum; i++) {
float l = 16 + 10 * i;
float circleR = 15 - i * 1.5;
if (i == lineVertexNum - 1) {
circleR = 40;
}
stroke(255, 0, 0, 130);
line(0, 0, l, 0);
translate(l, 0);
pushMatrix();
rotateY(PI/2);
noStroke();
if (i == lineVertexNum - 1) {
ellipse(0, 0, circleR * 2, circleR * 2);
} else {
sphere(circleR);
}
popMatrix();
rotate(sin(i/(float)lineVertexNum * 2 * PI) * 1/9.0 * 2 * PI);
}
popMatrix();
}
popMatrix();
}
在 Processing 3.0 下直接复制就能正常运行,此链接(
思路浅析
这里先不逐句讲解代码,只分享实现思路
当看到这样一个造型,第一步是要分解问题。它的基本组成单元是什么?
经过观察,初步猜测如上图。所以先用简单的直线,圆,还有球体来概括。
要在程序中画出一条类似于 S 形的曲线,不一定要用绝对坐标去表示。可以考虑相对坐标,这样更简便也更灵活。在 Processing 或 Openframeworks 中用相对坐标,就得熟悉这几个命令。translate,rotate,pushMatrix,popMatrix(对应 OF 中的 ofTranslate,ofRotate,ofPushMatrix,ofPopMatrix)。对于这样一条曲线,点与点之间的距离和角度是可以用某个关系式去表示的,角度可以使用周期函数 sin,因为它有一个来回的变化。而距离呈现的是一种递增关系,所以有了代码 float l = 16 + 10 * i。
当结构写好,就得调各种参数,让它符合预期的造型。完成这步后,接着就可以将这些元件进行重复。同样是采用相对坐标的方式去旋转复制图形,用 for 循环再结合 rotate 就能实现
这是经过重复并添加角度偏移后的效果。基本造型已经出来。只要将它打包成一个函数,再在 draw 里面传入不同的变量,就能让单个元件重复
上面是原理图,可以看到由简至繁的整个过程
最后在程序中添加三个点光源,中间用黄光,两旁用红光,就大功告成~
奥运火炬改装
最后放一个改装版。
在纸上画图,要重新设计必须得推倒重来。但在程序中,可能只要修改一下参数,多加几行代码即可,非常方便就能做出各种变化。这也是自己喜欢 coding 的原因之一,它可以带来更多创造的可能性。
一点心得
Processing 和 Openframeworks 内置的灯光系统有两个特性。一是没有投影,二是物体之间不会相互影响,光没有反射也没有折射。所以在真实感上比不上 Unity 这类游戏引擎,但只要参数调节得当,还是能有不错的三维表现力。
编程不是一步到位的。就像绘画,先有个草稿,骨架,再去一步步补充并丰富细节。别想着把所有东西都写完才 RUN。
多观察,多考虑图形间的相对关系。复杂图形也可以有简单的表示方法,学会概括。
pushMatrix 与 popMatrix 非常常用,尽量熟悉
Processing 与 Openframeworks 的异同对比
最近被问的问题里,频率最高之一的问题是:“ 这是用什么写的?Processing 还是 OF ?”。
这里解答一下,现在几乎只用 OF,因为它基于 C++,跨平台,效率高,能开发 App。所以选择它作为主力开发工具。
但无论 Processing 也好,OF 也好。它们之间的差别没有大家想象的大。若只从呈现的视觉结果来看,Processing 能做的,OF 也能做,反之亦然。
算法是内功,语言只是招式。核心的是算法,关键是思考用怎样的算法去造型去着色。无论你是用 JS,Python 还是 Unity,其实都大同小异,你只要用自己熟悉的工具即可。
目前的 Test 里,并没有用到多少高级的 OF 专用库。几乎都是用最简单的点线面去组织。而这些基础的造型元素,两种工具都会有。所以 98 % 的Test ,都可以同时用两者实现。
当然,若你想做一些更复杂的图形,OF 效率高的优势就能体现出来。正如这个例子的两个版本,OF 在图形元件数量更多时,跑起来就会更流畅。
工具的选择建议
学 Processing 还是 OF ,主要取决与你最终想做什么。有些是只有 Processing 能做的,比如输出程序在网页端运行(OF 理论上也行,但很不方便)。而有些只有 OF 能做,如开发 IOS 应用。
至于开发安卓应用,两者都可以。和 Kinect,Arduino 各种硬件传感器交互,也是两者皆可。如果你想做一些大型的互动装置,运算量较大,想更稳定,更推荐基于 C++ 的 OF。
但如果你是设计师,以前没接触过编程,想先提高 CreativeCoding 的内功,就可以考虑学 Processing,毕竟玩的人多,教程资源也丰富,更便于交流讨论。当熟悉两者中的任何一个,另一个只要花很少的时间既能掌握。假如你已经掌握 Processing,在教程资源完善的前提下,学习 OF 也只要一周的时间。
所以若是有意深入,不如两者都学,区别只是先后而已~
Openframeworks 版源码
点击阅读原文可下载 Openframeworks 版
(使用说明:单击拖动可切换角度。上下移动可改变元件数量,左右移动可改变元件间的旋转偏移量)