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,使用样例
这里我们在舞台上添加一个聚光灯,并使用该材质创建一个小球。可以看到这个材质看上去比较暗淡。//添加一个聚光灯 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 | 该属性指定该材质的光亮程度及高光部分的颜色。
|
shininess | 该属性指定镜面高光部分的亮度。默认值:30 |
metal | 如果此属性设置为 true,Three.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/)来写着色器。
着色器不是用 JavaScript 编写的。需要使用类似 C 的 GLSL 语言(WebGL 支持 OpenGL ES 着色语言 1.0 一更多关于 GLSL 的信息,参考 https://www.khronos.org/webgl/)来写着色器。
(3)还要注意的是 uniforms 变量。我们通过这个变量从渲染器向着色器传递信息。本样例中渲染循环(render)每执行一次,其中 time 变量就会增加 0.1。这个信息就会传递给 vertexShader、fragmentShader,分别样例计算方块顶点的新位置(这个本样例没有),以及颜色。
(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,着色器资源
我们自己去写一些着色些可能会很困难,好在下面两个网站为我们提供了许多现成的着色器代码,我们只需要直接拿来在自己的对象中使用就可以了。
同时网站还提供一个试验环境,可以在这里创建和分享着色器。