Three.js - 材质的使用详解

 

原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1816.html

原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1815.html
原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1819.html
原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1830.html

git项目示例源码地址: https://github.com/jdk137/learnThree.js

在线示例地址:

4. 1 MeshBasicMaterial 网格基础材质

4. 2 MeshDepthMaterial 网格深度材质

4. 3 材质结合: 基础材质 + 深度材质

4. 4 MeshNormalMaterial 网格法向材质

4. 5 MeshFaceMaterial 网格面材质

4. 6 MeshLambertMaterial 网格lambert材质

扫描二维码关注公众号,回复: 5603496 查看本文章

4. 7 MeshPhongMaterial 网格phong材质

4. 8 ShaderMaterial 着色器材质

4. 9 LineBasicMaterial 直线基础材质

4. 10 LineDashMaterial 虚线材质

我们知道一个材质结合 THREE.Geometry 对象,可以构成 THREE.Mesh 对象。材质就像物体的皮肤,决定了几何体的外表。例如皮肤定义了一个几何体看起来是否像金属、透明与否、或者显示为线框。

原文:Three.js - 材质的使用详解1(各种材质、及共有属性简介)


本文先简单介绍下 Three.js 里的各种材质,以及它们共有的一些属性。 

Three.js - 材质的使用详解1(各种材质、及共有属性简介)

一、Three.js 库提供的所有材质

 名称 描述
 MeshBasicMaterial(网格基础材质)  基础材质,用于给几何体赋予一种简单的颜色,或者显示几何体的线框。
 MeshDepthMaterial(网格深度材质)  这个材质使用从摄像机到网格的距离来决定如何给网格上色。
 MeshNormalMaterial(网格法向材质)  这是一种简单的材质,根据法向向量计算物体表面的颜色。
 MeshFaceMaterial(网格面材质)  这是一个容器,可以为几何体的各个表面指定不同的材质。
 MeshLambertMaterial(网格 Lambert 材质)  这是一种考虑光照影响的材质,用于创建暗淡的、不光亮的物体。
 MeshPhongMaterial(网格 Phong 式材质)  这是一种考虑光照影响的材质,用于创建光亮的物体。
 ShaderMaterial(着色器材质)  这种材质允许使用自定义的着色器程序,直接控制顶点的放置方式以及像素的着色方式。
 LineBasicMaterial(直线基础材质)  这种材质可以用于 THREE.Line(直线)几何体,用来创建着色的直线。
 LineDashMaterial(虚线材质)  这种材质与 LineBasicMaterial(直线基础材质)一样,但允许创建出一种虚线的效果。

二、材质的共有属性

Three.js 提供了一个材质基类 THREE.Material,它列出了所有的共有属性。这些共有属性可以分成三类。

1,基础属性

这些属性是最常用的。通过这些属性,可以控制物体的不透明度、是否可见以及如何被引用(通过 ID 或者自定义名称)。

 名称 描述
 id(标识符)  用来识别材质,并在材质创建时赋值。第一个材质的值从 0 开始,每新加一个材质,这个值就增加 1。
 uuid(通用唯一识别码)  这是生成的唯一 ID,在内部使用。
 name(名称)  可以通过这个属性赋予材质名称,用于调试的目的。
 opacity(不透明度)  定义物体的透明度。与 transparent 属性一起使用。该属性的赋值范围从 0 到 1。
 transparent(是否透明)
  • 如果该值设置为 true,Three.js 会使用指定的不透明度渲染物体。
  • 如果设置为 false,这个物体就不透明(只是着色更明亮些)。
  • 如果使用 alpha(透明度)通道的纹理,该属性应该设置为 true。
 overdraw(过度描绘)  当你使用 THREE.CanvasRender 时,多边形会被渲染得稍微大一点。当使用这个渲染器渲染的物体有间隙时,可以将这个属性设置为 true。
 visible(是否可见)  定义该材质是否可见。如果设置为 false,那么在场景中就看不到该物体。
 side(侧面)   通过这个属性,可以定义几何体的哪一面应用材质。
  • 默认值为 THREE.FrontSide(前面),这样可以将材质应用到物体的前面(外侧)。
  • 也可以将其设置为 THREE.BackSide(后面),这样可以将材质应用到物体的后面(内侧)。
  • 或者也可以将它设置为 THREE.DoubleSide(双侧),可将材质应用到物体的内外两侧。
 needsUpdate(是否更新)  对于材质的某些修改,你需要告诉 Three.js 材质已经改变了。如果该属性设置为 true,Three.js会使用新的材质属性更新它的缓存。

2,融合属性

每个物体都有一系列的融合属性。这些属性决定了物体如何与背景融合。

 名称 描述
 blending(融合)  该属性决定物体上的材质如何与背景融合。一般的融合模式是 THREE.NormalBlending,在这种模式下只显示材质的上层。。
 blendsrc(融合源)  除了使用标准融合模式之外,还可以通过设置 blendsrc、 blenddst 和 blendequation 来创建自定义的融合模式。
这个属性定义了该物体(源)如何与背景(目标)相融合。默认值为 THREE.SrcAlphaFactor,即使用 alpha(透明度)通道进行融合。
 blenddst(融合目标)  这个属性定义了融合时如何使用背景(目标),默认值为 THREE.OneMinusSrcAlphaFactor,其含义是目标也使用源的 alpha 通道进行融合,只是使用的值是 1(源的 alpha 通道值)。
 blendequation(融合公式)  定义了如何使用 blendsrc 和 blenddst 的值。默认值为使它们相加(AddEquation)。通过使用这三个属性,可以创建自定义的融合模式。

3,高级属性

这些高级属性可以控制底层 WebGL 上下文对象渲染物体的方式。不过大多数情况下是不需要使用这些属性的。

 名称 描述
 depthTest  这是一个高级 WebGL 属性。使用这个属性可以打开或关闭 GL_DEPTH_TEST 参数。此参数控制是否使用像素深度来计算新像素的值。通常情况下不必修改这个属性。更多信息可以在 OpenGL 规范中找到。
 depthWrite  这是另外一个内部属性。这个属性可以用来决定这个材质是否影响 WebGL 的深度缓存。如果你将一个物体用作二维贴图(例如一个套子),应该将这个属性设置为 false。但是,通常不应该修改这个属性。
 polygonOffset
 polygonOffsetFactor
 polygonOffsetUnits
 通过这些属性,可以控制 WebGL 的 POLYGON_OFFSET_FILL 特性。一般不需要使用它们。有关这些属性具体做什么的解释,可以参考 OpenGL 规范。
 alphatest  可以给这个属性指定一个值(从 0 到 1)。如果某个像素的 alpha 值小于该值,那么该像素不会显示出来。可以使用这个属性移除一些与透明度相关的毛边。

三、配置材质属性的两种方法

(1)有如下两种方式用来配置材质的属性。通常来说如果知道所有属性的值,最好的方式是在创建材质对象时使用构造方法传入参数(方法1)。
(2)这两种方式中参数使用相同的格式。唯一例外的是 color 属性:

  • 第一种方式中,可以只传人十六进制值,Three.js 会自己创建一个 THREE.Color 对象。
  • 第二种方式中,必须创建一个 THREE.color 对象。

方法1:可以在构造函数中通过参数对象的方式传入参数。

1

2

3

4

5

6

var meshMaterial = new THREE.MeshBasicMaterial({

  color: 0x7777ff,

  name: 'material-1',

  opacity: 0.5,

  transparent: true

});

方法2:还可以创建一个实例,并分别设置属性。

1

2

3

4

5

var meshMaterial = new THREE.MeshBasicMaterial();

meshMaterial.color = new THREE.Color(0x7777ff);

meshMaterial.name = 'material-1';

meshMaterial.opacity = 0.5;

meshMaterial.transparent = true;

Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)

一、THREE.MeshBasicMaterial(网格基础材质)

MeshBasicMaterial 是一种非常简单的材质,这种材质不考虑场景中光照的影响。使用这种材质的网格会被渲染成简单的平面多边形,而且也可以显示几何体的线框。

1,属性介绍

除了那些共有属性之外,MeshBasicMaterial 还有如下特有的属性。

 名称 描述
 color(颜色)  设置材质的颜色。
 wireframe(线框)  设置这个属性可以将材质渲染成线框,非常适用于调试。
 wireframeLinewidth(线框线宽)  如果已经打开了 wireframe,这个属性定义线框中线的宽度。
 wireframeLinecap(线框线段端点)  这个属性定义了线框模式下顶点间线段的端点如何显示。可选的值包括:
  • round:圆(默认值)
  • butt:平
  • square:方
 在实际使用中,这个属性的修改结果很难看出来。 WebGLRenderer 对象不支持该属性。
 wireframeLinejoin(线框线段连接点)  这个属性定义了线段的连接点如何显示。可选的值有:
  • round:圆(默认值)
  • bevel:斜角
  • miter:尖角
 如果在一个使用低透明度和 wirefiameLinewidth 值很大的例子里靠近观察,就可以看到这个属性的效果。 WebGLRenderer 对象不支持该属性。
 shading(着色)  该属性定义如何着色。可选的值有:
  • THREE.SmoothShading(默认值,这个将产生一个平滑的对象,看不到单个面)
  • THREE.NoShading
  • THREE.FlatShading
 vertexColors(顶点颜色)  可以通过这个属性给每个顶点定义不同的颜色。默认值为:THREE.NoColors。如果将这个值设置为 THREE.VertexColors,渲染器会采用 THREE.Geometry 对象的 colors 属性的值。
 该属性对 CanvasRenderer不起作用,但对 WebGLRender 起作用。比如我们可以使用该属性为线段的不同部分设置不同的颜色。也可以使用这个属性为这种材质类型创建渐变效果。
 fog(雾化)  该属性指定当前材质是否受全局雾化效果设置的影响。如果将该属性设置为 false,那么我们全局雾化效果设置就不会影响当前对象的渲染。

2,使用样例

这里我们创建一个小方块,使用的材质颜色为紫色且半透明。

原文:Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)

1

2

3

4

5

6

7

8

9

10

var meshMaterial = new THREE.MeshBasicMaterial({

  color: 0x7777ff,

  name: 'material-1',

  opacity: 0.5,

  transparent: true

});

var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);

var cube = new THREE.Mesh(cubeGeometry, meshMaterial);

scene.add(cube);

二、THREE.MeshDepthMaterial(网格深度材质)

使用这种材质的物体,其外观不是由光照或者某个材质属性决定的,而是由物体到摄像机的距离决定的。我们可将这种材质与其他材质结合使用,从而很容易地创建出逐渐消失得效果。

1,属性介绍

除了那些共有属性之外,MeshDepthMaterial 还有如下两个控制线框显示的属性。

 名称 描述
 wireframe(线框)  设置这个属性可以将材质渲染成线框,非常适用于调试。
 wireframeLinewidth(线框线宽)  如果已经打开了 wireframe,这个属性定义线框中线的宽度。

2,样例效果图

下面是一个通过联合材质创建出的新效果(两种材质融合起作用):

  • 我们往场景中添加 20 个自动旋转的方块,位置随机。
  • 这些方块从 THREE.MeshDepthMaterial 对象获得亮度。
  • 并从 THREE.MeshBasicMaterial 对象获得颜色。

原文:Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)

3,样例代码

这里要特别注意如下几个地方:

  • 要把 THREE.MeshBasicMaterial 的 transparent 属性设置为 true,并指定一个融合模式。否则 THREE.js 不会执行任何融合操作,方块始终未纯绿色。
  • 融合模式这里使用的是 THREE.MultiplyBlending,该模式会把前景色和背景色相乘,得到想要的结果。
  • 当 THREE.SceneUtils.createMultiMaterialObject() 方法创建一个网格的时候,几何体会被复制,返回一个网格组(里面两个网格完全相同)。当渲染的物体有一个在别的物体上,并且有一个物体是透明的,那么渲染时会出现画面闪烁问题。这里我们通过缩小带有 THREE.MeshDepthMaterial 材质的网格,就可以避免这种现象。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8">

    <title>hangge.com</title>

    <script type="text/javascript" src="three.min.js"></script>

    <style>

        body {

            margin: 0;

            overflow: hidden;

        }

    </style>

</head>

<body>

<!-- 作为Three.js渲染器输出元素 -->

<div id="WebGL-output">

</div>

<!-- 第一个 Three.js 样例代码 -->

<script type="text/javascript">

    //网页加载完毕后会被调用

    function init() {

        //创建一个场景(场景是一个容器,用于保存、跟踪所要渲染的物体和使用的光源)

        var scene = new THREE.Scene();

        //创建一个摄像机对象

        var camera = new THREE.PerspectiveCamera(45,

          window.innerWidth / window.innerHeight, 10, 130);

        camera.position.x = -30;

        camera.position.y = -40;

        camera.position.z = 30;

        camera.near = 0.1;

        camera.far = 139; //最远看到139

        camera.lookAt(scene.position);

        //创建一个WebGL渲染器并设置其大小

        var renderer = new THREE.WebGLRenderer();

        renderer.setClearColor(new THREE.Color(0x00000)); //0xc0c0c0

        renderer.setSize(window.innerWidth, window.innerHeight);

        //将渲染的结果输出到指定页面元素中

        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        //方块使用的Geometry对象

        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);

        //方块使用的网格深度材质

        var cubeMaterial = new THREE.MeshDepthMaterial();

        //方块使用的网格基础材质

        var colorMaterial = new THREE.MeshBasicMaterial({

            color: 0x00ff00,

            transparent: true,

            blending: THREE.MultiplyBlending

        });

        //创建20个方块对象并添加到舞台中

        for(var i=0; i<20; i++) {

          var cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry,

            [colorMaterial, cubeMaterial]);

          //缩小带有THREE.MeshDepthMaterial材质的网格,避免闪烁问题。

          cube.children[1].scale.set(0.99, 0.99, 0.99);

          cube.castShadow = true;

          //方块位置随机

          cube.position.x = Math.round((Math.random() * 60));

          cube.position.y = Math.round((Math.random() * 60));

          cube.position.z = Math.round((Math.random() * -60));

          //将方块添加到舞台中

          scene.add(cube);

        }

        //渲染场景

        render();

        function render() {

            //方块自动旋转

            scene.traverse(function (e) {

                if (e instanceof THREE.Mesh) {

                    e.rotation.x += 0.02;

                    e.rotation.y += 0.02;

                    e.rotation.z += 0.02;

                }

            });

            requestAnimationFrame(render);

            renderer.render(scene, camera);

        }

    }

    //确保init方法在网页加载完毕后被调用

    window.onload = init;

</script>

</body>

</html>

三、THREE.MeshNormalMaterial(网格法向量材质)

使用这种材质,每一面的颜色是由从该面向外指的法向量计算得到的。

1,属性介绍

除了那些共有属性之外,MeshNormalMaterial 还有如下属性。

 名称 描述
 wireframe(线框)  设置这个属性可以将材质渲染成线框,非常适用于调试。
 wireframeLinewidth(线框线宽)  如果已经打开了 wireframe,这个属性定义线框中线的宽度。
 shading(着色方法)  THREE.FlatShading:平面着色
 THREE.SmoothShading:平滑着色

2,使用样例

(1)效果图

  • 下面是一个使用 MeshNormalMaterial 材质的球体。左右两侧的 shading(着色方法)分别为 THREE.FlatShading 和 THREE.SmoothShading。
  • 法向量所指的方向决定了在使用 MeshNormalMaterial 材质时,每个面获取的颜色。由于球体各个面的法向量都不相同,所以我们看到的是一个色彩斑斓的球体。
  • 而且即使在球体旋转时,这些颜色也基本保持在原来的位置(不会跟着面的移动而移动)。

原文:Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)

(2)样例代码

1

2

3

4

5

6

7

//网格法向材质

var meshMaterial = new THREE.MeshNormalMaterial();

meshMaterial.shading = THREE.FlatShading;

var sphereGeometry = new THREE.SphereGeometry(14, 20, 20);

var sphere = new THREE.Mesh(sphereGeometry, meshMaterial);

scene.add(sphere);

3,使用 THREE.ArrowHelper 添加箭头

法向量是指与面垂直的向量。法向量在 Three.js 库中有很广泛的应用。它可以用来决定光的反射,有助于将纹理映射到三维模型,并提供有关如何计算光照、阴影和为表面像素着色的信息。
为了便于观察,这里我们遍历 THREE.SphereGeometry 的所有面。对于每个 THREE.Face3 对象来说,我们把构成该面的顶点相加再除以 3 来计算中心(质心)。使用这个质心连同该面的法向量来绘制箭头(THREE.ArrowHelper)。

原文:Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

//遍历球体的每一个面

for (var f = 0, fl = sphere.geometry.faces.length; f < fl; f++) {

    var face = sphere.geometry.faces[f];

    //计算每个面的中心(质心)

    var centroid = new THREE.Vector3(0, 0, 0);

    centroid.add(sphere.geometry.vertices[face.a]);

    centroid.add(sphere.geometry.vertices[face.b]);

    centroid.add(sphere.geometry.vertices[face.c]);

    centroid.divideScalar(3);

    //使用质心与该面的法向量绘制箭头

    var arrow = new THREE.ArrowHelper(

            face.normal,

            centroid,

            2,

            0x3333FF,

            0.5,

            0.5);

    sphere.add(arrow);

}

四、THREE.MeshFaceMaterial(网格面材质)

THREE.MeshFaceMaterial 并不是一种真正的材质,而更像是一种材质容器。它允许给几何体的每个面指定不同的材质。
 

1,效果图

我们使用 MeshFaceMaterial 给方块的每个面指定一种不同颜色的材质。

原文:Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)

2,样例代码

1

2

3

4

5

6

7

8

9

10

11

12

13

//网格面材质

var mats = [];

mats.push(new THREE.MeshBasicMaterial({color: 0x009e60}));

mats.push(new THREE.MeshBasicMaterial({color: 0x0051ba}));

mats.push(new THREE.MeshBasicMaterial({color: 0xffd500}));

mats.push(new THREE.MeshBasicMaterial({color: 0xff5800}));

mats.push(new THREE.MeshBasicMaterial({color: 0xC41E3A}));

mats.push(new THREE.MeshBasicMaterial({color: 0xffffff}));

var faceMaterial = new THREE.MeshFaceMaterial(mats);

var cubeGeom = new THREE.BoxGeometry(6, 6, 6);

var cube = new THREE.Mesh(cubeGeom, faceMaterial);

scene.add(cube);

Three.js - 材质的使用详解3(网格Lambert、Phong、着色器材质)

一、THREE.MeshLambertMaterial(网格 Lambert 材质)

这种材质可以用来创建暗淡的并不光亮的表面。该材质非常易用,而且会与场景中的光源产生反应。

1,属性介绍

(1)它拥有材质基类 THREE.Material 定义的的所有属性(点击查看)。

(2)同时也有 color、wireframe、 wireframeLinewidth、wireframeLinecap、wireframeLinejoin、shadingv、vertexColors、fog 这些 THREE.MeshBasicMaterial 定义的所有属性(点击查看

(3)该材质还有如下独有的属性:

 名称 描述
 ambient(环境色)  这是材质的环境色。它跟前面讲过的环境光源一起使用。这个颜色会与环境光提供的颜色相乘。默认值为白色。
 emissive(发射的)  这是该材质发射的颜色。它其实并不像一个光源,只是一种纯粹的、不受其他光照影响的颜色。默认值为黑色。
 wrapAround  如果这个属性设置为 true,则启动半 lambert 光照技术。有了它,光下降得更微妙。如果网格有粗糙、黑暗的地区,启用此属性阴影将变得柔和并且分布更加均匀。
 wrapRGB  当 wrapAround 属性设置为 true 时,可以使用 THREE.Vector3 来控制光下降的速度。

2,使用样例

这里我们在舞台上添加一个聚光灯,并使用该材质创建一个小球。可以看到这个材质看上去比较暗淡。

原文:Three.js - 材质的使用详解3(网格Lambert、Phong、着色器材质)

1

2

3

4

5

6

7

8

9

10

11

//添加一个聚光灯

var spotLight = new THREE.SpotLight(0xffffff);

spotLight.position.set(-30, 60, 60);

spotLight.castShadow = true;

scene.add(spotLight);

//使用网格Lambert材质

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

var sphereGeometry = new THREE.SphereGeometry(14, 20, 20);

var sphere = new THREE.Mesh(sphereGeometry, meshMaterial);

scene.add(sphere);

二、THREE.MeshPhongMaterial(网格 Phong 材质)

通过 THREE.MeshPhongMaterial 可以创建一种光亮的材质。

1,属性介绍

(1)它拥有材质基类 THREE.Material 定义的的所有属性(点击查看)。

(2)同时也有 color、wireframe、wireframeLinewidth、wireframeLinecap、wireframeLinejoin、shadingv、vertexColors、fog 这些 THREE.MeshBasicMaterial 定义的所有属性(点击查看

(3)该材质还有如下独有的属性:

 名称 描述
 ambient(环境色)  这是材质的环境色。它跟前面讲过的环境光源一起使用。这个颜色会与环境光提供的颜色相乘。默认值为白色。
 emissive(发射的)  这是该材质发射的颜色。它其实并不像一个光源,只是一种纯粹的、不受其他光照影响的颜色。默认值为黑色。
 specular  该属性指定该材质的光亮程度及高光部分的颜色。
  • 如果将它设置成与 color 属性相同的颜色,将会得到一个更加类似金属的材质。
  • 如果将它设置成灰色(grey),材质将变得更像塑料。 。
 shininess  该属性指定镜面高光部分的亮度。默认值:30
 metal  如果此属性设置为 true,Three.js 会使用稍微不同的方式计算像素的颜色,以使物体看起来更像金属。要注意的是,这个效果非常小。
 wrapAround  如果这个属性设置为 true,则启动半 lambert 光照技术。有了它,光下降得更微妙。如果网格有粗糙、黑暗的地区,启用此属性阴影将变得柔和并且分布更加均匀。
 wrapRGB  当 wrapAround 属性设置为 true 时,可以使用 THREE.Vector3 来控制光下降的速度。

2,使用样例

这里我们在舞台上添加一个聚光灯,并使用该材质创建一个小球。可以看到这个材质看上去比较光亮。

原文:Three.js - 材质的使用详解3(网格Lambert、Phong、着色器材质)

1

2

3

4

5

6

7

8

9

10

11

//添加一个聚光灯

var spotLight = new THREE.SpotLight(0xffffff);

spotLight.position.set(-30, 60, 60);

spotLight.castShadow = true;

scene.add(spotLight);

//使用网格Phong材质

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

var sphereGeometry = new THREE.SphereGeometry(14, 20, 20);

var sphere = new THREE.Mesh(sphereGeometry, meshMaterial);

scene.add(sphere);

三、THREE.ShaderMaterial(着色器材质)

1,功能特点

  • THREE.ShaderMaterial 是 Three.js 库中最通用、最复杂的材质之一。通过它,可以使用自己定制的着色器,直接在 WebGL 环境中运行。
  • 着色器可以将 Three.js 中的 JavaScript 网格转换为屏幕上的像素。通过这些自定义的着色器,可以明确地指定对象如何渲染,以及如何覆盖或修改 Three.js 库中的默认值。

2,属性介绍

(1)它拥有材质基类 THREE.Material 定义的的所有属性(点击查看)。

(2)该材质还有如下独有的属性:

 名称 描述
 wireframe  设置这个属性可以将材质渲染成线框。非常适合调试目的。
 wireframeLinewidth  如果已经打开了 wireframe,这个属性定义线框中线的宽度。
 linewidth  该属性定义了要绘制的线的宽度。
 shading  该属性定义如何着色。可选的值有 THREE.SmoothShading 和 THREE.Flat Shading。
 vertexColors  可以通过这个属性给每个顶点定义不同的颜色。该属性对 CanvasRenderer 不起作用,但是对 WebGLRenderer 起作用。
 fog  该属性指定当前材质是否受全局雾化效果设置的影响。
 fragmentShader  这个着色器定义的是每个传入的像素的颜色。你需要传入像素着色器程序的字符串值。
 vertexShader  这个着色器允许你修改每一个传入的顶点的位置。你需要传入顶点着色器程序的字符串值。
 uniforms  通过这个属性可以向你的着色器发信息。同样的信息会发给每一个顶点和片段。
 defines  转换成 #define 代码片段。这些片段可以用来设置着色器程序里的一些额外的全局变量。
 attributes  该属性可以修改每个顶点和片段。通常用来传递位置数据和与法向量相关的数据。如果要用这个属性,那么你需要为几何体中的每个顶点提供信息。
 lights  该属性定义光照数据是否传递给着色器。默认值:false。

3,使用样例

(1)下面在场景中添加一个不断旋转的方块,该方块使用的是着色器材质,可以看到方块的颜色会不断地过渡变化。

原文:Three.js - 材质的使用详解3(网格Lambert、Phong、着色器材质)

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

  • vertexShader:它会在几何体的每一个顶点上执行。可以用这个着色器通过改变顶点的位置来对几何体进行变换。本样例我们不调整顶点位置,所以这个方块的形状是不变的。
  • fragmentShader:它会在几何体的每一个片段上执行。我们会返回这个特定片段应该显示的颜色。本样例我们根据传入的外部值,不断地计算并返回颜色。

关于着色器:
着色器不是用 JavaScript 编写的。需要使用类似 C 的 GLSL 语言(WebGL 支持 OpenGL ES 着色语言 1.0 一更多关于 GLSL 的信息,参考 https://www.khronos.org/webgl/)来写着色器。

(3)还要注意的是 uniforms 变量。我们通过这个变量从渲染器向着色器传递信息。本样例中渲染循环(render)每执行一次,其中 time 变量就会增加 0.1。这个信息就会传递给 vertexShader、fragmentShader,分别样例计算方块顶点的新位置(这个本样例没有),以及颜色。

(4)下面是完整代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8">

    <title>hangge.com</title>

     <script type="text/javascript" src="three.min.js"></script>

    <style>

        body {

            margin: 0;

            overflow: hidden;

        }

    </style>

</head>

<body>

<!-- 作为Three.js渲染器输出元素 -->

<div id="WebGL-output">

</div>

<script id="vertexShader" type="x-shader/x-vertex">

    varying vec2 vUv;

    void main()

    {

      vUv = uv;

      vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

      //gl_Position是一个特殊变量,用来返回最终的位置

      gl_Position = projectionMatrix * mvPosition;

    }

</script>

<script id="fragmentShader" type="x-shader/x-fragment">

    uniform float time;

    uniform vec2 resolution;

    varying vec2 vUv;

    void main( void ) {

      vec2 position = -1.0 + 2.0 * vUv;

      float red = abs( sin( position.x * position.y + time / 5.0 ) );

      float green = abs( sin( position.x * position.y + time / 4.0 ) );

      float blue = abs( sin( position.x * position.y + time / 3.0 ) );

      //gl_FragColor是一个特殊变量,用来返回最终的颜色

      gl_FragColor = vec4( red, green, blue, 1.0 );

    }

</script>

<!-- 第一个 Three.js 样例代码 -->

<script type="text/javascript">

    //网页加载完毕后会被调用

    function init() {

        //创建一个场景(场景是一个容器,用于保存、跟踪所要渲染的物体和使用的光源)

        var scene = new THREE.Scene();

        //创建一个摄像机对象

        var camera = new THREE.PerspectiveCamera(45,

          window.innerWidth / window.innerHeight, 10, 130);

          camera.position.x = 30;

          camera.position.y = 30;

          camera.position.z = 30;

          camera.lookAt(new THREE.Vector3(0, 0, 0));

        //创建一个WebGL渲染器并设置其大小

        var renderer = new THREE.WebGLRenderer();

        renderer.setClearColor(new THREE.Color(0x00000)); //0xc0c0c0

        renderer.setSize(window.innerWidth, window.innerHeight);

        //将渲染的结果输出到指定页面元素中

        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        //创建一个着色器材质

        var material = new THREE.ShaderMaterial({

          uniforms: {

            time: {

                type: "f",

                value: 1.0

            },

            resolution: {

                type: "v2",

                value: new THREE.Vector2()

            }

          },

          vertexShader: document.getElementById( 'vertexShader' ).textContent,

          fragmentShader: document.getElementById( 'fragmentShader' ).textContent

        });

        //使用着色器材质创建一个方块

        var cubeGeometry = new THREE.BoxGeometry(10, 10, 10);

        var cube = new THREE.Mesh(cubeGeometry, material);

        //将方块添加到场景中

        scene.add(cube);

        //供方块旋转使用

        var step = 0;

        //渲染场景

        render();

        function render() {

            cube.rotation.y = step += 0.01;

            cube.rotation.x = step;

            cube.rotation.z = step;

            cube.material.uniforms.time.value += 0.1;

            requestAnimationFrame(render);

            renderer.render(scene, camera);

        }

    }

    //确保init方法在网页加载完毕后被调用

    window.onload = init;

</script>

</body>

</html>

4,着色器资源

我们自己去写一些着色些可能会很困难,好在下面两个网站为我们提供了许多现成的着色器代码,我们只需要直接拿来在自己的对象中使用就可以了。

同时网站还提供一个试验环境,可以在这里创建和分享着色器。

Three.js - 材质的使用详解4(线性几何体材质)

2017-10-24发布:hangge阅读:638

线性几何体材质(LineBasicMaterial、LineDashedMaterial)比较特殊,只能用于一个特别的集合体:THREE.Line(线段)。顾名思义,这个几何体只是一条线,线段由顶点组成,不包含任何面。

一、THREE.LineBasicMaterial(实线)

这是用于线段的基础材质。

1,属性介绍

该材质非常简单,有如下几个属性:

 名称 描述
 color  该属性定义线的颜色。如果指定了 vertexColors。这个属性就会被忽略。
 linewidth  该属性定义线的宽度。
 linecap  这个属性定义了线框模式下顶点间线段的端点如何显示。可选值包括:
  • round:圆(默认值)
  • butt:平
  • square:方
 在实际使用中,这个属性的修改结果很难看出来。WebGLRenderer 对象不支持该属性。
 linejoin  这个属性定义了线段的连结点如何显示。可选值有:
  • round:圆(默认值)
  • bevel:斜角
  • miter:尖角
 如果我们一个使用低透明度和很大 wireframeLinewidth 值的例子里靠近观察,就可以看到这个属性的效果。 WebGLRenderer 对象不支持该属性。
 vertexColors  将这个属性设置成 THREE.VertexColors 值,就可以给每个顶点指定一种颜色。
 fog  该属性指定当前材质是否受全局雾化效果设置的影响。

2,使用样例

这里我们在舞台上显示一条 gosper 曲线,同时对线段的每个顶点都会指定一种颜色。

原文:Three.js - 材质的使用详解4(线性几何体材质)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

//获取gosper曲线的x、y坐标点

var points = gosper(3, 60);

//为每个坐标创建一个顶点,并把它们放在lines属性中

var lines = new THREE.Geometry();

//同时每个坐标还会计算一个颜色值,用来设置colors属性

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

    //这里使用setHSL()方法设置颜色(色调、饱和度、亮度)

    colors[i].setHSL(e.x / 100 + 0.5, (  e.y * 20 ) / 300, 0.8);

    i++;

});

lines.colors = colors;

//创建线段基础材质

var material = new THREE.LineBasicMaterial({

    opacity: 1.0,

    linewidth: 1,

    vertexColors: THREE.VertexColors

});

//通过创建的材质结合几何体即可创建一个 THREE.Line网格。

var line = new THREE.Line(lines, material);

line.position.set(25, -30, -60);

scene.add(line);

附:gosper曲线函数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

//获取gosper曲线的x、y坐标点

function gosper(a, b) {

    var turtle = [0, 0, 0];

    var points = [];

    var count = 0;

    rg(a, b, turtle);

    return points;

    function rt(x) {

        turtle[2] += x;

    }

    function lt(x) {

        turtle[2] -= x;

    }

    function fd(dist) {

        //ctx.beginPath();

        points.push({x: turtle[0], y: turtle[1], z: Math.sin(count) * 5});

        //ctx.moveTo(turtle[0], turtle[1]);

        var dir = turtle[2] * (Math.PI / 180);

        turtle[0] += Math.cos(dir) * dist;

        turtle[1] += Math.sin(dir) * dist;

        points.push({x: turtle[0], y: turtle[1], z: Math.sin(count) * 5});

        //ctx.lineTo(turtle[0], turtle[1]);

        //ctx.stroke();

    }

    function rg(st, ln, turtle) {

        st--;

        ln = ln / 2.6457;

        if (st > 0) {

        //ctx.strokeStyle = '#111';

            rg(st, ln, turtle);

            rt(60);

            gl(st, ln, turtle);

            rt(120);

            gl(st, ln, turtle);

            lt(60);

            rg(st, ln, turtle);

            lt(120);

            rg(st, ln, turtle);

            rg(st, ln, turtle);

            lt(60);

            gl(st, ln, turtle);

            rt(60);

        }

        if (st == 0) {

            fd(ln);

            rt(60);

            fd(ln);

            rt(120);

            fd(ln);

            lt(60);

            fd(ln);

            lt(120);

            fd(ln);

            fd(ln);

            lt(60);

            fd(ln);

            rt(60)

        }

    }

    function gl(st, ln, turtle) {

        st--;

        ln = ln / 2.6457;

        if (st > 0) {

            //ctx.strokeStyle = '#555';

            lt(60);

            rg(st, ln, turtle);

            rt(60);

            gl(st, ln, turtle);

            gl(st, ln, turtle);

            rt(120);

            gl(st, ln, turtle);

            rt(60);

            rg(st, ln, turtle);

            lt(120);

            rg(st, ln, turtle);

            lt(60);

            gl(st, ln, turtle);

        }

        if (st == 0) {

            lt(60);

            fd(ln);

            rt(60);

            fd(ln);

            fd(ln);

            rt(120);

            fd(ln);

            rt(60);

            fd(ln);

            lt(120);

            fd(ln);

            lt(60);

            fd(ln);

        }

    }

}

二、THREE.LineDashedMaterial(虚线)

这种材质与 THREE.LineBasicMaterial 的区别是:可以通过指定虚线和空白间隙的长度来创建出虚线效果。

1,属性介绍

该材质除了拥有 THREE.LineBasicMaterial 全部的属性外,还有如下几个额外的属性,可以用来定义虚线的宽度和虚线之间的间隙的宽度。

 名称 描述
 scale  缩放 dashSize 和 gapSize。
  • 如果 scale 的值小于 1:dashSize 和 gapSize 就会增大。
  • 如果 scale 的值大于 1:dashSize 和 gapSize 就会减小。
 dashSize  虚线段的长度。
 gapSize  虚线间隔的宽度。

2,使用样例

这个材质的用法和上面的 THREE.LineBasicMaterial 基本一样。唯一的区别是必须调用 computeLineDistances() 方法来计算线段顶点之间的距离。如果不这么做,间隔就不会正确地显示。

原文:Three.js - 材质的使用详解4(线性几何体材质)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

//获取gosper曲线的x、y坐标点

var points = gosper(3, 60);

//为每个坐标创建一个顶点,并把它们放在lines属性中

var lines = new THREE.Geometry();

//同时每个坐标还会计算一个颜色值,用来设置colors属性

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

    //这里使用setHSL()方法设置颜色(色调、饱和度、亮度)

    colors[i].setHSL(e.x / 100 + 0.5, (  e.y * 20 ) / 300, 0.8);

    i++;

});

lines.colors = colors;

//使用虚线材质的话,必须调用 computeLineDistances()方法

lines.computeLineDistances();

//创建线段基础材质

var material = new THREE.LineDashedMaterial({

    vertexColors: true,

    color: 0xffffff,

    dashSize: 2,

    gapSize: 2,

    scale: 2

});

//通过创建的材质结合几何体即可创建一个 THREE.Line网格。

var line = new THREE.Line(lines, material);

line.position.set(25, -30, -60);

scene.add(line);

猜你喜欢

转载自blog.csdn.net/jdk137/article/details/88657132