共计 10188 个字符,预计需要花费 26 分钟才能阅读完成。
Three.JS的材质
在Three.js中材质就像是物体的皮肤,决定了几何的样子。
类型 | 名称 | 描述 |
---|---|---|
网络材质 | MeshBasicMaterial(网络基础材质) | 基础材质,可以用它赋予几何体一种简单的颜色,或者显示几何体的线框 |
网络材质 | MeshDepthMaterial(网络深度材质) | 根据网络到相机的距离,这种材质决定如何给网格着色 |
网络材质 | MeshNormalMaterial(网络法向材质) | 这是一种简单的材质,根据物体表面的法向向量计算颜色 |
网络材质 | MeshFaceMaterial(网络面材质) | 这是一个容器,可以在这个容器里面为物体的各个表面指定不同的颜色 |
高级材质 | MeshLambertMaterial(网络朗伯材质) | 这种材质会考虑光照的影响,可以创造颜色暗淡的,不光亮的物体 |
高级材质 | MeshPhongMaterial(网络Phong式材质) | 这种材质会考虑光照的影响,可以用来创造光亮的物体 |
高级材质 | ShaderMaterial(着色器材质) | 这种材质允许使用自定义的着色器程序,直接控制顶点的放置方式,以及像素的着色方式 |
线段几何体材质 | LineBasicMaterial(直线基础材质) | 这种材质可以用于Three.Line 几何体,从而创建着色的直线 |
线段几何体材质 | LineDashedMaterial(虚线材质) | 这种材质跟直线基础材质一样,不过用于创建虚线效果 |
材质的共同属性
- 基础属性:用于控制物体的透明度,是否可见,以及如何引用物体。
- 融合属性:每个物体都有一系列的融合属性,这些属性决定物体如何与背景融合。
- 高级属性:用于控制底层WebGL上下文渲染物体的方法。
基础属性有以下值:
属性 | 描述 |
---|---|
ID | 材质的ID,创建时赋值 |
name | 材质的name,创建时赋值 |
opacity | 透明度(0-1) |
transparent | 是否透明(true,false) |
overdraw过度描绘 | 如果用THREE.CanvasRenderer(画布渲染器)对象,多边形会被渲染的稍微大一点。当你用渲染器画出来的物体有缝隙时,这个值可以设置为true |
visible是否可见 | 定义该材质是否可见,true,false |
side侧面 | 通过这个属性,可以决定在几何体的哪一面应用这个材质。默认值是THREE.FrontSide前面,表示将材质用于前面。BackSide(后面),DoubleSide(两侧) |
needsUpdate是否刷新 | 是不是用于刷新缓存 |
融合属性有以下值:
属性 | 描述 |
---|---|
blending融合 | 决定物体上的材质如何与背景融合,一般为NormalBlending,这种模式下只显示材质的上层 |
blendsrc融合源 | 表示指定物体如何跟背景相融合,默认值SrcAlphaFactor,即使用透明度通道进行融合 |
blenddst融合目标 | 这是如何使用背景,默认值OneMinusSrcAlphaFactor,目标也使用源的透明通道进行融合,只是用的值是1 |
blendingequation融合公式 | 指定如何使用blendsrc和blenddst的值,默认方法是AddEquation,即使将两个颜色值相加 |
高级属性有以下值:
属性 | 描述 |
---|---|
blending融合 | 决定物体上的材质如何与背景融合,一般为NormalBlending,这种模式下只显示材质的上层 |
blendsrc融合源 | 表示指定物体如何跟背景相融合,默认值SrcAlphaFactor,即使用透明度通道进行融合 |
blenddst融合目标 | 这是如何使用背景,默认值OneMinusSrcAlphaFactor,目标也使用源的透明通道进行融合,只是用的值是1 |
blendingequation融合公式 | 指定如何使用blendsrc和blenddst的值,默认方法是AddEquation,即使将两个颜色值相加 |
1. MeshBasicMaterial材质
MeshBasicMaterial是一种非常简单的材质,不考虑光照的影响。它有以下属性:
属性 | 描述 |
---|---|
color | 设置材质的颜色 |
wireframe | 设置这个属性可以将材质渲染成线框 |
wireframeLinewidth | wireframe这个打开的时候,设置这个值表示线的宽度 |
wireframeLinecap | 表示顶点间线段的端点如何显示,butt平,round圆,square方。webglrenderer对象不支持该属性 |
wireframeLinejoin | 定义线段的连接点如何显示,round,bevel斜角,miter尖角。webglrenderer对象不支持该属性 |
shading着色 | 定义如何着色,可选值是THREE.SmoothShading和THREE.FlatShading |
vertexColors顶点颜色 | 为每个顶点设置不同的颜色。CanvasRanderer时不起作用。webglrenderer对象支持该属性 |
fog雾化 | 该属性指定当前材质是否受全局雾化效果设置的形象 |
举个栗子
var meshMaterial = new THREE.MeshBasicMaterial({color:0x7777ff});
meshMaterial.visible = false;
2. MeshDepthMaterial材质
MeshBasicMaterial材质的物体,外观不是由光照和某个材质属性决定的,而是由物体到相机的距离决定的。可以将该材质与其他材质结合。它有以下属性:
属性 | 描述 |
---|---|
wireframe | 设置这个属性可以将材质渲染成线框 |
wireframeLinewidth | wireframe这个打开的时候,设置这个值表示线的宽度 |
举个栗子
var scene = new THREE.Scene();
scene.overrideMaterial = new THREE.MeshDepthMaterial();
3. MeshNormalMaterial材质
MeshBasicMaterial法向颜色材质,外观不是由光照和某个材质属性决定的,而是由物体到相机的距离决定的。可以将该材质与其他材质结合。它有以下属性:
属性 | 描述 |
---|---|
wireframe | 设置这个属性可以将材质渲染成线框 |
wireframeLinewidth | wireframe这个打开的时候,设置这个值表示线的宽度 |
shading着色 | 定义如何着色,可选值是THREE.SmoothShading平滑着色和THREE.FlatShading平面着色 |
法向量是与面垂直的向量,法向量在THEREE中用于决定光的反射反向,用于计算光照,阴影时提供信息,用于为物体表面像素上色。
举个栗子
//表示法向量的箭头,可以使用THREE.ArrowHelper对象
for(var f=0,fl=sphere.geometry.faces.length;f<fl;f++){
var arrow = new THREE.ArrowHelper(face.normal,face.centroid,2);
shpere.add(arrow);
}
4. MeshFaceMaterial材质
MeshBasicMaterial,是一种材质容器。可以以几何体的每一个面指定不同的材质。
举个栗子
var metArray = [];
metArray.push(new THREE.MeshBasicMaterial({color:0x009e60}));
metArray.push(new THREE.MeshBasicMaterial({color:0x0051ba}));
metArray.push(new THREE.MeshBasicMaterial({color:0xffd500}));
metArray.push(new THREE.MeshBasicMaterial({color:0xc49e60}));
metArray.push(new THREE.MeshBasicMaterial({color:0xffffff}));
metArray.push(new THREE.MeshBasicMaterial({color:0x000000}));
var faceMaterial = new THREE.MeshFaceMaterial(metArray);
//1
var cubeGeom1 = new THREE.CubeGemotry(3,3,3);
var cube1 = new THREE.Mesh(cubeGeom1, faceMaterial);
//2
var group = new THREE.Mesh();
for(var x = 0;x<3;x++){
for(var y=0;y<3;y++){
for(var z=0;z<3;z++){
var cubeGeom = new THREE.CubeGemotry(2.9,2.9,2.9);
var cube = new THREE.Mesh(cubeGeom, faceMaterial);
cube.position = new THREE.Vector3(x*3-3,y*3,z*3-3);
group.add(cube);
}
}
}
5. 联合材质
- MeshDepthMaterial使用的时候设置方块的颜色,而材质是使用默认的。 举个栗子
var cubem = new THREE.MeshDepthMaterial();
var colorm = new THREE.MeshBasicMaterial({
color:0x00ff00,
transparent:true,//指定融合模式,不透明
blending:THREE.MultiplyBlending //前景的颜色跟背景的颜色相乘,得出结果
});
var cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry,[colorm, cubem]);//createMultiMaterialObject用于创建一个网格,几何体会被复制,返回一个新的网格组
cube.childreb[1].scale.set(0.99,0.99,0.99)//防止画面闪烁。
6.高级材质
6.1 用于暗淡、不光亮表面的MeshLambertMaterial
MeshLambertMaterial除了以上所有属性,还有两个特有属性;
属性 | 描述 |
---|---|
ambient环境色 | 这是该材质的环境色,跟AmbientLight一起使用。其值会与AmbientLight光源的颜色相乘。默认白色 |
emissive反射的 | 这是该材质的反射的颜色,一种不受其他光源影响的颜色,默认黑色 |
举个栗子
var cubem = new THREE.MeshLambertMaterial({color:0x7777ff});
6.2 用于光亮表面的MeshPhongMaterial
MeshPhongMaterial除了以上所有属性,还有两个特有属性;
属性 | 描述 |
---|---|
ambient环境色 | 这是该材质的环境色,跟AmbientLight一起使用。其值会与AmbientLight光源的颜色相乘。默认白色 |
emissive反射的 | 这是该材质的反射的颜色,一种不受其他光源影响的颜色,默认黑色 |
specular镜面的 | 该属性指定该材质的光亮程度及其高光部分的颜色。如果该值与color属性值一样,会得到一种类似金属的材质。 |
shininess | 该属性指定高光部分的亮度,默认30 |
举个栗子
var cubem = new THREE.MeshPhongMaterial({color:0x7777ff});
6.3 ShaderMaterial创建自己的着色器
ShaderMaterial是THREE中最复杂的材质。以下是普通属性
属性 | 描述 |
---|---|
wireframe | 设置这个属性可以将材质渲染成线框。用于调试 |
wireframeLinewidth | 定义线框中线的宽度 |
shading | 定义如何着色,可选值是THREE.SmoothShading平滑着色和THREE.FlatShading平面着色 |
vertexColors | 可以通过这个属性为每一个顶点定义不同的颜色 |
fog | 该属性指定当前材质是否会受到全局雾化效果设置影响。 |
除了以上属性,还有以下特别属性;
属性 | 描述 |
---|---|
fragmentShader(像素着色器) | 这个着色器定义的是每个传入的像素的颜色 |
vertexShader(顶点着色器) | 修改每一个传入的顶点的位置 |
uniforms(统一值) | 通过这个属性可以向你的着色器发信息。同样的信息会发到每一个顶点和片段 |
defines | 这个属性的值可以转换成vertexShader 和 fragmentShader 里面的#define 的代码。该属性可以用来设置着色器程序里的一些全局变量 |
attributes | 该属性可以修改每个顶点和片段。通常用来传递位置数据和法向量相关的数据。 |
lights | 该属性定义光照数据是否传递给着色器。默认值false |
要使用ShaderMaterial材质,需要传入两个不同的着色器:
- vertexShader: vertexShader会在几何体的每一个顶点上执行。可以用这个着色器通过改变顶点位置来对几何体进行变换。
- fragmentShader: fragmentShader会在几何体的每一个像素上执行。在vertexShader里,我们会返回这个特定像素应该显示的颜色。
举个栗子
<script id='vertex-shader' type='x-shader/x-vertex'>
uniform float time;
void main(){
vec3 posChanged = position;
posChanged.x = posChanged.x * (abs(sin(time*1.0)));
posChanged.y = posChanged.y * (abs(cos(time*1.0)));
posChanged.z = posChanged.z * (abs(sin(time*1.0)));
gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0)
}
</script>
着色器不是JS编写的,用类似C的GLSL语言来编写的着色器。
gl_Position是一个特殊变量,用来返回最终位置。
function createMaterial(vertexShader,fragmentShader) {
var vertShader = document.getElementById(vertexShader).innerHTML;
var fragShader = document.getElementById(fragmentShader).innerHTML;
var attributes = {};
var uniforms = {
time:{type:'f',value:0.2},
scale:{type:'f',value:0.2},
alpha:{type:'f',value:0.6},
resolution:{type:'v2',value: new THREE.Vector2},
};
uniforms.resolution.value.x = window.innerWidth;
uniforms.resolution.value.y = window.innerHeight;
var meshMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader : vertShader,
fragmentShader: fragShader,
transparent: true,
});
return meshMaterial;
}
用法是:var meshMaterial1 = createMaterial(“vertex-shader”,“fragment-shader-1”)
。这些参数所指的是HTML页面元素的ID。这个变量是用来从我们的渲染器中向着色器传递信息的。
function render(){
stats.update();
cube.rotation.y = step+=0.1;
cube.rotation.x = step;
cube.rotation.z = step;
cube.meterial.meterials.forEach(function(e){
e.uniforms.time.value +=0.1;
})
requestAnimationFrame(render);
renderer.render(scene,camera);
}
上面中这个渲染循环每执行一次变量time就会增加0.01。这个信息会传递给vertexShader,用来计算方块顶点的新位置。
每一个面都在不断变化,正是每个面上的fragmentShader造就了变化。使用了MeshFaceMaterial。
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var meshMaterial1 = createMaterial("vertex-shader", "fragment-shader-1");
var meshMaterial2 = createMaterial("vertex-shader", "fragment-shader-2");
var meshMaterial3 = createMaterial("vertex-shader", "fragment-shader-3");
var meshMaterial4 = createMaterial("vertex-shader", "fragment-shader-4");
var meshMaterial5 = createMaterial("vertex-shader", "fragment-shader-5");
var meshMaterial6 = createMaterial("vertex-shader", "fragment-shader-6");
var material = new THREE.MeshFaceMaterial(
[meshMaterial1,
meshMaterial2,
meshMaterial3,
meshMaterial4,
meshMaterial5,
meshMaterial6]);
<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.JS库的颜色是通过gl_FragColor = color_final;
设置的。
7.线段几何体的材质
线段几何体的材质主要包括两个:
- LineBasicMaterial: 通过线段基础材质可以设置线段的颜色、宽度、端点、连接点的属性。
- LineDashedMaterial: 跟LineBasicMaterial一样。但是通过指定短划线和空格的长度,可以创造出虚线效果。
7.1 LineBasicMaterial
属性 | 描述 |
---|---|
color | 指定线的颜色。如果指定vertexColors,这个属性忽略。 |
linewidth | 线的宽度 |
LineCap | 该属性定义顶点间的线段端点如何显示。butt,round,square. |
LineJoin | 定义线段连接点如何显示。round,bevel,miter. |
vertexColors | 可以为每个顶点指定一种颜色 |
fog | 定义该物体是否受到全局雾化效果影响 |
var points = gosper(4, 60);//获取一组xy的坐标,返回一个gosper曲线。
var lines = new THREE.Geometry();
var colors = [];
var i = 0;
points.forEach(function (e) {
lines.vertices.push(new THREE.Vector3(e.x, e.z, e.y));
colors[i] = new THREE.Color(0xffffff);
colors[i].setHSL(e.x / 100 + 0.5, ( e.y * 20 ) / 300, 0.8);
//使用setHSL设置颜色。还可以使用HSL,RGB等设置
i++;
});
lines.colors = colors;
var material = new THREE.LineBasicMaterial({
opacity: 1.0,
linewidth: 1,
vertexColors: THREE.VertexColors
});
var line = new THREE.Line(lines, material);
line.position.set(25, -30, -60);
scene.add(line);
7.2 LineDashedMaterial
属性 | 描述 |
---|---|
scale缩放比例 | 缩放dashSize和gapSize,如果scale小于1,dashSize和gapSize就会增大,反之减小。 |
dashSize | 短划线的长度 |
gapSize | 间隔的长度 |
lines.computeLineDistances();
var material = new THREE.LineDashedMaterial({
vertexColors: true,
color: 0xffffff,
dashSize: 2,
gapSize: 2,
scale: 0.1
});
var line = new THREE.Line(lines, material);
line.position.set(25, -30, -60);
scene.add(line);
8. 总结
three.js库提供的很多覆盖几何体的材质。从简单到复杂。总结:
- 各种材质有很多共同的属性。
- 并不是所有的材质都会带场景的光源做出反应。MeshPhongMaterial和MeshLambertMaterial会对场景的光源做出反应,
- 如果要创建一个透明的材质,仅仅设置opacity属性是不够的,还要将transparent设置成true。
- 材质的大部分属性都可以在运行时修改。但是side不能,如果你要修改需要将needsUpdate设置为true,这样就能在运行中修改属性了、
- 可以为一个几何体赋值多种材质。这样会复制几何体创建多个网格
- THREE.Line几何体不可以用普通材质覆盖。只能用线段几何体的材质。
- 如果想要一个光亮的物体,可以使用MeshPhongMaterial;如果想要一个暗淡的物体可以使用MeshLambertMaterial;
- 可以用dat.GUI来试验各种材质属性。