webgl之Three.js学习 day3使用Three.js的材质

在开始这一节前,我们先将要探究的材质列在下表中:

名称

描述

MeshBasicMaterial(网格基础材质)

基础材质,可以用它赋予几何体一种简单的颜色,或者显示几何体的线框。

MeshDepthMaterial(网格深度材质)

根据网格到相机的距离,这种材质决定如何给网格染色。

MeshNormalMaterial(网格法向材质)

这是一种简单的材质,根据物体表面的法向向量计算颜色。

MeshFaceMaterial(网格面材质)

这是一个容器,可以在这个容器里为物体的各个表面指定不同的颜色。

MeshLambertMaterial(网格朗伯材质)

这种材质会考虑光照的影响,可以用来创建颜色暗淡的、不光亮的物体。

MeshPhongMaterial(网格Phong式材质)

这种材质也会考虑光照的影响,而且可以用来创建光亮的物体。

ShaderMaterial(着色器材质)

这种材质允许使用自定义的着色器程序,直接控制顶点的放置方式,以及像素的着色方式。

LineBasicMaterial(直线基础材质)

这种材质可以用于THREE.Line(直线)几何体,从而创建着色的直线。

LineDashedMaterial(虚线材质)

这种材质跟直线基础材质一样,不过可以用来创建出一种虚线效果。

注:1)Lambert,朗伯,一种亮度单位。

       2)Phong,一种着色方式。

一、理解共有属性


Three.js提供了一个材质基类,THREE.Material,这个类列出了所有共有属性。我们将这些共有属性分成了三类:

  • 基础属性:这些属性是最常用到的。通过这些属性可以控制物体的透明度、是否可见或如何引用物体(通过ID或自定义名称)。
  • 融合属性:每个物体都有一系列的融合属性。这些属性决定物体如何与背景融合。
  • 高级属性:有一些高级属性可以控制底层WebGL上下文渲染物体的方法。大多数情况下,不会用到这些属性。

1.基础属性

THREE.Material类的基础属性列在下表中。

属性

描述

ID(标识符)

用来标识材质,在创建时赋值。

name(名称)

可以通过这个属性赋予材质名称。

opacity(透明度)

定义物体有多透明。需与属性transparent一起使用。该属性的取值范围是0~1。

transparent(是否透明)

如果设为true,THREE.js库就会根据opacity的值来渲染物体。如果是false,这个物体就不透明,只是着色明亮一些。

overdraw(过度描绘)

如果你用THREE.CanvasRenderer(画布渲染器)对象,多边形会被渲染得稍微大一点儿。当你用这个渲染器画出来的物体有缝隙时,可以将这个属性设为true。

visible(是否可见)

定义该材质是否可见,如果设为false,那么在场景中就看不到该物体。

side(侧面)

通过这个属性,可以决定在几何体的哪一面应用这个材质。默认值是THREE.FrontSIde(前面),这可以将材质应用到物体的前(外)面。也可以将它设为THREE.BackSide(后面),这可以将材质应用到物体的后(内)侧。或者也可以将它设为THREE.DoubleSide(双侧),这样就可以将材质应用到物体的内外两侧。 

needsUpdate(要否刷新)

对于材质的某些修改,你需要告诉Three.js库材质已经改变了。如果这个属性设为true,THREE.js就会使用新的材质属性刷新它的缓存。

2.融合属性

 材质有几个跟融合相关的一些属性,如下表所示:

名称

描述

blending(融合)

决定物体上的材质如何跟背景融合。融合模式一般是NormalBlending,在这种模式下只显示材质的上层。

blendsrc(融合源)

除了使用标准融合模式之外,还可以通过指定blendsrc、blenddst和blendequation属性来创建自定义的融合模式。该属性指定物体(源)如何跟背景(目标)相融合。默认值是SrcAlphaFactor,即使用alpha(透明度通道进行融合)。

blenddst(融合目标)

该属性定义融合时如何使用背景(目标),默认值是OneMinusSrcAlphaFactor,其含义是:目标也使用源的alpha通道进行融合,只是用的值是1(源的alpha通道值)。

blendingequation(融合公式)

指定如何使用blendsrc和blenddst的值。默认方法是AddEquation,即将两个颜色值相加。使用这三个属性,就可以创建自定义的融合模式。

3.高级属性

高级属性跟WebGL内部如何工作相关。

名称

描述

depthTest(深度测试)

使用这个参数可以打开或关闭GL_DEPTH_TEST参数。该参数决定像素深度是否用来计算新的像素值。通常情况下不必修改这个属性。

depthWrite

可以用来决定这个材质是否影响WebGL的深度缓存。如果你将一个物体用作二维贴图时(例如一个套子),你应该将这个属性设为false。但一般来说,你不应该修改这个属性。

polygonOffset、polygonOffsetFactor和polygonOffsetUnits

通过这些属性,可以控制WenGL的POLYGON_OFFSET_FILL功能。一般不需要使用它们

alphaTest

可以给这个属性指定一个值(从0到1)。如果某个像素的alpha值小于这个值,那么该像素就不会显示出来。

 

二、从简单的网格材质(基础、深度和面)开始


1.简单表面的MeshBasicMaterial

MeshBasicMaterial是一种非常简单的材质,这种材质不考虑光照的影响。使用这种材质的网格会被渲染成一些简单的平面多边形,而且你也有机会显示几何体的线框。除了之前提到的共有属性,还可以设置以下属性:

名称

描述

color

设置材质的颜色。

wireframe

设置这个属性可以将材质渲染成线框。对调试非常有利。

wireframeLinewidth(线框线宽)

如果已经打开了wireframe,这个属性可以定义线框中线的宽度。

wireframeLinecap(线框线端点)

这个属性定义线框模式下顶点间线段的端点如何定义。可选值包括butt(平)、round(圆)和square(方)。默认值是round。在实际使用中,这个属性的修改结果很难看出来。WebGLRenderer对象不支持该属性。

wireframeLinejoin(线框线段连接点)

定义线段的连接点如何显示。可选的值包括round、bevel(斜角)和miter(尖角)。默认值是round。如果你在一个使用低透明度和很大wireframeLinewidth值的例子里靠近观察,你就可以观察到这个属性的效果。WebGLRenderer对象不支持该属性。

shading(着色)

该属性定义如何 着色。可选的值是THREE.SmoothShading和THREE.FlatShading。该属性在这个材质的例子里没有设置

vertexColors(顶点颜色)

可以通过这个属性为每一个顶点定义不同的颜色。该属性在使用CanvasRenderer时不起作用,但可以在使用WebGLRenderer时起作用。

fog(雾化)

该属性指定当前材质是否会受全局雾化效果设置的影响。

我们会像下面这样设置MeshBasicMaterial,所有的属性即可以在构造函数里传递,也可以在材质创建好之后设置:

var meshMaterial = new THREE.MeshBasicMaterial({color:0x7777ff});
meshMaterial.visible = false;

2.基于深度着色的MeshDepthMaterial

使用这种材质的物体,其外表不是由光照或某种材质决定的;而是由物体到相机的距离决定的。可以将这种材质与其他材质相结合,从而很容易地创建出逐渐消失的效果。这种材质只有两个控制线框的属性:

名称

描述

wireframe

是否显示线框

wireframeLinewidth

线框线的宽度

创建MeshDepthMaterial非常简单。这个对象没有多少参数。在下面这个例子中,我们使用了scene.overrideMaterial属性,以保证场景中的所有物体都会使用该材质,如下面这段代码所示:

var scene = new THREE.Scene();
scene.overrideMaterial = new THREE.MeshDepthMaterial();

3.联合材质

在MeshDepthMaterial中,你会发现没有选项可以用来设置方块的颜色,一切都是有材质的默认属性决定的。但是,Three.js库可以通过联合材质创建出新效果(这也是材质融合起作用的地方)。使用下面的代码,就可以把MeshDepthMaterial材质赋予方块:

var cubeMaterial = new THREE.MeshDepthMaterial();
var cubeColor = new THREE.MeshBasicMAterial({color:0x00ff00,
               transparent:true,blending:THREE.MultiplyBlending});
var cube = new THREE.SceneUtils.createMultiMaterialObject(
               cubeGeometry,[cubeMaterial,cubeColor]);
cube.children[1].scale.set(0.99,0.99,0.99);

然后就可以获得下图所示的绿色方块,这些方块从MeshBasicMaterial中获得渐变效果,从MeshBasicMaterial中获得颜色。

让我们来看看要达到这种效果需要采取的步骤:

首先,要创建两种材质,对于MeshDepthMaterial没有什么特别要做的,但对于MeshBasicMaterial,要把transparent属性设为true,并指定融合模式;

其次,调用createMultiMaterialObject()函数创建一个网格,此时,几何体会被复制,返回一个网格组,里面两个网格完全相同;

最后,代码的最后一行也很重要,如果没有最后一行,那么在渲染的时候画面就会闪烁,因为它们会直接在彼此的上面渲染。通过缩小带有MeshDepthMaterial材质的网络,就可以避免这种现象。

4.计算法向颜色的MeshNormalMaterial

如下图所示,网格上的 每一面在渲染时颜色都稍有不同,而且即便在球体旋转时,这些颜色也基本上保持原来的位置。之所以是这样,是因为每一个面的颜色是从该面向指的法向量计算得出的。法向量所指的方向决定每个面从MeshNormalMaterial材质获取的颜色。

MeshNormalMaterial对象还有几个属性可以设置,如下表所示:

名称

描述

wireframe

该属性指定是否显示线框

wireframeLinewidth

指定线框的宽度

shading

该属性用来设置着色方式:THREE.FlatShading表示平面着色,THREE.SmoothShading表示平滑着色。

5.为每个面指定材质的MeshFaceMaterial

这种基础材质并不是真正的材质,更像是一个材质容器。通过MeshFaceMaterial可以为几何体的每个面指定不同的材质。这种材质使用起来很简单,如下所示:

var matArray = [];
matArray.push(new THREE.MeshBasicMaterial({color: 0x009e60}));
matArray.push(new THREE.MeshBasicMaterial({color: 0x0051ba}));
matArray.push(new THREE.MeshBasicMaterial({color: 0xffd500}));
matArray.push(new THREE.MeshBasicMaterial({color: 0xff5800}));
matArray.push(new THREE.MeshBasicMaterial({color: 0xc41e3a}));
matArray.push(new THREE.MeshBasicMaterial({color: 0xffffff}));
var faceMaterial = new THREE.MeshFaceMaterial(matArray);
var cubeGeom = new THREE.CubeGeometry(3,3,3);
var cube = new THREE.Mesh(cubeGeom,faceMaterial);

效果图如下图所示:

 

三、学习高级材质


1.用于暗淡、不光亮表面的MeshLambertMaterial

这种材质可以用来创建看上去暗淡的并不光亮的表面。该材质非常易用,而且会对场景中的光源产生反应。可以在这个材质上配置之前提到的几个属性:color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLinewidth、wireframeLinecap、wireframeLinejoin、vertexColors以及fog。这种材质还有两种独有的材质:

名称

描述

ambient(环境色)

这是该材质的环境光。跟AmbientLight光源一起使用。这个颜色会与AmbientLight光源的颜色相乘。默认值是白色。

emissive(发射的)

这是该材质发射的颜色。它其实并不像一个光源,只是一种纯粹的、不受其他光影响的颜色。默认值是黑色。

这种材质的创建跟其他材质都一样,如下所示:

var meshMaterial = new THREE.MeshLambertMaterial({color:0x7777ff});

2.用于光亮表面的MeshPhongMaterial

通过MeshPhongMaterial,可以创建一种光亮的材质。可以使用的属性与创建暗淡材质的MeshLambertMaterial基本一样。对于这种材质我们将感兴趣的属性列在下表中:

名称

描述

ambient

这是该材质的环境色。

emissive        这是该材质发射的颜色。它其实并不像一个光源,只是一种纯粹的、不受其他光照影响的颜色。默认值是黑色。
specular(镜面的)

该属性指定该材质的光亮程度及其高光部分的颜色。如果将它设置成跟color属性相同的颜色,将会得到一种更加类似金属的材质。如果设置为grey(灰色),材质将变得更像塑料。

shininess        该属性指定高光部分的亮度。默认值是30.

3.用ShaderMaterial创建自己的着色器

通过ShaderMaterial,可以使用自己定制的着色器,着色器可以将Three.js中的Javascript对象转换为屏幕上的像素。通过自定义的着色器,你可以明确指定你的对象如何渲染和遮盖,或者修改Three.js库中的默认值。

ShaderMaterial有几个属性可以设置,除了包括之前提到的wireframe、wireframeLinewidth、shading、vertexColors以及fog属性,还有几个特别属性,使用它们你可以传入数据,定制你的着色器。

名称

描述

fragmentShader(像素着色器)

这个着色器定义的是每个传入的像素的颜色

vertexShader(顶点着色器)

这个着色器允许你修改每一个传入的顶点的位置

uniforms(统一值)

通过这个属性可以向你的着色器发信息。同样的信息会发到每一个顶点和片段

definess

这个属性的值可以转换成vertexShader和fragmentShader里的#define代码。该属性可以用来设置着色器程序里的一些全局变量

attributes

该属性可以修改每个顶点和片段。通常用来传递位置数据和与法向量相关的数据。如果要用这个属性,那么你要为几何体中的所有顶点提供信息

lights

该属性定义光照数据是否传递给着色器。默认值是false

要使用ShaderMaterial材质,必须要传入两个不同的着色器:

(1)vertexShader:vertexShader会在几何体的每一个顶点上执行。可以用这个着色器通过改变顶点的位置来对几何体进行变换。

(2)fragmentShader:fragmentShader会在几何体的每一个像素上执行。在vertexShader里,我们会返回这个特定像素应该显示的颜色。

编写好着色器后,我们要将vertexShader与fragmentShader传入ShaderMaterial,出于这个目的,我们可以创建如下一个简单的辅助函数:

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;
}

 

四、线段几何体的材质


1.LineBasicMaterial

通过线段基础材质可以设置线段的颜色、宽度、端点和连接点属性。下表列出的是这种材质中可用的属性:

名称

描述

color

指定线的颜色。如果指定vertexColors,这个属性就会被忽略

linewidth

定义先的宽度

LineCap

定义顶点间的线段端点如何显示。可选的值包括butt(平)、round(圆)和square(方)。默认值是round。在实际应用中,修改这个属性的结果很难看出来。WebGLRenderer也不支持该属性

LineJoin

定义的是线段连接点如何显示。可选的值包括round(圆)、bevel(斜切)和miter(尖角)。默认值是round

vertexColors

将这个属性设置成THREE.VertexColors值,就可以为每个顶点指定一个颜色

fog        指定当前物体是否受全局雾化效果i的影响

我们先来快速浏览一下如何从顶点集合中创建出一些线段,并为它们赋予LineBasicMaterial材质,构成一个网格。代码如下所示:

var points = gosper(4,60);   //返回一个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);   //HSL:色调、饱和度、亮度
    i++;
});
lines.colors = colors;
var material = new THREE.LineBasicMaterial({
    opacity:1.0,
    linewidth:1,
    vertexColors:THREE.VertexColors });
var line = new THREE.Line(lines,material);

 效果图如下所示:

2.LineDashedMaterial

这种材质的属性跟LineBasicMaterial的属性一样,但是通过指定短划线和空格的长度,可以创建出虚线的效果。这种材质的几个额外的、可以用来定义短划线长度和短划线中间空格长度的属性,如下所示:

名称

描述

scale(缩放比例)

缩放dashSize和gapSize。如果scale小于1,dashSize和gapSzie就会增大;如果scale大于1,dashSize和gapSzie就会缩小

dashSize

短划线的长度

gapSize

间隔的长度

这种属性的用法跟LineBasicMaterial基本一样,唯一的区别是必须调用computeLineDistances(),如下所示:

lines.computeLineDistances();
var material = new THREE.LineDashedMaterial({
                    vertexColors:true,
                    color:0xffffff,
                    dashSize:10,
                    gapSize:1,
                    scale:0.1
                });

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值