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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章