您的位置:首页 > 其它

谈谈Processing 3D世界 三

2016-08-08 17:48 232 查看
有了前两节的知识,接下来咱们该做什么呢?丰富多边形?控制摄影机?这些先不急,我们不妨先来了解下纹理

(Texture)。有了这玩意,能极大的丰富我们绘制的对象。

纹理(Texture)

我们先来看看有关纹理的函数,很简单只有3个:

texture()        -载入纹理
textureMode()    -设置纹理坐标模式
textureWrap()    -设置纹理环绕模式

逐个来分析一下: 

texture()
- 载入纹理

这个函数必须在beginShape()和endShape()这对基友之间使用,它将一副图像载入到纹理中,并应用
到顶点。
 
范例:
size(100, 100,P3D);
noStroke();
PImage img =loadImage("laDefense.jpg");
beginShape();
texture(img);
vertex(10, 20,0, 0);
vertex(80, 5,100, 0);
vertex(95, 90,100, 100);
vertex(40, 95,0, 100);
endShape();

 
这时候vertex()中的后两位参数不在描述坐标,而是顶点的UV;
vertex(x,y, u, v);    - 2d
vertex(x,y, z, u, v); - 3d
 
何为顶点的UV?看下图:



*注意,2D坐标系只有相对方向。所以无论UV朝向什么方向,最后都能旋转成上图这样。
当我们指定好绘制多边形使用的纹理后,我们把纹理标准化到一个0到1的坐标系空间中。横轴称为U轴,纵
轴成为V轴。我们将每个顶点映射到这个平面空间中,从而指定了这个多边形使用了贴图的那一片区域。
 

textureMode()
- 用来设定纹理是否标准化

 
textureMode(IMAGE)  -使用图片自身像素尺寸作为坐标(默认)
textureMode(NORMAL) -使用标准化坐标
 
因此,贴图(也就是用于载入纹理的图片)最好是1:1的正方形。其次因为数据位的原因,贴图的尺寸最好是
128*128, 256*256, 512*512这样的2的n次幂。另外,贴图的尺寸不要太大,牛逼一些的游戏使用的也
不过是2k贴图(也就是2048*2048)。当然了,这里是我大Processing,没有那么严谨也是容许的。
 
---------------------------------这里是华丽的分割线 ---------------------------------

绘制带纹理的cube

回顾一下第二节的知识,我们要如何处理cube才能使其拥有纹理呢?
我们有两种处理的方法:
1.我们可以吧这个cube展成一个平面就像下图这样:

如此我们在一张贴图的空间内就可以描述所有顶点的UV坐标。这也就是我们常说的对模型网格展UV的工作了。



2.鉴于cube简单的构造,倘若我们把贴图平贴在cube的每一面上也是一种不错的方法。游戏
-《我的世界》
便是这种做法。这样我们也只需要一张贴图便可以完成工作。
 
这里我们采用第二中方法。这里先给出贴图
 

step 1导入贴图

 
PImage tex;
tex = loadImage("t1.jpg"); //你可以随意替换自己喜欢的贴图
tex.resize(256, 0); //我们这里不需要那么的贴图,重设成256的
textureMode(NORMAL); //纹理使用标准化UV坐标

step2设置顶点UV

我们需要对每一个顶点设置UV,算算我们有36个顶点。因此目前有一点苦力活需要干,但很快,将会
有东西拯救我们。
 
PVector[][]uv;
uv =new PVector[12][3]; // 12个面,每个面3个顶点,为每个顶点描述UV
//top
uv[0][0] = new PVector(0, 1); // face0
uv[0][1] = new PVector(0, 0); //注意UV是浮点数
uv[0][2] = new PVector(1, 0);
uv[1][0] = new PVector(0, 1); // face1
uv[1][1] = new PVector(1, 0);
uv[1][2] = new PVector(1, 1);
...
// bottom
...
 

step 3更新绘图过程

 
//fill(255, 127, 39);有了纹理我们不再需要填充颜色了。
for (int i = 0; i < face.length; i++) {
beginShape();
texture(tex); //这里装载并启用纹理
// x , y , z , u , v
vertex(ver[int(face[i].x)].x,ver[int(face[i].x)].y, ver[int(face[i].x)].z, uv[i][0].x, uv[i][0].y);
vertex(ver[int(face[i].y)].x,ver[int(face[i].y)].y, ver[int(face[i].y)].z, uv[i][1].x, uv[i][1].y);
vertex(ver[int(face[i].z)].x,ver[int(face[i].z)].y, ver[int(face[i].z)].z, uv[i][2].x, uv[i][2].y);
endShape(TRIANGLES);
}
如此应该可以看见咱们的图块出现在屏幕中了,有没开始觉得有一点兴奋?
 



 
 
这里是完整的代码,不太清楚的同学可以查看。

------------------------------------- 这里是华丽的分割线 -------------------------------

纹理环绕

让我们进入最后一个知识点,纹理环绕方式(Texture Weapping)。

textureWrap() 
  -设置纹理环绕模式

是的这个函数负责设置纹理环绕的方式。Processing慈悲的准备了两种:

CLAMP  - 纹理坐标绘制0到1之间,超出的部分会重复纹理坐标的边缘,就像是边缘被拉伸。(默认的)

REPEAT - 重复纹理图像,比如吧坐标设置成4,这会使纹理重复4次。

咱们可以吧之前cube的案例拿来试试效果,首先咱们换一张好体现效果的贴图

接下来把uv改造一下:

float max = 1.0;
// top
uv[0][0] = new PVector(0, max); // face0
uv[0][1] = new PVector(0, 0);
uv[0][2] = new PVector(max, 0);
uv[1][0] = new PVector(0, max); // face1
uv[1][1] = new PVector(max, 0);
uv[1][2] = new PVector(max, max);
...

然后设置纹理属性:

// 载入贴图
tex = loadImage("t3.jpg");
tex.resize(int(256/max), 0);

// 设置纹理属性
textureMode(NORMAL);
textureWrap(REPEAT);
现在我们来试试结果。

当max = 1.0;时应该是这样:



当max = 2.0; textureWrap(CLAMP);时,纹理边缘会被拉伸:



旁白:瞬间好像明白了星际穿越中外星人的五维空间是咋做的了?

当max = 2.0; textureWrap(REPEAT);时,纹理会被重复:



在制作地面的时候,纹理重复就十分好用。想想魔兽世界那广鞣的土地,一个劲的重复着单调的纹理!

完整代码看这里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  processing 图形 3d