Three.js - 材质的使用详解3(网格Lambert、Phong、着色器材质)
作者:hangge | 2017-10-21 08:10
一、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,着色器资源
我们自己去写一些着色些可能会很困难,好在下面两个网站为我们提供了许多现成的着色器代码,我们只需要直接拿来在自己的对象中使用就可以了。
同时网站还提供一个试验环境,可以在这里创建和分享着色器。
全部评论(0)