前言:材质就像物体的皮肤,决定几何体的外表。例如:定义一个几何体看起来是否像金属,透明与否,或者显示为线框,得到THREEJS.Mesh对象添加到Threejs渲染的场景中。
创建三维对象主要使用的材质:
MeshBasicMaterial(网格基础材质) | 可赋予简单颜色 | MeshDepthMaterial(网格深度材质) | 根据摄像机距离进行调色 | MeshNormalMaterial(网格法向材质) | 根据法向量计算物体颜色 | MeshLambertMaterial(网格Lambert 材质)? | 考虑光照影响的材质,用于创建不光亮的物体 | MeshPhongMaterial(网格 Phong式材质)? | 考虑光照影响的材质,用于创建光亮的物体 | MeshStandardMaterial(网格标准材质) | 它能够计算出表面与光线的正确互动关系,从面便?染出的物体看起来更加真实(新) | MeshPhysicalMaterial(网格物理材质) | 这是MeshPhongMaterial的扩展材质(新) | MeshToonMaterial(网格卡通材质)? | MeshPhongMaterial的扩展材质,更卡通化 | ShadowMaterial(阴影材质) | 专门用于接收阴影图的特殊材质。在该材质中只有?阴影图像,非阴影部分为完全透明的区域 | ShaderMaterial(着色器材质) | 这种材质允许使用自定义的着色器程序,直接控制顶点的放置方式及像素的着色方式 | LineBasicMaterial(直线基础材质) | 这种材质可以用于THREE.Line(直线)几何体,用来创建着色的直线 | LineDashMaterial(虚线材质) | 创建出一种虚线的效果? |
一、材质的属性
? ? ? ? Three.js 提供了一个材质基类 THREE. Material,它列出了所有的共有属性。这些共有属性分成了三类,如下所示: 基础属性 :?这些属性是最常用的。通过这些属性,可以控制物体的不透明度、是否可见以及如何被引用(通过ID或是自定义名称)。 融合属性 : 每个物体都有一系列的融合属性。这些属性决定了物体如何与背景融合。
高级属性?: 有一些高级属性可以控制底层WebGL上下文对象渲染物体的方式。大多数情况下是不需要使用这些属性的。
基础属性这里就不罗列了,需要可以查看源码
//材质的共有属性
THREE.Material = function () {
Object.defineProperty( this, 'id', { value: THREE.MaterialIdCount ++ } );
this.uuid = THREE.Math.generateUUID();
this.name = '';
this.type = 'Material';
this.side = THREE.FrontSide;
this.opacity = 1;
this.transparent = false;
this.blending = THREE.NormalBlending;
this.blendSrc = THREE.SrcAlphaFactor;
this.blendDst = THREE.OneMinusSrcAlphaFactor;
this.blendEquation = THREE.AddEquation;
this.depthTest = true;
this.depthWrite = true;
this.polygonOffset = false;
this.polygonOffsetFactor = 0;
this.polygonOffsetUnits = 0;
this.alphaTest = 0;
this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing
//antialiasing gaps in CanvasRenderer
this.visible = true;
this.needsUpdate = true;
};
二、THREE.MeshBasicMaterial(网格基础材质)
? ? ? ? ? ? ??MeshBasicMaterial是一种基础材质,不考虑场景中是否有光照影响。一般使用该材质的网格会被渲染成基础几何,也可显示边框使用。
在使用该材质时常用属性通常对以下属性进行调试:
var meshMaterial = new THREE.MeshBasicMaterial({
color: 0x7777ff,
//wireframe : true, //开启wireframe属性,将模型渲染成线框
//opacity : 0.01
//wireframeLinewidth: 20 //测试线宽,看不出变化
//name : 'Material-1',
//transparent: true, //开启透明度
//opacity : 0.5 //设置透明度(0-1)
});
实例 :?
?可通过插件GUI对网格对象属性进行调试,该实例中并未添加光照(不受光照影响)。
三、THREE.MeshDepthMaterial(联合材质)
MeshDepthMaterial材质无法设置对象颜色,通过设置多种材质用以改变物体颜色。该方案又称联合材质。
创建方案:?
//Math.ceil() “向上取整”, 即小数部分直接舍去,并向正数部分进1
//Math.random()是令系统随机选取大于等于 0.0 且小于 1.0 的伪随机 double 值
var cubeSize = Math.ceil(3 + (Math.random() * 3)); //cubeSize随机 3 4 5 6
var boxGeometry = new THREE.BoxGeometry(cubeSize,cubeSize,cubeSize);
var meshDepthMaterial = new THREE.MeshDepthMaterial();
var meshBasicMaterial = new THREE.MeshBasicMaterial({
color: controls.color,
transparent: true,
//材质融合MultiplyBlending将前景色与背景色(MeshDepthMaterial渲染的方块)相乘
blending: THREE.MultiplyBlending
});
//混合材质创建网格
//顺序不要放错
var cube = new THREE.SceneUtils.createMultiMaterialObject(boxGeometry,[meshBasicMaterial,meshDepthMaterial]);
//将第一种材质对象缩小,解决闪光现象
//闪光现象 : 当一个物体作用在另一个物体上时,并且有一个物体是透明的,存在这种现象
cube.children[1].scale.set(0.99, 0.99, 0.99);
cube.castShadow = true;
// position the cube randomly in the scene
//Math.round() “四舍五入”, 该函数返回的是一个四舍五入后的的整数
cube.position.x = -60 + Math.round((Math.random() * 100));
cube.position.y = Math.round((Math.random() * 10));
cube.position.z = -100 + Math.round((Math.random() * 150));
scene.add(cube);
一般项目建模型时经常使用联合材质,概念要清晰。感兴趣的话可以自己测试一下,注意可能会出现闪光,个人理解是两个Mesh没有重合好。解决的话需要缩小一个即可。
四、THREE.MeshLambertMaterial(网格Lambert 材质)?
????????MeshLambertMaterial(常用)用于创建暗淡不光亮的表面。而且会对场景中的光源产生反应。MeshLambertMaterial材质的独有属性搭配基础属性适用于多种场景。
? ? ? ? MeshLambertMaterial材质的常用属性:
color | 材质的环境色(会与环境光颜色相乘) | emissive(自发光) | 并非光源,在暗处也可见 |
创建方式:
var meshMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
展示效果:
五、THREE.MeshPhongMaterial(网格 Phong式材质)?
? ? ? ? ? ?MeshPhongMaterial可以创建光亮的材质,与MeshLambertMaterial属性基本一样,不同的是通过MeshPhongMaterial可以实现高光效果。该材质下的模型既可以模拟金属质感的物体,还可以模拟塑料质感的物体。
MeshPhongMaterial材质的常用属性:
color | 材质的环境色(会与环境光颜色相乘) | emissive(自发光) | 并非光源,在暗处也可见 | specular(高光颜色) | 指定该材质的光亮程度及高光部分颜色 | shiness(高光度) | 镜面高光的清晰程度(默认30)光滑度高的表面清晰度高 |
?创建方案:
var material = new THREE.MeshPhongMaterial({
color: 0x7777ff
});
?常用属性方式:
var controls = new function (){
this.transparent = false;
this.opacity = 1;
this.visible = true;
this.ambient = 0x0c0c0c;
//材质自身颜色不受光照影响
this.emissive = material.emissive.getHex();
//高光 即可模仿塑料质感 又可模仿金属质感
this.specular = material.specular.getHex();
//高光部分轮廓的清晰程度
this.shininess = material.shininess;
//对应的对象那一面有材质
this.side = "front";
//材质的环境光
this.color = material.color.getStyle();
this.wrapAround = false;
this.wrapR = 1;
this.wrapG = 1;
this.wrapB = 1;
this.selectedMesh = "cube";
}
测试效果:建议对比MeshLambertMaterial材质进行测试。
简单测试感觉没啥区别。高光效果暂时没找到运用的demo。后续测试
六、 THREE.ShaderMaterial(着色器材质)
????????THRFE.ShaderMaterial是Threejs库中最通用、最复杂的材质之一。通过自己定制的着色器,直接在WebGL环境中运行。着色器可以将Threejs中的JavaScript网格转换为屏幕上的像素。通过这些自定义的着色器,可以明确地指定对象如何渲染,以及如何覆盖或修改Threejs库中的默认值。
????????THREE.ShaderMaterial有一些我们已经见过的可以设置的属性。Three.js传人这些属性的所有信息,但是仍然必须在自己的着色器程序中处理这些信息。
着色器时使用类似与C语言的GLSL语言编写的(应该是OpenES 着色语言)
部分代码:
<script id="fragment-shader-6" type="x-shader/x-fragment">
uniform float time;
uniform vec2 resolution;
void main( void )
{
vec2 uPos = ( gl_FragCoord.xy / resolution.xy );//normalize wrt y axis
//suPos -= vec2((resolution.x/resolution.y)/2.0, 0.0);//shift origin to center
uPos.x -= 1.0;
uPos.y -= 0.5;
vec3 color = vec3(0.0);
float vertColor = 2.0;
for( float i = 0.0; i < 15.0; ++i )
{
float t = time * (0.9);
uPos.y += sin( uPos.x*i + t+i/2.0 ) * 0.1;
float fTemp = abs(1.0 / uPos.y / 100.0);
vertColor += fTemp;
color += vec3( fTemp*(10.0-i)/10.0, fTemp*i/10.0, pow(fTemp,1.5)*1.5 );
}
vec4 color_final = vec4(color, 1.0);
gl_FragColor = color_final;
}
</script>
着色器测试效果:
?七、 THREE.LineBasicMaterial(直线基础材质)
基础属性:? ? ??
color | 该属性定义线的颜色。如果指定了vertexColors,这个属性就会被忽略? | linewidth | 该属性定义线的宽度? | vertexColors | 设置成THREEVertexColors值,就可以给每个顶点指定一种颜色 |
创建方案:?
var material = new THREE.LineBasicMaterial({
opacity: 1,
linewidth: 0.1,
vertexColors: THREE.VertexColors
});
实例效果:
?还可以通过LineDashMaterial(虚线材质)产生虚线效果:
lines.computeLineDistances();
var material = new THREE.LineDashedMaterial({
vertexColors: true,
color: 0xcccccc,
dashSize: 0.1, //虚线段的长度
gapSize: 0.6, //虚线段间隔的宽度
scale: 1
});
var line = new THREE.Line(lines, material);
line.position.set(25, -30, -60);
scene.add(line);
必须强调的是:调用computeLineDistanceO(用来计算线段顶点之间的距离)。如果不这么做,间隔就不会正确地显示。
八、总结
? ? ? ? Threejs提供了很多材质用于给几何体指定皮肤。从简单的THREE.MeshBasicMaterial到复杂的 THREE.ShaderMaterial,通过THREE.ShaderMaterial可以提供自己的顶点着色器和着色器程序。材质共享很多基础属性。如果你知道如何使用一种材质,可能也知道如何使用其他材质。注意,不是所有的材质都对场景中的光源做出反应。如能希望一个材质计算光照的影响,如果希望一个材质计算光照的影响,应该尽量使用准材质THREE.MeshStandardMatcrial。而当你需要更多控制时,可以考虑使用THRE MeshPhysicalMaterial、THREE.MeshPhongMaterial或 THREE.MeshLambertMaterial。 仅仅从代码确定某种材质属性的效果是非常困难的。通常,使用dat.GUI控制面板来试验这些性是一个不错的方法。 ????????同样的是,材质的大部分属性都可以在运行时修改。但是有一些属性(例如 side)不能在运行时修改。如果你要修改这些属性的值,需要将needsUpdate属性设置为 true。要了解运行时哪些属性可以修改,哪些不属性不能修改,
???????最新的两种材质测试属性测试效果在简单的场景并不能体现出来。有dmeo的小伙伴可以给我留言讨论一下效果。感谢。
?
|