当前位置: > > > Three.js - 材质的使用详解3(网格Lambert、Phong、着色器材质)

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

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

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

1,属性介绍

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

(2)同时也有 colorwireframewireframeLinewidthwireframeLinecapwireframeLinejoinshadingvvertexColorsfog 这些 THREE.MeshBasicMaterial 定义的所有属性(点击查看

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

2,使用样例

这里我们在舞台上添加一个聚光灯,并使用该材质创建一个小球。可以看到这个材质看上去比较暗淡。
//添加一个聚光灯
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)同时也有 colorwireframewireframeLinewidthwireframeLinecapwireframeLinejoinshadingvvertexColorsfog 这些 THREE.MeshBasicMaterial 定义的所有属性(点击查看

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

2,使用样例

这里我们在舞台上添加一个聚光灯,并使用该材质创建一个小球。可以看到这个材质看上去比较光亮。
//添加一个聚光灯
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)下面在场景中添加一个不断旋转的方块,该方块使用的是着色器材质,可以看到方块的颜色会不断地过渡变化。

(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。这个信息就会传递给 vertexShaderfragmentShader,分别样例计算方块顶点的新位置(这个本样例没有),以及颜色。

(4)下面是完整代码
<!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,着色器资源

我们自己去写一些着色些可能会很困难,好在下面两个网站为我们提供了许多现成的着色器代码,我们只需要直接拿来在自己的对象中使用就可以了。
同时网站还提供一个试验环境,可以在这里创建和分享着色器。
评论0