7. 材质-美化你的物体
本教程翻译自官方教程Materials,各位也可以进入本站镜像站点查看
本文目录
材质material
材质被用来覆盖在你的物体上,用来给物体上色或者贴图,要注意一般来说材质要配合灯光才能显示出效果,同一个材质是可以应用到多个物体上面去的。
材质对光线的反应
无论是使用颜色还是纹理贴图来设置材质,它对光线的反射都有着不同的表现。
- 漫反射 - 在灯光下看到的材质基本颜色或纹理
- 镜面反射 - 在灯光照射下,高光给与材质的效果
- 自发光 - 材质的颜色或纹理就像一个灯光那样可以对外发出效果
- 环境 - 环境背光所照射出来的材质颜色或纹理
要看到漫反射和镜面反射的材质效果,必须要求创建至少一个光源。
要让环境背光照射出材质的环境颜色效果,还需要为场景设置一个环境颜色,如下所示:
scene.ambientColor = new BABYLON.Color3(1, 1, 1);
材质还可以设置一个透明度,会产生一个半透明的效果,通过设置材质的alpha属性来实现,取值范围是[0, 1]。
颜色Color
可以通过如下代码创建一个材质:
//第一个参数是材质名称,第二个是场景实例
var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);
接下来我们可以使用漫反射颜色diffuseColor、镜面颜色specularColor、自发光颜色emissiveColor以及环境颜色ambientColor来设置材质颜色,这四个颜色可以同时设置也可以只设置其中某一个。再次强调,仅当场景的环境颜色已设置时,环境颜色才能看到效果。设置材质颜色的案例如下:
var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);//创建一个材质
myMaterial.diffuseColor = new BABYLON.Color3(1, 0, 1);//漫反射颜色
myMaterial.specularColor = new BABYLON.Color3(0.5, 0.6, 0.87);//镜面颜色
myMaterial.emissiveColor = new BABYLON.Color3(1, 1, 1);//自发光颜色
myMaterial.ambientColor = new BABYLON.Color3(0.23, 0.98, 0.53);//环境光颜色
mesh.material = myMaterial;//mesh是之前创建的物体
漫反射颜色示例
为了理解灯光照射在材质上时,材质漫反射颜色的反应,下面的Playground示例显示了不同颜色的材质,分别对白色、红色、绿色和蓝色聚光灯Spot Light所反应出的效果。这里要注意的是灯光light也具有颜色,可以设置漫反射diffuse和镜面反射specular。
设置材质的颜色如下,分别对应下图中的四个位置:
黄色材质 | 紫色材质 |
青色材质 | 白色材质 |
下图中还可以看到白色,红色,绿色和蓝色的聚光灯Spot Light。
各位看到这里可能会比较郁闷,咱们来捋一捋,示例中的地面Ground可以通过单选框来切换不同的漫反射颜色:黄色、紫色、青色、白色,而且聚光灯一共有四盏,颜色分别是:白色,红色,绿色和蓝色,也就是它们都设置了灯光的漫反射颜色。示例是让各位熟悉一下不同颜色的灯光照射在有不同漫反射颜色的地面下会产生什么视觉效果,这里有一个规律,当地面材质为白色的时候,灯光照射在地面都显示出了自身原有的颜色;而且白色那一盏灯,会照射出地面材质的原本颜色。这说明在babylon中白色是一个通透的颜色,就像透明一样,而黑色则相反,它完全会遮挡住其他颜色,至于其他中间色,则表现出了一些特殊的效果,大家可以慢慢观察。
环境颜色示例
先上一个例子Playground 环境颜色示例
例子中设置了一个半球光Hemispheric Light,并给它设置了红色漫反射diffuse和绿色底色groundColor,所有的球体都由这个半球光来照亮,首先左边第一个球体没有设置材质和其环境颜色、中间的球体设置了红色环境色的材质、右边的球体设置了绿色环境色的材质。各位别忘了,还要设置场景scene的环境色哦,这里我们设置成了白色,上面说到白色代表通透,所以球的材质环境色改变会立马得到体现,但是如果scene的环境色设置为了黑色,也就是Color3(0,0,0),那么各位可以想象得到,球体将一直体现灯光的颜色,无论自身的材质环境色设置为任何颜色,都将没有效果。
透明度示例
通过将材质的alpha属性设置为0(不可见)到1(不透明)可以实现透明度。
myMaterial.alpha = 0.5;
纹理贴图Texture
可以使用一张图片来生成纹理,纹理必须配合材质来使用,首先新建一个材质:
var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);
然后可以使用漫反射纹理diffuseTexture、镜面反射纹理specularTexture、自发光纹理emissiveTexture以及环境纹理ambientTexture来设置材质纹理贴图,这四个纹理可以同时设置也可以只设置其中某一个。注意:如果没有设置场景的环境颜色,环境纹理将没有效果。设置材质纹理的案例如下:
var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);
//PATH TO IMAGE,表示图片的路径,其实也可以使用base64格式的图片。
myMaterial.diffuseTexture = new BABYLON.Texture("PATH TO IMAGE", scene);
myMaterial.specularTexture = new BABYLON.Texture("PATH TO IMAGE", scene);
myMaterial.emissiveTexture = new BABYLON.Texture("PATH TO IMAGE", scene);
myMaterial.ambientTexture = new BABYLON.Texture("PATH TO IMAGE", scene);
mesh.material = myMaterial; //记得设置物体的材质属性
注意,如果没有指定法线时,Babylon的标准材质将会自动计算并生成法线数组。
各位可能要问,法线是什么?在3D世界中,法线用来进行光照计算,也就是灯光照射到物体上的呈现效果。具体各位可以百度一下。
纹理示例
首先上一个案例Playground 纹理案例
例子中设置了一个半球光Hemispheric Light,并给它设置了红色漫反射diffuse和绿色底色groundColor,所有的球体都由这个半球光来照亮。第一个球体设置了漫反射纹理,中间的设置了自发光纹理,最右边了不仅设置了一个环境纹理,还给了一个红色的漫反射颜色。效果如下:
透明纹理示例
让我们来看一个让材质纹理透明的案例Playground,和上面颜色的透明度讲到的一样,都是设置alpha。
myMaterial.alpha = 0.5;
另外,用于创建纹理的图片本身可能已经有透明度了,例如Wikimedia Commons的这张狗的png图片就具有透明背景
在这种情况下,我们将纹理的hasAlpha属性设置为true,就能把图片本身带有的透明给体现出来了。
myMaterial.diffuseTexture.hasAlpha = true;
正常情况下,为了节省计算资源,3D世界对于被遮挡的东西都是做隐藏处理的。但是一个当立方体设置了带有透明png图片的纹理时,默认是认为被图片遮挡的部分是隐藏的,不管你透不透明,所以为了处理这种情况我们要了解一下 背面消除backFaceCulling 这个设置。
背面消除
不绘制立方体或其他对象的背面,这是一种在二维屏幕上有效绘制三维模型的渲染方法,因为默认背面都会被正面所遮挡,所以你肯定猜到了,在巴比伦JS中,默认设置背面消除backFaceCulling为true。
现在请看下面的图片,当材质的backFaceCulling属性设置为true时,你可以看到狗周围的透明区域仍然是透明的。无法看到背面的图像,因为它们已被默认消除了。 如果backFaceCulling为false,则在3D渲染过程中不会删除背面,因此我们可以通过正面的透明区域看到背面的内容。
backFaceCulling = True | backFaceCulling = False |
---|---|
Playground backFaceCulling设置为true时的案例
其实有的人可能已经发现了,backFaceCulling=false 和 之前物体的属性sideOrientation 设置为 双面DOUBLESIDE 产生的效果是不是很像?是的,我们对比了一下的确很相似,两者还可以同时使用,都可以达到看到背面的效果,不同的是这两种方法对灯光的照射产生的效果不一样,具体大家可以自己试试看。
线框WireFrame
如果要下图那样呈现物体,我们可以设置材质的线框WireFrame属性:
materialSphere1.wireframe = true;
纹理打包程序Texture Packer
babylon内置了一个很强大的功能:纹理打包程序Texture Packer,一些复杂的场景需要包含大量的纹理,这意味着要加载很多图片。一个材质常常会使用到3个或者更多的纹理,为了优化载入过程避免过多的请求,我们可以把来自于多个材质的纹理打包成为一系列图片,这个类似于css sprite雪碧图。但需要权衡的是,每个纹理都将按比例缩放到固定的大小,并可能导致一些纹理图片的相互混淆,webGL的限制也可能会成为一个瓶颈。打包程序将为纹理创建一系列的帧,这个纹理是所有材质所对应的纹理通道的集合,且是唯一的;然后再为被打包材质对应的每个通道生成一张图片;最后,通过修改物体的目标UV#,以使其与打包程序生成的纹理对应帧匹配,这个UV值是通过物体构造函数进行传递的。打包程序假定所有纹理都是一个正方形,即使不是,程序也会把这个纹理贴图放到正方形的框内。
我们通过以下代码进行纹理打包:
let pack = new BABYLON.TexturePacker(name, targetMeshes, options, scene);
pack.processAsync().then(success).catch(error);
纹理打包虽然很强大,但是你也必须了解它的一些使用限制,包括:纹理体积限制、透明度、反射和折射材质等。请移步这里查看更多信息创建一个纹理包
我感觉各位可能看到这里会一脸懵逼,因为我一开始也懵逼了, 材质所对应的纹理通道 是啥? 帧是啥?带着这些疑问我给各位解释一下
材质所对应的纹理通道,其实说的是一个材质material里的diffuseTexture、emissiveTexture、opacityTexture、specularTexture,看懂了不?也就是说打包程序会把material.diffuseTexture,material.emissiveTexture,material.opacityTexture,material.specularTexture等通道对应的纹理进行打包,如果遇到长得一样的纹理贴图,则会进行合并,而且多个材质的同一个通道纹理会被合并。
帧其实就是一组数据,由左上、右下的两个坐标,4个值组成,下面看看打包程序打包后下载下来json各位就明白了。
{
"name": "TestPack",//包的名称
"sets": {
"diffuseTexture": "base64图片数据",//多个材质的diffuseTexture通道生成的纹理会打包到这里
"emissiveTexture": "base64图片数据",//多个材质的emissiveTexture通道生成的纹理会打包到这里
"opacityTexture": "base64图片数据",//多个材质的opacityTexture通道生成的纹理会打包到这里
"specularTexture": "base64图片数据",//多个材质的specularTexture通道生成的纹理会打包到这里
},
"options": {//一些配置现在可以不用管,默认生成
"frameSize": 256,
"layout": 1,
"paddingMode": 1,
"map": [
"ambientTexture",
"bumpTexture",
"diffuseTexture",
"emissiveTexture",
"lightmapTexture",
"opacityTexture",
"reflectionTexture",
"refractionTexture",
"specularTexture"
],
"uvsIn": "uv",
"uvsOut": "uv",
"updateInputMeshes": true,
"disposeSources": true,
"fillBlanks": true,
"customFillColor": "black",
"paddingRatio": 0.0115
},
"frames": [//这个就是帧,每4个数代表一帧,表示左上、右下两个坐标值,表示一个正方形位置。
0.16161616161616163,//1帧
0.16161616161616163,//1帧
0.0025252525252525255,//1帧
0.0025252525252525255,//1帧
0.16161616161616163,//2帧
0.16161616161616163,//2帧
0.16919191919191917,//2帧
0.0025252525252525255,//2帧
0.16161616161616163,//3帧
0.16161616161616163,//3帧
0.33585858585858586,//3帧
0.0025252525252525255,//3帧
]
}
本地文件访问
各位可能觉得有时候在Playground或者本机中调试代码不方便,因为无法访问本地文件。这几教大家一个小技巧哦,出于安全原因,像chrome这样的web浏览器,在默认情况下不允许直接访问web页面的本地文件。图片、模型、环境文件等等都不允许,这对咱们学习有阻碍,所以在chrome中介绍几种方法解决这个问题。首先关闭所有chrome窗口,并在控制台中打开它。
Windows下就是cmd控制台,打以下命令:
start chrome --allow-file-access-from-files
Mac下进入command输入:
open -a "Google Chrome" --args --allow-file-access-from-files
Linux下进入command输入:
google-chrome --allow-file-access-from-files
请注意,上述方法会有安全风险。 对于正式项目,还是搭建一个HTTP服务来得靠谱。或者也可以建一个简单的HTTP服务,这样更接近正式项目。可以先安装Python,然后在项目的文件夹运行以下命令:
1.设置python路径为环境变量
// python3
2.命令行输入python -m http.server 8888
// 或python2
2.命令行输入python -m SimpleHTTPServer 8888
3.使用http://localhost:8888/ 进行访问
下一步
非常好,有了这些材质,你的场景看起来更加吸引人了!以后我们将学习到更多关于材质的知识。接下来,请阅读下一章相机-找一个合适的观察视角。
延伸阅读
聚光灯Spot Light介绍
半球光介绍Hemispheric Light介绍
材质概述
贡献者
参与贡献? 联系alexads@foxmail.com