04.ThreeJs开发指南-第四章-材质

第四章 材质

材质种类:
MeshBasicMaterial:为几何体赋予一种简单的颜色,或者显示几何体的线框
MeshDepthMaterial:根据网格到相机的距离,该材质决定如何给网格染色
MeshNormalMaterial:根据物体表面的法向量计算颜色
MeshFaceMaterial:这是一种容器,可以在该容器中为物体的各个表面上设置不同的颜色
MeshLambertMaterial:考虑光照的影响,可以创建颜色暗淡,不光亮的物体
MeshPhongMaterial:考虑光照的影响,可以创建光亮的物体
ShaderMaterial:使用自定义的着色器程序,直接控制顶点的放置方式,以及像素的着色方式。
LineBasicMaterial:可以用于THREE.Line几何体,从而创建着色的直线
LineDashedMaterial:类似与基础材质,但可以创建虚线效果

共有属性:

材质基类:THREE.Material该类列出了所有材质的共有属性

基础属性:
控制物体的透明度、是否可见、如何引用物体(通过ID或者自定义物体名称)

融合属性:
决定物体如何与背景融合

高级属性:
可以控制底层WebGL上下文渲染物体的方法。

ID:标识材质,在创建时赋值。
name
opacity:与transparent属性一起使用,取值范围0-1
transparent:是否透明,为true,则根据opacity渲染物体。
overdraw:如果使用THREE.CanvasRenderer渲染物体的时候,多边形会被渲染的大一点。当用这个渲染器画出的物体有间隙时,这时候将该属性设置为true。
visible
side:决定在物体的哪一个面应用材质。默认THREE.FrontSide。可选值有:THREE.BackSide、THREE.DoubleSide。
needsUpdate:材质一般存储在缓存中,对于材质的某些修改,只有设置该属性为true,Three.js库才会使用新的材质去刷新材质的缓存。

融合属性:

blending:决定物体如何与背景进行融合。默认是:NormalBlending,这种模式只显示材质的上层。
blendsrc:渲染源(物体),默认值是SrcAlphaFactor,即用源的alpha通道进行融合。
blenddst:渲染目标(背景),默认值是OneMinusSrcAlphaFactor,即用1-SrcAlphaFactor作为背景的alpha通道值进行融合
blendingequation:指定如何使用blendsrc和blenddst的值。默认方法是:AddEquation,即将两个颜色值相加。

高级属性:
大多数在内部使用,用来控制WebGL渲染场景的细节。

depthTest:深度测试
depthWrite:
polygonOffset、polygonOffsetFactor、polygonOffsetUnits
alphaTest:alpha测试,设置值的范围0-1,如果某个像素的alpha值小于该属性设置的值,那么该像素就不会被显示出来。

一、MeshBasicMaterial
不考虑光照的影响。

color
wireframe
wireframeLinewidth
wireframeLinecap:线段端点如何显示。可选值有:butt(平)、round、square。默认是round。WebGLRenderer对象不支持该属性。
wireframeLinejoin:线段连接点如何显示。可选值有:round、bevel(斜角)、miter(尖角)。默认是round。WebGLRenderer对象不支持属性。
shading:着色模式。可选值:THREE.SmoothShading、THREE.FlatShading。
vertexColors:为每个顶点定义不同的颜色。在CanvasRenderer对象中不起作用。
fog:指示当前是否会受全局雾化效果设置的影响。

两种设置属性的方式:
1.构造函数

var meshMaterial = new THREE.MeshBasicMaterial({color:0xffccff});

2.属性

meshMaterial.visible = false;

二、MeshDeptMaterial

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

只有两个控制线框的属性:
wireframe
wireframeLinewidth

尽管该材质没有多少属性可以控制物体的渲染效果,但是我们可以控制物体消失的速度。

我们可以通过设置相机的near和far的值,来控制创建中使用这种材质的物体的消失速度。如果near和fat之间的差值越大,那么物体远离相机时,只会稍微消失一点;反之,物体消失的效果非常明显。

三、联合材质

var cubeMaterial = new THREE.MeshDepthMaterial();

var colorMaterial = new THREE.MeshBasicMaterial({color:0x00ff00,transparent:true,blending:THREE.MultiplyBlending});

var cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry,[colorMaterial,cubeMaterial]);

cube.children[1].scale.set(0.99,0.99,0.99);//避免渲染遮挡而造成的闪烁

这些cube可以从MeshDepthMaterial材质中或得渐变效果,可以从MeshBasicMaterial材质中获得颜色。

注意:MeshBasicMaterial材质,如果transparent属性不设置为true,则只会得到一个纯绿色的物体。如果设置为true,则Three.js库就会检查blending属性,来看看这个绿色如何和背景(用MeshDepthMaterial材质渲染的方块)相互作用。

四、MeshNormalMaterial

法向量的作用:
决定光的发射方向、在计算光照、阴影时提供信息、为物体表面上色。

法向量所指的方向决定每个面从MeshNormalMaterial材质获取的颜色。

在平面上添加表示法向量的箭头:使用THREE.ArrowHelper

for(var f = 0 , f1 = sphere.geometry.faces.length; f < f1 ; f++){
    var face = spere.geometry.faces[f];
    var arrow = new THREE.ArrowHelper(face.normal,face.centroid,2,0x3333ff);
    spere.add(arrow);
}

这段代码在球体的每个面上添加了一个长度为2,颜色为0x3333ff的箭头。

属性:
wireframe
wireframeLinewidth
shading

五、MeshFaceMaterial

材质容器。可以为几何体的每一个面指定不同的材质。

假设有一个正方体,可以为每个面指定不同的颜色。

var matArray = [];
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));

var faceMaterial = new THREE.MeshFaceMaterial(matArray);

var cubeGeometry = new THREE.CubeGeometry(3,3,3);
var cube = new THREE.Mesh(cubeGeometry,faceMaterial);

Mesh组的概念:

var group = new THREE.Mesh();

var mats = [];
mats.push(new THREE.MeshBasicMaterial({color: 0x009e60}));
mats.push(new THREE.MeshBasicMaterial({color: 0x009e60}));
mats.push(new THREE.MeshBasicMaterial({color: 0xC41E3A}));
mats.push(new THREE.MeshBasicMaterial({color: 0xC41E3A}));
mats.push(new THREE.MeshBasicMaterial({color: 0xffffff}));
mats.push(new THREE.MeshBasicMaterial({color: 0xffffff}));

var faceMaterial = new THREE.MeshFaceMaterial(mats);

for (var x = 0; x < 3; x++) {
    for (var y = 0; y < 3; y++) {
        for (var z = 0; z < 3; z++) {
            var cubeGeom = new THREE.BoxGeometry(2.9, 2.9, 2.9);
            var cube = new THREE.Mesh(cubeGeom, faceMaterial);

            //将cube定位到(0,0,0)的四周,这样旋转时,整个组围绕(0,0,0)进行旋转。
            cube.position.set(x * 3 - 3, y * 3, z * 3 - 3);

            group.add(cube);
        }
    }
}

// call the render function
scene.add(group);

高级材质:

一、暗淡、不光亮表面的 MeshLambertMaterial

对光源有反应。

基本属性:
color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLineWith、wirefLinecap、wireframeLinejoin、vertexColors、fog。

独特属性:

ambient:和AmbientLight光源一起使用。该颜色会与AmbientLight光源的颜色相乘。默认是白色。
emissive:该材质发射的属性。不像是光源,只是一种纯粹的、不受其他光照影响的颜色。默认是黑色。

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

二、光亮表面的 MeshPhongMaterial

基本属性:
color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLineWith、wirefLinecap、wireframeLinejoin、vertexColors、fog。

独特属性:

ambient
emissive
specular:指定该材质的光亮程度及其高光部分的颜色。如果将他设置成跟color属性相同的颜色,将会得到一种更加类似金属的材质。如果设置为灰色,材质将变得更像塑料。
shininess:指定高光部分的亮度。默认是30.

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

三、ShaderMaterial 创建自己的着色器

创建自己的着色器,直接在WebGL环境中运行。
着色器可以将js对象转换为屏幕上的像素。

属性:
wireframe
wireframeLinewidth
shading
vertexColor
fog:指示当前是否会受全局雾化效果设置的影响。

独特属性:

fragmentShader:定义每个传入的像素的颜色。
vertexShader:允许你修改每一个传入的顶点的位置
uniforms:该属性可以向你的着色器发送消息。将同样的信息发送到每一个顶点和片段。
defines:该属性可以转换为vertexShader和fragmentShader里的#define代码。该属性可以用来设置着色器程序里的一些全局变量。
attributes:该属性可以修改每个顶点和片段。常用来传递位置数据和法向量相关的数据。如果要用这个属性,辣么你要为几何体中的所有顶点提供信息。
lights:定义光照数据是否传递给着色器。默认是false。

要使用ShaderMaterial,必须传入两个着色器:

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

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

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

    uniform float time;

    void main()
    {
        vec3 posChanged = position;
        posChanged.x = posChanged.x * (abs(sin(time*1.0)));
        posChanged.y = posChanged.y * (abs(cos(time*1.0)));
        posChanged.z = posChanged.z * (abs(sin(time*1.0)));


        gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0);
    }

</script>

为了能够在js中着色器通信,我们使用uniform变量。

这里,我们使用uniform float time传入外部数据。根据这个数据,我们会改变传入顶点的x,y,z座标(通过position变量传入)

gl_Position 是glsl内置的变量,用来表示最终要渲染的顶点的位置。

接下来要创建一个shaderMaterial,并传入这个vertexShader。我们定义一个函数:

function createMaterial(vertexShader,fragmentShader){
    var verthader = 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:'f',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;
}

该例子的完整循环如下:

function render(){

    stats.update();

    cube.rotation.y = step += 0.01;
    cube.rotation.x = step;
    cube.rotation.z = step;

    cube.material.materials.forEach(function(e){
        e.uniforms.time.value += 0.01;
    });

    requestAnimationFrame(render);
    renderer.render(scene,camera);
}

该例子中cube的每个面都在发生变化,这就是fragmentShader的作用。

var cubeGeometry = new THREE.CubeGeometry(20,20,20);

var meshMaterial1 = createMaterial("vertex-shader","fragment-shader-1");
var meshMaterial2 = createMaterial("vertex-shader","fragment-shader-2");
var meshMaterial3 = createMaterial("vertex-shader","fragment-shader-3");
var meshMaterial4 = createMaterial("vertex-shader","fragment-shader-4");
var meshMaterial5 = createMaterial("vertex-shader","fragment-shader-5");
var meshMaterial6 = createMaterial("vertex-shader","fragment-shader-6");

var material = new THREE.MeshFaceMaterial([
    meshMaterial1,meshMaterial2,meshMaterial3,meshMaterial4,meshMaterial5,meshMaterial6
]);

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

fragmentShader都是从 http://glsl.heroku.com 中复制过来的。

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

    uniform float time;
    uniform vec2 resolution;

    void main( void )
    {

        vec2 uPos = ( gl_FragCoord.xy / resolution.xy );//normalize wrt y axis
        //suPos -= vec2((resolution.x/resolution.y)/2.0, 0.0);//shift origin to center

        uPos.x -= 1.0;
        uPos.y -= 0.5;

        vec3 color = vec3(0.0);
        float vertColor = 2.0;
        for( float i = 0.0; i < 15.0; ++i )
        {
            float t = time * (0.9);

            uPos.y += sin( uPos.x*i + t+i/2.0 ) * 0.1;
            float fTemp = abs(1.0 / uPos.y / 100.0);
            vertColor += fTemp;
            color += vec3( fTemp*(10.0-i)/10.0, fTemp*i/10.0, pow(fTemp,1.5)*1.5 );
        }

        vec4 color_final = vec4(color, 1.0);
        gl_FragColor = color_final;
    }

</script>

线段几何体的材质:

LineBasicMaterial

基本属性:

color
lineWidth
LineCap:butt、round、square。默认是round。WebGLRenderer不支持该属性。
LineJoin:round、bevel(斜切)、miter(尖角)。默认是round。WebGLRenderer不支持该属性。
vertexColors:该属性值设置为 THREE.VertexColors值时,就可以为每个顶点指定一种颜色。
fog:指定当前物体是否受全局雾化效果的影响。

//获取一组x,y座标,返回一个gosper曲线,这是一种填充二维空间的简单算法。
var points = gosper(4,60);

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);
    i++;
});


lines.colors = colors;

var material = new THREE.LineBasicMaterial({
    opacity:1.0,
    lineWidth:1,
    vertexColors:THREE.VertexColors
});

//线网格
var line = new THREE.Line(lines,material);

LineDashedMaterial

和LineBasicMaterial有着一样的属性,但是有几个额外的属性,可以用来定义短划线长度和短划线中间空格长度的属性。

独特属性:
scale:缩放dashSize和gapSize。如果scale<1,则dashSize和gapSize就会增大。
dashSize:短线划的长度
gapSize:间隔的长度

//要想显示间隔,必须调用此方法
lines.computeLineDistances();
var material = new THREE.LineDashedMaterial({
    vertexColor:true,
    color:0xffffff,
    dashSize:10,
    gapSize:1,
    scale:0.1
});
发布了98 篇原创文章 · 获赞 68 · 访问量 29万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章