谈谈Processing 3D世界 二
来源:互联网 发布:自学linux运维要多久 编辑:程序博客网 时间:2024/04/28 22:10
有了第一节的知识,我们其实已经可以做很多事情了。比如,
绘制一个立方体(cube)。
不过绘制立方体相对复杂。我们先从绘制一个正方形起步吧。
仍然使用beginShape(),与endShape()这对基友来绘制我们的多边形:
// 绘制图形beginShpae(); // 开始绘制vertex(); // 这里填入顶点位置...endShpae(CLOSE); // 结束绘制
step 1 定义顶点
如何定义正方形的4个顶点?
经过第一节知识洗礼,我们知道第一步要把正方形画在坐标系原点附近,最好图形的中心点能与原点重合。
这样无论图形在之后要怎么倒腾,我们只需对这个坐标系进行矩阵变换(平移、旋转、缩放)就可以应付了。
事实上,我们把这些操作称为对模型矩阵的变换操作。
上图标示了正方形4个顶点位置。我们将申请4个向量来填装。
// 设置顶点PVector[] ver = new PVector[4];ver[0] = new PVector(-0.5, -0.5);ver[1] = new PVector( 0.5, -0.5);ver[2] = new PVector( 0.5, 0.5);ver[3] = new PVector(-0.5, 0.5);
你可能注意到了,这一次我们并没有使用具体的数值来描述顶点的位置。相比官网提供的例子,如:
vertex(30, 20);vertex(85, 20);vertex(85, 75);vertex(30, 75);
状的变化,并方便我们后续对模型矩阵的变换操作。
translate(width/2,height/2);
然而,这时候我们任然看不见图形,因为我们需要给图形指定大小:
scale(100);
我们将图形放大100倍,正方形的边长由1.0放大成了100.0。
使用遍历顶点的结构,我们可以过程化多边形的绘制工作。
这里是完整的代码:
你可以尝试运行第25行代码。
step 2 变换矩阵
我们希望这个正方形显示在屏幕正中央,因此使用平移矩阵,将画面移到屏幕中央:translate(width/2,height/2);
然而,这时候我们任然看不见图形,因为我们需要给图形指定大小:
scale(100);
我们将图形放大100倍,正方形的边长由1.0放大成了100.0。
step 3 绘制图形
// 绘制图形beginShape();for(int i = 0; i < ver.length; i++) { vertex(ver[i].x, ver[i].y);}endShape(CLOSE);
使用遍历顶点的结构,我们可以过程化多边形的绘制工作。
这里是完整的代码:
你可以尝试运行第25行代码。
// 定义顶点PVector[] ver;void setup() { size(200, 200, P3D); // 设置顶点 ver = new PVector[4]; ver[0] = new PVector(-0.5, -0.5); ver[1] = new PVector( 0.5, -0.5); ver[2] = new PVector( 0.5, 0.5); ver[3] = new PVector(-0.5, 0.5); // 设置图形模式 noStroke(); noLoop();}void draw() { // 模型矩阵变换 // 在opengl中,我们建议您在组合矩阵时,先进行缩放操作, // 然后是旋转,最后才是平移,否则它们会(消极地)互相影响。 // 在Processing中,恰恰相反。 translate(width/2, height/2); //rotateZ(radians(45)); scale(100); // 绘制图形 fill(255, 127, 39); beginShape(); for(int i = 0; i < ver.length; i++) { vertex(ver[i].x, ver[i].y); } endShape(CLOSE);}
--------------------------这里是华丽的分割线 --------------------------------
现在我们回过头来想象立方体的顶点分布
.
现在我们回过头来想象立方体的顶点分布
step 1 定义顶点
这一次,我们的顶点将加上z轴坐标。// 设置顶点ver = new PVector[8];ver[0] = new PVector(-0.5, -0.5, 0.5); // 顶点1ver[1] = new PVector(-0.5, -0.5, -0.5); // 顶点2ver[2] = new PVector( 0.5, -0.5, -0.5); // ...ver[3] = new PVector( 0.5, -0.5, 0.5);ver[4] = new PVector(-0.5, 0.5, 0.5);ver[5] = new PVector(-0.5, 0.5, -0.5);ver[6] = new PVector( 0.5, 0.5, -0.5);ver[7] = new PVector( 0.5, 0.5, 0.5);
step 2 变换矩阵
没有什么变化。step 3 绘制图形
然而我们还能像刚才那样遍历顶点吗?.
.
.
真正开始时,我们似乎有一点不知从何下手,对吧?事实上这里会遇到两个问题:
.
真正开始时,我们似乎有一点不知从何下手,对吧?事实上这里会遇到两个问题:
1.描述绘制多边形的方法
关于这一点我们可以查看beginShape()的官方说明。我们可以看到说明里列举了很多绘制的方法,一般我们选:
TRIANGLES - 绘制独立的三角面
或 TRIANGLE_FAN - 绘制连续的三角面
因为我们的显卡在处理三角面时效率会快的多。同时,使用三角面,我们也无需考虑线条穿插问题。我
TRIANGLES - 绘制独立的三角面
或 TRIANGLE_FAN - 绘制连续的三角面
因为我们的显卡在处理三角面时效率会快的多。同时,使用三角面,我们也无需考虑线条穿插问题。我
倾向选择前者。处理起来直截了当。我们的立方体有6个面,每个面可以由2个三角形构成,那么一共就
是12个三角面。
2.描述顶点的方法
当然,我们可以老老实实把12个三角面的顶点都描述一遍。不过这样的操作似乎是机器的爱好。。。想必我们会很厌烦。仔细想想,尽管有12个三角面,但它们的顶点仍然是由上文中ver 那8个顶点构成的。
因此我们可以称ver为[顶点列表],然后添加一个[顶点索引列表],用来描述每一个三角面使用了那些
因此我们可以称ver为[顶点列表],然后添加一个[顶点索引列表],用来描述每一个三角面使用了那些
顶点:
face= new PVector[12];face[0] = new PVector(0, 1, 2); // 三角面1face[1] = new PVector(0, 2, 3); // 三角面2...
3.更新绘制图形方法
既然我们添加了顶点索引列表,那么原来的绘制图形的过程就有必要更新一下了:// 绘制图形fill(255, 127, 39);for (int i = 0; i < face.length; i++) { // 遍历三角面 // 绘制三角面 beginShape(); vertex(ver[int(face[i].x)].x, ver[int(face[i].x)].y, ver[int(face[i].x)].z); vertex(ver[int(face[i].y)].x, ver[int(face[i].y)].y, ver[int(face[i].y)].z); vertex(ver[int(face[i].z)].x, ver[int(face[i].z)].y, ver[int(face[i].z)].z); endShape(TRIANGLES);}
现在,我们来更新一下立方体的绘制过程:
// 定义顶点PVector[] ver;PVector[] face;void setup() { size(200, 200, P3D); // 设置顶点 ver = new PVector[8]; ver[0] = new PVector(-0.5, -0.5, 0.5); // 顶点1 ver[1] = new PVector(-0.5, -0.5, -0.5); // 顶点2 ver[2] = new PVector( 0.5, -0.5, -0.5); // ... ver[3] = new PVector( 0.5, -0.5, 0.5); ver[4] = new PVector(-0.5, 0.5, 0.5); ver[5] = new PVector(-0.5, 0.5, -0.5); ver[6] = new PVector( 0.5, 0.5, -0.5); ver[7] = new PVector( 0.5, 0.5, 0.5); // 设置顶点索引 face = new PVector[12]; // top face[0] = new PVector(0, 1, 2); face[1] = new PVector(0, 2, 3); // front face[2] = new PVector(0, 3, 7); face[3] = new PVector(0, 7, 4); // back face[4] = new PVector(1, 2, 6); face[5] = new PVector(1, 6, 5); // right face[6] = new PVector(3, 2, 7); face[7] = new PVector(2, 6, 7); // left face[8] = new PVector(0, 4, 5); face[9] = new PVector(1, 5, 0); // bottom face[10] = new PVector(4, 5, 7); face[11] = new PVector(5, 6, 7); // 设置图形模式 noStroke();}void draw() { // 清楚缓冲区 background(0); // 模型矩阵变换 // 在opengl中,我们建议您在组合矩阵时,先进行缩放操作, // 然后是旋转,最后才是平移,否则它们会(消极地)互相影响。 // 在Processing中,恰恰相反。 translate(width/2, height/2, -100); float angle = frameCount%360; rotateX(radians(angle)); rotateY(radians(angle)); scale(100); // 绘制图形 fill(255, 127, 39); for (int i = 0; i < face.length; i++) { beginShape(); vertex(ver[int(face[i].x)].x, ver[int(face[i].x)].y, ver[int(face[i].x)].z); vertex(ver[int(face[i].y)].x, ver[int(face[i].y)].y, ver[int(face[i].y)].z); vertex(ver[int(face[i].z)].x, ver[int(face[i].z)].y, ver[int(face[i].z)].z); endShape(TRIANGLES); }}
好啦,咱们的立方体终于顺利绘制到屏幕中了。欣喜之余,你是不是会突然想到利用box()函数,不是
也可简单快速的绘制一个立方体吗?其实不然,通过上面的努力,你已经开启了通往3D世界大门。精彩
的世界就在眼前。
0 0
- 谈谈Processing 3D世界 二
- 谈谈Processing 3D世界 六 (续二)
- 谈谈Processing 3D世界 一
- 谈谈Processing 3D世界 三
- 谈谈Processing 3D世界 四
- 谈谈Processing 3D世界 五
- 谈谈Processing 3D世界 六
- 谈谈Processing 3D世界 四(补充)
- 谈谈Processing 3D世界 六 (续)
- 3D静态世界
- 3D rendering pipeline(重点:vertex processing)
- 【Processing入门】第十章:3D
- (十)利用processing绘制3D图形
- AQSENSE 3D acquisition and processing Tools
- OpenGL 漫游3D世界
- 世界第一名的 3D
- 跟这世界谈谈
- Processing 教程(13) 我的3D开山之作!
- 谈谈Processing 3D世界 一
- Android之RadioButton和RadioGroup结合Dialog的多种运用详解
- GPU作用解析
- FragmentPagerAdapter与FragmentStatePagerAdapter区别
- 排序:智能收件箱
- 谈谈Processing 3D世界 二
- 端口号的分类
- Android 代码库
- ITOO--导入图片(MongoDB)
- Residual Learning
- 字符串替换(string.find() 和 string.substr() 的使用)----去哪儿2016研发工程师编程题
- poj 2531 Network Saboteur
- RocketMQ与kafka对比
- 并查集 亲戚