three.js ShaderMaterial

2023-02-16 17:45 更新

使用自定義shader渲染的材質(zhì)。 shader是一個(gè)用GLSL編寫(xiě)的小程序 ,在GPU上運(yùn)行。 您可能需要使用自定義shader,如果你要:

  • 要實(shí)現(xiàn)內(nèi)置 materials 之外的效果。
  • 將許多對(duì)象組合成單個(gè)BufferGeometry以提高性能。

使用ShaderMaterial時(shí)需要注意以下注意事項(xiàng):

  • ShaderMaterial 只有使用 WebGLRenderer 才可以繪制正常, 因?yàn)?nbsp;vertexShader 和 fragmentShader 屬性中GLSL代碼必須使用WebGL來(lái)編譯并運(yùn)行在GPU中。
  • 從 THREE r72開(kāi)始,不再支持在ShaderMaterial中直接分配屬性。 必須使用 BufferGeometry實(shí)例,使用BufferAttribute實(shí)例來(lái)定義自定義屬性。
  • 從 THREE r77開(kāi)始,WebGLRenderTarget 或 WebGLCubeRenderTarget 實(shí)例不再被用作uniforms。 必須使用它們的texture 屬性。
  • 內(nèi)置attributes和uniforms與代碼一起傳遞到shaders。 如果您不希望WebGLProgram向shader代碼添加任何內(nèi)容,則可以使用RawShaderMaterial而不是此類。
  • 您可以使用指令#pragma unroll_loop_start,#pragma unroll_loop_end 以便通過(guò)shader預(yù)處理器在GLSL中展開(kāi)for循環(huán)。 該指令必須放在循環(huán)的正上方。循環(huán)格式必須與定義的標(biāo)準(zhǔn)相對(duì)應(yīng)。
    • 循環(huán)必須標(biāo)準(zhǔn)化normalized。
    • 循環(huán)變量必須是i。
    • 對(duì)于給定的迭代,值 UNROLLED_LOOP_INDEX 將替換為 i 的顯式值,并且可以在預(yù)處理器語(yǔ)句中使用。
    • #pragma unroll_loop_start
      for ( int i = 0; i < 10; i ++ ) {
      
      	// ...
      
      }
      #pragma unroll_loop_end

代碼示例

const material = new THREE.ShaderMaterial( {

	uniforms: {

		time: { value: 1.0 },
		resolution: { value: new THREE.Vector2() }

	},

	vertexShader: document.getElementById( 'vertexShader' ).textContent,

	fragmentShader: document.getElementById( 'fragmentShader' ).textContent

} );

例子

webgl / buffergeometry / custom / attributes / particles
webgl / buffergeometry / selective / draw
webgl / custom / attributes
webgl / custom / attributes / lines
webgl / custom / attributes / points
webgl / custom / attributes / points2
webgl / custom / attributes / points3
webgl / depth / texture
webgl / gpgpu / birds
webgl / gpgpu / protoplanet
webgl / gpgpu / water
webgl / interactive / points
webgl / video / kinect
webgl / lights / hemisphere
webgl / marchingcubes
webgl / materials / envmaps
webgl / materials / lightmap
webgl / materials / wireframe
webgl / modifier / tessellation
webgl / postprocessing / dof2
webgl / postprocessing / godrays

頂點(diǎn)著色器和片元著色器(Vertex shaders and fragment shaders)

您可以為每種材質(zhì)指定兩種不同類型的shaders::

  • 頂點(diǎn)著色器首先運(yùn)行; 它接收attributes, 計(jì)算/操縱每個(gè)單獨(dú)頂點(diǎn)的位置,并將其他數(shù)據(jù)(varyings)傳遞給片元著色器。
  • 片元(或像素)著色器后運(yùn)行; 它設(shè)置渲染到屏幕的每個(gè)單獨(dú)的“片元”(像素)的顏色。

shader中有三種類型的變量: uniforms, attributes, 和 varyings:

  • Uniforms是所有頂點(diǎn)都具有相同的值的變量。 比如燈光,霧,和陰影貼圖就是被儲(chǔ)存在uniforms中的數(shù)據(jù)。 uniforms可以通過(guò)頂點(diǎn)著色器和片元著色器來(lái)訪問(wèn)。
  • Attributes 與每個(gè)頂點(diǎn)關(guān)聯(lián)的變量。例如,頂點(diǎn)位置,法線和頂點(diǎn)顏色都是存儲(chǔ)在attributes中的數(shù)據(jù)。attributes 只 可以在頂點(diǎn)著色器中訪問(wèn)。
  • Varyings 是從頂點(diǎn)著色器傳遞到片元著色器的變量。對(duì)于每一個(gè)片元,每一個(gè)varying的值將是相鄰頂點(diǎn)值的平滑插值。

注意:在shader 內(nèi)部,uniforms和attributes就像常量;你只能使用JavaScript代碼通過(guò)緩沖區(qū)來(lái)修改它們的值。

內(nèi)置attributes 和 uniforms(Built-in attributes and uniforms)

WebGLRenderer默認(rèn)情況下為shader提供了許多attributes和uniforms; 這些變量定義在shader程序編譯時(shí)被自動(dòng)添加到*片元著色器*和*頂點(diǎn)著色器*代碼的前面,你不需要自己聲明它們。 這些變量的描述請(qǐng)參見(jiàn)WebGLProgram。

這些uniforms或attributes(例如,那些和照明,霧等相關(guān)的)要求屬性設(shè)置在材質(zhì)上, 以便 WebGLRenderer來(lái)拷貝合適的值到GPU中。 如果你想在自己的shader中使用這些功能,請(qǐng)確保設(shè)置這些標(biāo)志。

如果你不希望WebGLProgram 向你的shader代碼中添加任何東西, 你可以使用RawShaderMaterial 而不是這個(gè)類。

自定義 attributes 和 uniforms(Custom attributes and uniforms)

自定義attributes和uniforms必須在GLSL著色器代碼中聲明(在 vertexShader 和/或 fragmentShader 中)。 自定義uniforms必須定義為 ShaderMaterial 的 uniforms 屬性, 而任何自定義attributes必須通過(guò)BufferAttribute實(shí)例來(lái)定義。 注意 varyings 只需要在shader代碼中聲明(而不必在材質(zhì)中)。

要聲明一個(gè)自定義屬性,更多細(xì)節(jié)請(qǐng)參考BufferGeometry頁(yè)面, 以及 BufferAttribute 頁(yè)面關(guān)于BufferAttribute 接口。

當(dāng)創(chuàng)建attributes時(shí),您創(chuàng)建的用來(lái)保存屬性數(shù)據(jù)的每個(gè)類型化數(shù)組(typed array)必須是您的數(shù)據(jù)類型大小的倍數(shù)。 比如,如果你的屬性是一個(gè)THREE.Vector3類型,并且在你的緩存幾何模型BufferGeometry中有3000個(gè)頂點(diǎn), 那么你的類型化數(shù)組的長(zhǎng)度必須是3000 * 3,或者9000(一個(gè)頂點(diǎn)一個(gè)值)。每個(gè)數(shù)據(jù)類型的尺寸如下表所示:

GLSL 類型 JavaScript 類型 尺寸
float Number 1
vec2 THREE.Vector2 2
vec3 THREE.Vector3 3
vec3 THREE.Color 3
vec4 THREE.Vector4 4

請(qǐng)注意,屬性緩沖區(qū) 不會(huì) 在其值更改時(shí)自動(dòng)刷新。要更新自定義屬性, 需要在模型的BufferAttribute中設(shè)置needsUpdate為true。 (查看BufferGeometry了解細(xì)節(jié))。

要聲明一個(gè)自定義的Uniform,使用uniforms屬性:

uniforms: {
		time: { value: 1.0 },
		resolution: { value: new THREE.Vector2() }
	}

在Object3D.onBeforeRender中,建議根據(jù)object和camera來(lái)更新自定義Uniform的值。 因?yàn)?nbsp;Material 可以被meshes,Scene的matrixWorld以及Camera共享, 會(huì)在WebGLRenderer.render中更新,并會(huì)對(duì)擁有私有cameras的scene的渲染造成影響。

構(gòu)造函數(shù)(Constructor)

ShaderMaterial( parameters : Object )

parameters - (可選)用于定義材質(zhì)外觀的對(duì)象,具有一個(gè)或多個(gè)屬性。 材質(zhì)的任何屬性都可以從此處傳入(包括從Material繼承的任何屬性)。

屬性(Properties)

共有屬性請(qǐng)參見(jiàn)其基類Material。

.clipping : Boolean

定義此材質(zhì)是否支持剪裁; 如果渲染器傳遞clippingPlanes uniform,則為true。默認(rèn)值為false。

.defaultAttributeValues : Object

當(dāng)渲染的幾何體不包含這些屬性但材質(zhì)包含這些屬性時(shí),這些默認(rèn)值將傳遞給shaders。這可以避免在緩沖區(qū)數(shù)據(jù)丟失時(shí)出錯(cuò)。

this.defaultAttributeValues = {
	'color': [ 1, 1, 1 ],
	'uv': [ 0, 0 ],
	'uv2': [ 0, 0 ]
};

.defines : Object

使用 #define 指令在GLSL代碼為頂點(diǎn)著色器和片段著色器定義自定義常量;每個(gè)鍵/值對(duì)產(chǎn)生一行定義語(yǔ)句:

defines: {
	FOO: 15,
	BAR: true
}

這將在GLSL代碼中產(chǎn)生如下定義語(yǔ)句:

#define FOO 15
#define BAR true

.extensions : Object

一個(gè)有如下屬性的對(duì)象:

this.extensions = {
	derivatives: false, // set to use derivatives
	fragDepth: false, // set to use fragment depth values
	drawBuffers: false, // set to use draw buffers
	shaderTextureLOD: false // set to use shader texture LOD
};

.fog : Boolean

定義材質(zhì)顏色是否受全局霧設(shè)置的影響; 如果將fog uniforms傳遞給shader,則為true。默認(rèn)值為false。

.fragmentShader : String

片元著色器的GLSL代碼。這是shader程序的實(shí)際代碼。在上面的例子中, vertexShader 和 fragmentShader 代碼是從DOM(HTML文檔)中獲取的; 它也可以作為一個(gè)字符串直接傳遞或者通過(guò)AJAX加載。

.glslVersion : String

定義自定義著色器代碼的 GLSL 版本。僅與 WebGL 2 相關(guān),以便定義是否指定 GLSL 3.0。有效值為 THREE.GLSL1 或 THREE.GLSL3。默認(rèn)為空。

.index0AttributeName : String

如果設(shè)置,則調(diào)用gl.bindAttribLocation 將通用頂點(diǎn)索引綁定到屬性變量。默認(rèn)值未定義。

.isShaderMaterial : Boolean

只讀標(biāo)志,用于檢查給定對(duì)象是否屬于 ShaderMaterial 類型。

.lights : Boolean

材質(zhì)是否受到光照的影響。默認(rèn)值為 false。如果傳遞與光照相關(guān)的uniform數(shù)據(jù)到這個(gè)材質(zhì),則為true。默認(rèn)是false。

.linewidth : Float

控制線框?qū)挾?。默認(rèn)值為1。

由于OpenGL Core Profile與大多數(shù)平臺(tái)上WebGL渲染器的限制,無(wú)論如何設(shè)置該值,線寬始終為1。

.flatShading : Boolean

定義材質(zhì)是否使用平面著色進(jìn)行渲染。默認(rèn)值為false。

.uniforms : Object

如下形式的對(duì)象:

{ "uniform1": { value: 1.0 }, "uniform2": { value: 2 } }

指定要傳遞給shader代碼的uniforms;鍵為uniform的名稱,值(value)是如下形式:

{ value: 1.0 }

這里 value 是uniform的值。名稱必須匹配 uniform 的name,和GLSL代碼中的定義一樣。 注意,uniforms逐幀被刷新,所以更新uniform值將立即更新GLSL代碼中的相應(yīng)值。

.uniformsNeedUpdate : Boolean

可用于在 Object3D.onBeforeRender() 中更改制服時(shí)強(qiáng)制進(jìn)行制服更新。默認(rèn)為假。

.vertexColors : Boolean

定義是否使用頂點(diǎn)著色。默認(rèn)為假。

.vertexShader : String

頂點(diǎn)著色器的GLSL代碼。這是shader程序的實(shí)際代碼。 在上面的例子中,vertexShader 和 fragmentShader 代碼是從DOM(HTML文檔)中獲取的; 它也可以作為一個(gè)字符串直接傳遞或者通過(guò)AJAX加載。

.wireframe : Boolean

將幾何體渲染為線框(通過(guò)GL_LINES而不是GL_TRIANGLES)。默認(rèn)值為false(即渲染為平面多邊形)。

.wireframeLinewidth : Float

控制線框?qū)挾?。默認(rèn)值為1。

由于OpenGL Core Profile與大多數(shù)平臺(tái)上WebGL渲染器的限制,無(wú)論如何設(shè)置該值,線寬始終為1。

方法(Methods)

共有方法請(qǐng)參見(jiàn)其基類Material。

.clone () : ShaderMaterial this : ShaderMaterial

創(chuàng)建該材質(zhì)的一個(gè)淺拷貝。需要注意的是,vertexShader和fragmentShader使用引用拷貝; attributes的定義也是如此; 這意味著,克隆的材質(zhì)將共享相同的編譯WebGLProgram; 但是,uniforms 是 值拷貝,這樣對(duì)不同的材質(zhì)我們可以有不同的uniforms變量。

源碼(Source)

src/materials/ShaderMaterial.js


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)