three.js 源碼注釋(四十五)Material /Material .js


商域無疆 (http://blog.csdn.net/omni360/)

本文遵循“署名-非商業用途-保持一致”創作公用協議

轉載請保留此句:商域無疆 -  本博客專注於 敏捷開發及移動和物聯設備研究:數據可視化、GOLANG、Html5、WEBGL、THREE.JS否則,出自本博客的文章拒絕轉載或再轉載,謝謝合作。


俺也是剛開始學,好多地兒肯定不對還請見諒.

以下代碼是THREE.JS 源碼文件中Material/Material .js文件的注釋.

更多更新在 : https://github.com/omni360/three.js.sourcecode


/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */
/*
///Material是材質對象的抽象基類,當創建材質時都從這個類繼承.Material對象的功能函數采用定義構造的函數原型對象來實現.
/// 簡單的說就是物體看起來是什么質地。材質可以看成是材料和質感的結合。在渲染程式中,它是表面各可視屬性的結合,
/// 這些可視屬性是指表面的色彩、紋理、光滑度、透明度、反射率、折射率、發光度等。
///
*/
///<summary>Material</summary>
THREE.Material = function () {

	this.id = THREE.MaterialIdCount ++;		//材質屬性id
	this.uuid = THREE.Math.generateUUID();	//材質uuid(通用唯一標識碼)屬性

	this.name = '';		//材質名稱屬性,可有可無

	this.side = THREE.FrontSide;	//模型正面只附着材質,還有選項THREE.BackSide 材質只附着背面 ,和選項THREE.DoubleSide = 2;	模型雙面都附着材質

	this.opacity = 1;		//屬性opacity為一個0-1區間的值,表明透明度。屬性transparent指定是否使用透明,只有在該值為真的時候,才會將其與混合(透明是渲染像素時,待渲染值與已存在值共同作用計算出渲染后像素值,達到混合的效果)。
	this.transparent = false;	//是否使用透明.

	//屬性blending,blendSrc,blendDst,blendEquation指定了混合方式和混合源Src和混合像素已有的像元值Dst的權重指定方式。默認情況下(如構造函數中賦的缺省值),新的像元值等於:新值×alpha+舊值×(1-alpha)。
	this.blending = THREE.NormalBlending;	//材質混合混合模式類型
	//材質混合混合模式類型,有相加,相減,相乘,自定義等將不同的材質,顏色混合的方式
	//TODO:有時間可以自定義幾種混合模式試試.實現一些特殊的效果.

	//參考:http://blog.csdn.net/tudoumayi/article/details/6489575
	//參考:https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.13
	//參考:https://www.opengl.org/registry/specs/EXT/blend_color.txt
	//參考:http://blog.sina.com.cn/s/blog_9f4bc8e301014m6c.html
	//參考:https://www.opengl.org/registry/specs/EXT/blend_color.txt
	//參考:https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBlendFuncSeparate.xml
	/*************************************摘抄自王路傑滴博客,http://blog.sina.com.cn/s/blog_9f4bc8e301014m6c.html***********

	混合是什么呢?混合就是把兩種顏色混在一起。具體一點,就是把某一像素位置原來的顏色和將要畫上去的顏色,通過某種方式混在一起,從而實現特殊的效果。
	假設我們需要繪制這樣一個場景:透過紅色的玻璃去看綠色的物體,那么可以先繪制綠色的物體,再繪制紅色玻璃。在繪制紅色玻璃的時候,利用“混合”功能,
	把將要繪制上去的紅色和原來的綠色進行混合,於是得到一種新的顏色,看上去就好像玻璃是半透明的。
	要使用OpenGL的混合功能,只需要調用:glEnable(GL_BLEND);即可。
	要關閉OpenGL的混合功能,只需要調用:glDisable(GL_BLEND);即可。
	注意:只有在RGBA模式下,才可以使用混合功能,顏色索引模式下是無法使用混合功能的。
	一、源因子和目標因子
	前面我們已經提到,混合需要把原來的顏色和將要畫上去的顏色找出來,經過某種方式處理后得到一種新的顏色。
	這里把將要畫上去的顏色稱為“源顏色”,把原來的顏色稱為“目標顏色”。
	OpenGL 會把源顏色和目標顏色各自取出,並乘以一個系數(源顏色乘以的系數稱為“源因子”,目標顏色乘以的系數稱為“目標因子”),然后相加,這樣就得到了新的顏色。
	(也可以不是相加,新版本的OpenGL可以設置運算方式,包括加、減、取兩者中較大的、取兩者中較小的、邏輯運算等,但我們這里為了簡單起見,不討論這個了)
	下面用數學公式來表達一下這個運算方式。假設源顏色的四個分量(指紅色,綠色,藍色,alpha值)是(Rs, Gs, Bs,  As),目標顏色的四個分量是(Rd, Gd, Bd, Ad),
	又設源因子為(Sr, Sg, Sb, Sa),目標因子為(Dr, Dg, Db,  Da)。則混合產生的新顏色可以表示為:
	(Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da)
	當然了,如果顏色的某一分量超過了1.0,則它會被自動截取為1.0,不需要考慮越界的問題。

	源因子和目標因子是可以通過glBlendFunc函數來進行設置的。glBlendFunc有兩個參數,前者表示源因子,后者表示目標因子。這兩個參數可以是多種值,下面介紹比較常用的幾種。
	GL_ZERO:     表示使用0.0作為因子,實際上相當於不使用這種顏色參與混合運算。
	GL_ONE:      表示使用1.0作為因子,實際上相當於完全的使用了這種顏色參與混合運算。
	GL_SRC_ALPHA:表示使用源顏色的alpha值來作為因子。
	GL_DST_ALPHA:表示使用目標顏色的alpha值來作為因子。
	GL_ONE_MINUS_SRC_ALPHA:表示用1.0減去源顏色的alpha值來作為因子。
	GL_ONE_MINUS_DST_ALPHA:表示用1.0減去目標顏色的alpha值來作為因子。
	除 此以外,還有GL_SRC_COLOR(把源顏色的四個分量分別作為因子的四個分量)、GL_ONE_MINUS_SRC_COLOR、 GL_DST_COLOR、GL_ONE_MINUS_DST_COLOR等,前兩個在OpenGL舊版本中只能用於設置目標因子,
	后兩個在OpenGL 舊版本中只能用於設置源因子。新版本的OpenGL則沒有這個限制,並且支持新的GL_CONST_COLOR(設定一種常數顏色,將其四個分量分別作為因子的四個分量)、GL_ONE_MINUS_CONST_COLOR、GL_CONST_ALPHA、
	 GL_ONE_MINUS_CONST_ALPHA。另外還有GL_SRC_ALPHA_SATURATE。新版本的OpenGL還允許顏色的alpha 值和RGB值采用不同的混合因子。但這些都不是我們現在所需要了解的。畢竟這還是入門教材,不需要整得太復雜~

	舉例來說:
	如果設置了glBlendFunc(GL_ONE, GL_ZERO);,則表示完全使用源顏色,完全不使用目標顏色,因此畫面效果和不使用混合的時候一致(當然效率可能會低一點點)。如果沒有設置源因子和目標因子,則默認情況就是這樣的設置。
	如果設置了glBlendFunc(GL_ZERO, GL_ONE);,則表示完全不使用源顏色,因此無論你想畫什么,最后都不會被畫上去了。(但這並不是說這樣設置就沒有用,有些時候可能有特殊用途)
	如果設置了glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);,則表示源顏色乘以自身的alpha 值,目標顏色乘以1.0減去源顏色的alpha值,這樣一來,源顏色的alpha值越大,則產生的新顏色中源顏色所占比例就越大,
	                                                                而目標顏色所占比例則減小。這種情況下,我們可以簡單的將源顏色的alpha值理解為“不透明度”。這也是混合時最常用的方式。
	如果設置了glBlendFunc(GL_ONE, GL_ONE);,則表示完全使用源顏色和目標顏色,最終的顏色實際上就是兩種顏色的簡單相加。例如紅色(1, 0, 0)和綠色(0, 1, 0)相加得到(1, 1, 0),結果為黃色。
	注意:
	        所謂源顏色和目標顏色,是跟繪制的順序有關的。假如先繪制了一個紅色的物體,再在其上繪制綠色的物體。則綠色是源顏色,紅色是目標顏色。如果順序反過來,則紅色就是源顏色,綠色才是目標顏色。
	        在繪制時,應該注意順序,使得繪制的源顏色與設置的源因子對應,目標顏色與設置的目標因子對應。不要被混亂的順序搞暈了。
	 
	一、源因子和目標因子
	前面我們已經提到,混合需要把原來的顏色和將要畫上去的顏色找出來,經過某種方式處理后得到一種新的顏色。這里把將要畫上去的顏色稱為“源顏色”,把原來的顏色稱為“目標顏色”。
	OpenGL 會把源顏色和目標顏色各自取出,並乘以一個系數(源顏色乘以的系數稱為“源因子”,目標顏色乘以的系數稱為“目標因子”),然后相加,這樣就得到了新的顏色。(也可以不是相加,
	新版本的OpenGL可以設置運算方式,包括加、減、取兩者中較大的、取兩者中較小的、邏輯運算等,但我們這里為了簡單起見,不討論這個了)
	下面用數學公式來表達一下這個運算方式。假設源顏色的四個分量(指紅色,綠色,藍色,alpha值)是(Rs, Gs, Bs,  As),目標顏色的四個分量是(Rd, Gd, Bd, Ad),又設源因子為(Sr, Sg, Sb, Sa),
	目標因子為(Dr, Dg, Db,  Da)。則混合產生的新顏色可以表示為:
	        (Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da)
	當然了,如果顏色的某一分量超過了1.0,則它會被自動截取為1.0,不需要考慮越界的問題。

	源因子和目標因子是可以通過glBlendFunc函數來進行設置的。glBlendFunc有兩個參數,前者表示源因子,后者表示目標因子。這兩個參數可以是多種值,下面介紹比較常用的幾種。
	GL_ZERO:     表示使用0.0作為因子,實際上相當於不使用這種顏色參與混合運算。
	GL_ONE:      表示使用1.0作為因子,實際上相當於完全的使用了這種顏色參與混合運算。
	GL_SRC_ALPHA:表示使用源顏色的alpha值來作為因子。
	GL_DST_ALPHA:表示使用目標顏色的alpha值來作為因子。
	GL_ONE_MINUS_SRC_ALPHA:表示用1.0減去源顏色的alpha值來作為因子。
	GL_ONE_MINUS_DST_ALPHA:表示用1.0減去目標顏色的alpha值來作為因子。
	除 此以外,還有GL_SRC_COLOR(把源顏色的四個分量分別作為因子的四個分量)、GL_ONE_MINUS_SRC_COLOR、 GL_DST_COLOR、GL_ONE_MINUS_DST_COLOR等,前兩個在OpenGL舊版本中只能用於設置目標因子,
	后兩個在OpenGL 舊版本中只能用於設置源因子。新版本的OpenGL則沒有這個限制,並且支持新的GL_CONST_COLOR(設定一種常數顏色,將其四個分量分別作為因子的四個分量)、GL_ONE_MINUS_CONST_COLOR、
	GL_CONST_ALPHA、 GL_ONE_MINUS_CONST_ALPHA。另外還有GL_SRC_ALPHA_SATURATE。新版本的OpenGL還允許顏色的alpha 值和RGB值采用不同的混合因子。但這些都不是我們現在所需要了解的。畢竟這還是入門教材,不需要整得太復雜~

	舉例來說:
	如果設置了glBlendFunc(GL_ONE, GL_ZERO);,則表示完全使用源顏色,完全不使用目標顏色,因此畫面效果和不使用混合的時候一致(當然效率可能會低一點點)。如果沒有設置源因子和目標因子,則默認情況就是這樣的設置。
	如果設置了glBlendFunc(GL_ZERO, GL_ONE);,則表示完全不使用源顏色,因此無論你想畫什么,最后都不會被畫上去了。(但這並不是說這樣設置就沒有用,有些時候可能有特殊用途)
	如果設置了glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);,則表示源顏色乘以自身的alpha 值,目標顏色乘以1.0減去源顏色的alpha值,這樣一來,源顏色的alpha值越大,則產生的新顏色中源顏色所占比例就越大,而目標顏色所占比例則減小。
	這種情況下,我們可以簡單的將源顏色的alpha值理解為“不透明度”。這也是混合時最常用的方式。
	如果設置了glBlendFunc(GL_ONE, GL_ONE);,則表示完全使用源顏色和目標顏色,最終的顏色實際上就是兩種顏色的簡單相加。例如紅色(1, 0, 0)和綠色(0, 1, 0)相加得到(1, 1, 0),結果為黃色。
	注意:
	所謂源顏色和目標顏色,是跟繪制的順序有關的。假如先繪制了一個紅色的物體,再在其上繪制綠色的物體。則綠色是源顏色,紅色是目標顏色。如果順序反過來,則紅色就是源顏色,綠色才是目標顏色。
	在繪制時,應該注意順序,使得繪制的源顏色與設置的源因子對應,目標顏色與設置的目標因子對應。不要被混亂的順序搞暈了。

	三、實現三維混合
	也許你迫不及待的想要繪制一個三維的帶有半透明物體的場景了。但是現在恐怕還不行,還有一點是在進行三維場景的混合時必須注意的,那就是深度緩沖。
	深度緩沖是這樣一段數據,它記錄了每一個像素距離觀察者有多近。在啟用深度緩沖測試的情況下,如果將要繪制的像素比原來的像素更近,則像素將被繪制。否則,像素就會被忽略掉,不進行繪制。
	這在繪制不透明的物體時非常有用——不管是先繪制近的物體再繪制遠的物體,還是先繪制遠的物體再繪制近的物體,或者干脆以混亂的順序進行繪制,最后的顯示結果總是近的物體遮住遠的物體。
	然而在你需要實現半透明效果時,發現一切都不是那么美好了。如果你繪制了一個近距離的半透明物體,則它在深度緩沖區內保留了一些信息,使得遠處的物體將無法再被繪制出來。雖然半透明的物體仍然半透明,但透過它看到的卻不是正確的內容了。
	要解決以上問題,需要在繪制半透明物體時將深度緩沖區設置為只讀,這樣一來,雖然半透明物體被繪制上去了,深度緩沖區還保持在原來的狀態。如果再有一個物體出現在半透明物體之后,在不透明物體之前,
	則它也可以被繪制(因為此時深度緩沖區中記錄的是那個不透明物體的深度)。以后再要繪制不透明物體時,只需要再將深度緩沖區設置為可讀可寫的形式即可。嗯?你問我怎么繪制一個一部分半透明一部分不透明的物體?這個好辦,
	只需要把物體分為兩個部分,一部分全是半透明的,一部分全是不透明的,分別繪制就可以了。
	即使使用了以上技巧,我們仍然不能隨心所欲的按照混亂順序來進行繪制。必須是先繪制不透明的物體,然后繪制透明的物體。否則,假設背景為藍色,近處一塊紅色玻璃,中間一個綠色物體。
	如果先繪制紅色半透明玻璃的話,它先和藍色背景進行混合,則以后繪制中間的綠色物體時,想單獨與紅色玻璃混合已經不能實現了。
	總結起來,繪制順序就是:首先繪制所有不透明的物體。如果兩個物體都是不透明的,則誰先誰后都沒有關系。然后,將深度緩沖區設置為只讀。接下來,繪制所有半透明的物體。
	如果兩個物體都是半透明的,則誰先誰后只需要根據自己的意願(注意了,先繪制的將成為“目標顏色”,后繪制的將成為“源顏色”,所以繪制的順序將會對結果造成一些影響)。最后,將深度緩沖區設置為可讀可寫形式。
	調用glDepthMask(GL_FALSE);可將深度緩沖區設置為只讀形式。調用glDepthMask(GL_TRUE);可將深度緩沖區設置為可讀可寫形式。
	一些網上的教程,包括大名鼎鼎的NeHe教程,都在使用三維混合時直接將深度緩沖區禁用,即調用glDisable(GL_DEPTH_TEST);。這樣做並不正確。如果先繪制一個不透明的物體,再在其背后繪制半透明物體,
	本來后面的半透明物體將不會被顯示(被不透明的物體遮住了),但如果禁用深度緩沖,則它仍然將會顯示,並進行混合。NeHe提到某些顯卡在使用glDepthMask函數時可能存在一些問題,但可能是由於我的閱歷有限,並沒有發現這樣的情況。

	那么,實際的演示一下吧。我們來繪制一些半透明和不透明的球體。假設有三個球體,一個紅色不透明的,一個綠色半透明的,一個藍色半透明的。紅色最遠,綠色在中間,藍色最近。根據前面所講述的內容,紅色不透明球體必須首先繪制,
	而綠色和藍色則可以隨意修改順序。這里為了演示不注意設置深度緩沖的危害,我們故意先繪制最近的藍色球體,再繪制綠色球體。
	為了讓這些球體有一點立體感,我們使用光照。在(1, 1, -1)處設置一個白色的光源。代碼如下:
	void setLight(void)
	{
	    static const GLfloat light_position[] = {1.0f, 1.0f, -1.0f, 1.0f};
	    static const GLfloat light_ambient[]  = {0.2f, 0.2f, 0.2f, 1.0f};
	    static const GLfloat light_diffuse[]  = {1.0f, 1.0f, 1.0f, 1.0f};
	    static const GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};

	    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
	    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
	    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

	    glEnable(GL_LIGHT0);
	    glEnable(GL_LIGHTING);
	    glEnable(GL_DEPTH_TEST);
	}
	每一個球體顏色不同。所以它們的材質也都不同。這里用一個函數來設置材質。
	void setMatirial(const GLfloat mat_diffuse[4], GLfloat mat_shininess)
	{
	    static const GLfloat mat_specular[] = {0.0f, 0.0f, 0.0f, 1.0f};
	    static const GLfloat mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};

	    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_diffuse);
	    glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
	    glMaterialfv(GL_FRONT, GL_EMISSION,  mat_emission);
	    glMaterialf (GL_FRONT, GL_SHININESS, mat_shininess);
	}
	有了這兩個函數,我們就可以根據前面的知識寫出整個程序代碼了。這里只給出了繪制的部分,其它部分大家可以自行完成。
	void myDisplay(void)
	{
	    // 定義一些材質顏色
	    const static GLfloat red_color[] = {1.0f, 0.0f, 0.0f, 1.0f};
	    const static GLfloat green_color[] = {0.0f, 1.0f, 0.0f, 0.3333f};
	    const static GLfloat blue_color[] = {0.0f, 0.0f, 1.0f, 0.5f};

	    // 清除屏幕
	    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	    // 啟動混合並設置混合因子
	    glEnable(GL_BLEND);
	    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	    // 設置光源
	    setLight();

	    // 以(0, 0, 0.5)為中心,繪制一個半徑為.3的不透明紅色球體(離觀察者最遠)
	    setMatirial(red_color, 30.0);
	    glPushMatrix();
	    glTranslatef(0.0f, 0.0f, 0.5f);
	    glutSolidSphere(0.3, 30, 30);
	    glPopMatrix();

	    // 下面將繪制半透明物體了,因此將深度緩沖設置為只讀
	    glDepthMask(GL_FALSE);

	    // 以(0.2, 0, -0.5)為中心,繪制一個半徑為.2的半透明藍色球體(離觀察者最近)
	    setMatirial(blue_color, 30.0);
	    glPushMatrix();
	    glTranslatef(0.2f, 0.0f, -0.5f);
	    glutSolidSphere(0.2, 30, 30);
	    glPopMatrix();

	    // 以(0.1, 0, 0)為中心,繪制一個半徑為.15的半透明綠色球體(在前兩個球體之間)
	    setMatirial(green_color, 30.0);
	    glPushMatrix();
	    glTranslatef(0.1, 0, 0);
	    glutSolidSphere(0.15, 30, 30);
	    glPopMatrix();

	    // 完成半透明物體的繪制,將深度緩沖區恢復為可讀可寫的形式
	    glDepthMask(GL_TRUE);

	    glutSwapBuffers();
	}

	大家也可以將上面兩處glDepthMask刪去,結果會看到最近的藍色球雖然是半透明的,但它的背后直接就是紅色球了,中間的綠色球沒有被正確繪制。

	小結:
	本課介紹了OpenGL混合功能的相關知識。
	混合就是在繪制時,不是直接把新的顏色覆蓋在原來舊的顏色上,而是將新的顏色與舊的顏色經過一定的運算,從而產生新的顏色。新的顏色稱為源顏色,原來舊的顏色稱為目標顏色。傳統意義上的混合,
	是將源顏色乘以源因子,目標顏色乘以目標因子,然后相加。
	源因子和目標因子是可以設置的。源因子和目標因子設置的不同直接導致混合結果的不同。將源顏色的alpha值作為源因子,用1.0減去源顏色alpha值作為目標因子,是一種常用的方式。
	這時候,源顏色的alpha值相當於“不透明度”的作用。利用這一特點可以繪制出一些半透明的物體。
	在進行混合時,繪制的順序十分重要。因為在繪制時,正要繪制上去的是源顏色,原來存在的是目標顏色,因此先繪制的物體就成為目標顏色,后來繪制的則成為源顏色。繪制的順序要考慮清楚,
	將目標顏色和設置的目標因子相對應,源顏色和設置的源因子相對應。
	在進行三維混合時,不僅要考慮源因子和目標因子,還應該考慮深度緩沖區。必須先繪制所有不透明的物體,再繪制半透明的物體。在繪制半透明物體時前,還需要將深度緩沖區設置為只讀形式,
	否則可能出現畫面錯誤。
	*************************************************************************************************************************/
	/***************自定義混合源和目標顏色因子**************************************************************************************
	THREE.ZeroFactor = 200;                       //GL_ZERO:     表示使用0.0作為因子,實際上相當於不使用這種顏色參與混合運算
	THREE.OneFactor = 201;                        //GL_ONE:      表示使用1.0作為因子,實際上相當於完全的使用了這種顏色參與混合運算。
	THREE.SrcColorFactor = 202;                   //GL_SRC_COLOR  表示使用源顏色的四個分量分別作為因子的四個分量
	THREE.OneMinusSrcColorFactor = 203;           //GL_ONE_MINUS_SRC_COLOR 表示使用1.0減去源顏色的四個分量分別作為因子的四個分量
	THREE.SrcAlphaFactor = 204;                   //GL_SRC_ALPHA:表示使用源顏色的alpha值來作為因子。
	THREE.OneMinusSrcAlphaFactor = 205;           //GL_ONE_MINUS_SRC_ALPHA:表示用1.0減去源顏色的alpha值來作為因子。
	THREE.DstAlphaFactor = 206;                   //GL_DST_ALPHA:表示使用目標顏色的alpha值來作為因子。
	THREE.OneMinusDstAlphaFactor = 207;           //GL_ONE_MINUS_DST_ALPHA:表示用1.0減去目標顏色的alpha值來作為因子。

	//custom blending source factors
	// 自定義混合模式源顏色因子

	//THREE.ZeroFactor = 200;
	//THREE.OneFactor = 201;
	//THREE.SrcAlphaFactor = 204;
	//THREE.OneMinusSrcAlphaFactor = 205;
	//THREE.DstAlphaFactor = 206;
	//THREE.OneMinusDstAlphaFactor = 207;
	THREE.DstColorFactor = 208;                   //GL_DST_COLOR  表示使用目標顏色的四個分量分別作為因子的四個分量
	THREE.OneMinusDstColorFactor = 209;           //GL_ONE_MINUS_DST_COLOR  表示使用1.0減去目標顏色的四個分量分別作為因子的四個分量
	THREE.SrcAlphaSaturateFactor = 210;           //GL_SRC_ALPHA_SATURATE  表示源顏色的alpha 值和RGB值采用不同的混合因子
	*****************************************************************************************************************************/
	this.blendSrc = THREE.SrcAlphaFactor;	//混合顏色的源顏色因子,默認為THREE.SrcAlphaFactor. GL_SRC_ALPHA:表示使用源顏色的alpha值來作為因子。其它選項參考上面注釋
	this.blendDst = THREE.OneMinusSrcAlphaFactor;	//混合顏色的目標顏色因子,默認為THREE.OneMinusSrcAlphaFactor. GL_ONE_MINUS_SRC_ALPHA:表示用1.0減去源顏色的alpha值來作為因子。其它選項參考上面注釋

	// 參考:https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBlendEquation.xml
	// 參考:https://www.opengl.org/wiki/Blending
	// 參考:http://blog.sina.com.cn/s/blog_7b62c61c01016nnc.html
	/*********************************************設置混合方程式*********************************************************
	設置混合方程式:glBlendEquation(GLenum mode);
	        GLenum mode可取的值:
	        GL_FUNC_ADD                        Cf = (Cs * S)+(Cd * D)
	        GL_FUNC_SUBTRACT                   Cf = (Cs * S)-(Cd * D)   
	        GL_FUNC_RESERSE_SUBTRACT           Cf = (Cd * D)-(Cs * S)
	        GL_MIN                             Cf = min(Cs,Cd)
	        GL_MAX                             Cf = max(Cs,Cd)
	其中:
	        a. Cf表示混合后顯示的顏色
	        b. Cd混合前顏色緩沖中已經有的顏色值
	        c. Cs將要繪制的顏色
	        d. S為glBlendFunc函數設置時的第一個參數,源顏色因子
	        e. D為glBlendFunc函數設置時的第二個參數,目標顏色因子
	**********************************************設置混合方程式*********************************************************/
	this.blendEquation = THREE.AddEquation;		//混合方程式,默認為THREE.AddEquation,相加,看上面公式
	/************************深度測試************************************************************************************
	參考:http://blog.csdn.net/zhongjling/article/details/7573055
	openGL里常出現深度測試,一直不清楚。今天就來弄清楚。
	  (1)什么是深度?
	        深度其實就是該象素點在3d世界中距離攝象機的距離(繪制坐標),深度緩存中存儲着每個象素點(繪制在屏幕上的)的深度值!
	   深度值(Z值)越大,則離攝像機越遠。
	   深度值是存貯在深度緩存里面的,我們用深度緩存的位數來衡量深度緩存的精度。深度緩存位數越高,則精確度越高,目前的顯卡一般都可支持16位的Z Buffer,一些高級的顯卡已經可以支持32位的Z Buffer,但一般用24位Z Buffer就已經足夠了。
	  (2)為什么需要深度?
	   在不使用深度測試的時候,如果我們先繪制一個距離較近的物體,再繪制距離較遠的物體,則距離遠的物體因為后繪制,會把距離近的物體覆蓋掉,這樣的效果並不是我們所希望的。而有了深度緩沖以后,繪制物體的順序就不那么重要了,都能按照遠近(Z值)正常顯示,這很關鍵。
	        實際上,只要存在深度緩沖區,無論是否啟用深度測試,OpenGL在像素被繪制時都會嘗試將深度數據寫入到緩沖區內,除非調用了glDepthMask(GL_FALSE)來禁止寫入。這些深度數據除了用於常規的測試外,還可以有一些有趣的用途,比如繪制陰影等等。
	 (2)啟用深度測試
	     使用 glEnable(GL_DEPTH_TEST);
	     在默認情況是將需要繪制的新像素的z值與深度緩沖區中對應位置的z值進行比較,如果比深度緩存中的值小,那么用新像素的顏色值更新幀緩存中對應像素的顏色值。
	     但是可以使用glDepthFunc(func)來對這種默認測試方式進行修改。
	     其中參數func的值可以為GL_NEVER(沒有處理)、GL_ALWAYS(處理所有)、GL_LESS(小於)、GL_LEQUAL(小於等於)、GL_EQUAL(等於)、GL_GEQUAL(大於等於)、GL_GREATER(大於)或GL_NOTEQUAL(不等於),其中默認值是GL_LESS。
	    一般來將,使用glDepthFunc(GL_LEQUAL);來表達一般物體之間的遮擋關系。 
	(3)啟用了深度測試,那么這就不適用於同時繪制不透明物體。

	備注:
		繪制半透明物體時,需注意:在繪制半透明物體時前,還需要利用glDepthMask(GL_FALSE)將深度緩沖區設置為只讀形式,否則可能出現畫面錯誤。為什么呢,因為畫透明物體時,將使用混色,這時就不能繼續使用深度模式,而是利用混色函數來進行混合。這一來,就可以使用混合函數繪制半透明物體了。

	*****************************深度測試*******************************************************************************/
	this.depthTest = true;		//深度測試,默認為true,如果設置為false,在場景中遠處的對象不被近處的對象遮擋

	/*****************************************************************************************************************
	如果flag是GL_FLASE,那么向深度緩沖區寫入是禁止的。否則,就是允許的。初始時,是允許向深度緩沖區寫入數據的。
	glDepthMask指定是否允許向深度緩沖區寫入數據。如果flag是GL_FLASE,那么向深度緩沖區寫入是禁止的。否則,就是允許的。
	初始時,是允許向深度緩沖區寫入數據的。
	如果在glBegin和glEnd之間執行glDepthMask,會產生GL_INVALID_OPERATION。
	參考:http://blog.csdn.net/wlsgzl/article/details/13022959
	******************************************************************************************************************/
	this.depthWrite = true;		//允許或禁止向深度緩沖區寫入數據,默認為true,指定是否允許向深度緩沖區寫入數據。


	this.polygonOffset = false;	//多邊形位移,當兩個面共面時,會出現十分難看的z - fighting 問題,要解決此問題可以使用, Polygon Offset,
								//參考:https://www.opengl.org/sdk/docs/man2/xhtml/glPolygonOffset.xml
	this.polygonOffsetFactor = 0;	//多邊形位移因子
	this.polygonOffsetUnits = 0;	//多邊形位移單位

	/*************************alpha測試*******************************************************************************
	參考:http://blog.sina.com.cn/s/blog_471132920101d8z1.html
	原創文章如需轉載請注明:轉載自風宇沖Unity3D教程學院
	                       Shader第十二講 Alpha測試

	引言:本講和下一講主要講Alpha即透明通道有關的內容。RGBA,其中最終在屏幕上顯示的只有RGB即 紅綠藍組成的顏色,Alpha並沒有任何顏色顯示。A只是輔助顏色運算特別是多圖層運算而已。例如在單圖層的情況下(1,1,1,0.8)輸出的是(1,1,1)*0.8即 淺灰色(0.8,0.8,0.8),和(0.8,0.8,0.8)是等價的.但是假如不再是單圖層而背景為綠色(0,1,0,1)的時候,(0.8,0.8,0.8)就不知道怎么去運算了,而(1,1,1,0.8)知道。看不懂這段引言?沒關系,往下看,當學完第五講和第六講后再回來看就自然能深刻理解了。

	什么是通道:
	通道是8位的灰度圖像,能夠顯示256種灰度,用來表示顏色的RGBA值。R=Red紅色,G=Green綠色,B=blue藍色,A=alhpa透明值, 其中RGB為原色通道,A為透明通道。
	在通道中,以白色代替透明表示要處理的部分(選擇區域);以黑色表示不需處理的部分(非選擇區域)
	所有通道取值范圍是 [0,255], 但是在Shader里取值范圍是[0,1], 0和1分辨對應0和255
	什么是Alpha通道:
	定義:一般圖形卡具有32位總線,附加的8位信號就被用來保存不可見的透明度信號以方便處理用,這就是Alpha通道。白色的alpha象素用以定義不透明的彩色象素,而黑色的alpha象素用以定義透明象素,黑白之間的灰階用來定義半透明象素。
	簡而言之:Alpha通道取值同樣為[0,255] 以及Shader[0,1], 值越小最透明,值最大越不透明。在Shader里即0為透明,什么都沒有,編輯器顯示為黑色。1則不透明,全部都顯示,編輯器其顯示為白色如下圖。
	【風宇沖】Unity3D教程寶典之Shader篇:第十二講 <wbr>Alpha測試

	什么是Alpha Test:
	Alpha Test ,中文就是透明度測試。簡而言之就是V&F shader中最后fragment函數輸出的該點顏色值(即上一講frag的輸出half4)的alpha值與固定值進行比較。 AlphaTest語句通常位於Pass{}中的起始位置。

	語法:
	第一種: AlphaTest Off: 不測試,全渲染
	第二種:Alpha 比較符 目標alpha值
	其中目標alpha值取值范圍是 0至1, 也可以用參數 ,如 AlphaTest [varName]。

	比較符:(目標alpha值下面記作x)
	Always  全渲染(任意x值)
	Never   全不渲染
	Greater  點的alpha值大於x時渲染
	GEuqal   點的alpha值大於等於x時渲染
	Less       點的alpha值小於x時渲染
	LEqual    點的alpha值小於等於x時渲染
	Equal  點的alpha值等於x時渲染
	NotEqual  點的alpha值不等於x時渲染

	例:
	AlphaTest never  0      全不渲染(這個0可以是任意值,但必須填)
	AlphaTest always 0      全渲染(這個0可以是任意值,但必須填)
	AlphaTest off               全渲染
	AlphaTest Greater 0.4  當alpha大於0.4渲染,   缺點是邊緣過於鋒利並且顯示不完整,alpha小於0.4的部分被忽略掉了
	Alpha Blend                 邊緣柔和,但是中心也太柔和,沒有實體的感覺
	AlphaTest Greater 0.4 / AlphaTest LEqual 0.4 兩個部分,大於0.4不混合,小於0.4混合。效果是既有實體感覺,邊緣也柔和。
	【風宇沖】Unity3D教程寶典之Shader篇:第十二講 <wbr>Alpha測試


	*************************alpha測試*********************************************************************************/
	this.alphaTest = 0;	//alpha測試,取值范圍0.0-1.0

	this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer
						// 當三角面之間產生間距,發生圖形走樣時,填充像素,確保圖形保真,消除走樣.通常取值范圍在0.0=1.0之間.

	this.visible = true;	//可見性,默認為true

	this.needsUpdate = true;	//當設置為true時,標記材質已經更新.

};

/****************************************
****下面是Fog對象提供的功能函數.
****************************************/

THREE.Material.prototype = {

	constructor: THREE.Material,		//構造器,返回對創建此對象的Material函數的引用

	/*
	///setValues方法用來通過參數values設置材質對象的屬性.values參數的格式為
	 values = {
	 *  color: <hex>,
	 *  opacity: <float>,
	 *  map: new THREE.Texture( <Image> ),
	 *
	 *  lightMap: new THREE.Texture( <Image> ),
	 *
	 *  specularMap: new THREE.Texture( <Image> ),
	 *
	 *  alphaMap: new THREE.Texture( <Image> ),
	 *
	 *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
	 *  combine: THREE.Multiply,
	 *  reflectivity: <float>,
	 *  refractionRatio: <float>,
	 *
	 *  shading: THREE.SmoothShading,
	 *  blending: THREE.NormalBlending,
	 *  depthTest: <bool>,
	 *  depthWrite: <bool>,
	 *
	 *  wireframe: <boolean>,
	 *  wireframeLinewidth: <float>,
	 *
	 *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
	 *
	 *  skinning: <bool>,
	 *  morphTargets: <bool>,
	 *
	 *  fog: <bool>
	 * }
	*/
	///<summary>setValues</summary>
	///<param name ="values" type="Object">材質屬性值</param>
	///<returns type="Material">返回新的材質對象</returns>
	setValues: function ( values ) {

		if ( values === undefined ) return;

		for ( var key in values ) {	//遍歷values中的鍵值,並一一賦值給當前材質對象.

			var newValue = values[ key ];

			if ( newValue === undefined ) {

				console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
				continue;

			}

			if ( key in this ) {

				var currentValue = this[ key ];

				if ( currentValue instanceof THREE.Color ) {

					currentValue.set( newValue );

				} else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) {

					currentValue.copy( newValue );

				} else if ( key == 'overdraw' ) {

					// ensure overdraw is backwards-compatable with legacy boolean type
					this[ key ] = Number( newValue );

				} else {

					this[ key ] = newValue;

				}

			}

		}

	},

	/*clone方法
	///clone方法克隆一個材質對象.
	*/
	///<summary>clone</summary>
	///<param name ="material" type="Material">接收結果的材質對象</param>
	///<returns type="Texture">返回克隆的材質對象</returns>	
	clone: function ( material ) {
		//一下將材質屬性一一復制.
		if ( material === undefined ) material = new THREE.Material();

		material.name = this.name;

		material.side = this.side;

		material.opacity = this.opacity;
		material.transparent = this.transparent;

		material.blending = this.blending;

		material.blendSrc = this.blendSrc;
		material.blendDst = this.blendDst;
		material.blendEquation = this.blendEquation;

		material.depthTest = this.depthTest;
		material.depthWrite = this.depthWrite;

		material.polygonOffset = this.polygonOffset;
		material.polygonOffsetFactor = this.polygonOffsetFactor;
		material.polygonOffsetUnits = this.polygonOffsetUnits;

		material.alphaTest = this.alphaTest;

		material.overdraw = this.overdraw;

		material.visible = this.visible;

		return material;	//返回克隆的材質對象

	},
	/*dispose方法
	///dispose方法從內存中刪除對象,釋放資源.
	///NOTE: 當刪除材質對象,不要忘記調用這個方法,否則會導致內存泄露.
	*/
	///<summary>dispose</summary>
	dispose: function () {

		this.dispatchEvent( { type: 'dispose' } );

	}

};
///EventDispatcher方法應用到當前Material對象.
THREE.EventDispatcher.prototype.apply( THREE.Material.prototype );
///設置全局的Material對象計數器.
THREE.MaterialIdCount = 0;


商域無疆 (http://blog.csdn.net/omni360/)

本文遵循“署名-非商業用途-保持一致”創作公用協議

轉載請保留此句:商域無疆 -  本博客專注於 敏捷開發及移動和物聯設備研究:數據可視化、GOLANG、Html5、WEBGL、THREE.JS否則,出自本博客的文章拒絕轉載或再轉載,謝謝合作。


以下代碼是THREE.JS 源碼文件中Material/Material .js文件的注釋.

更多更新在 : https://github.com/omni360/three.js.sourcecode


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com