iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 20
1
Modern Web

寫給工程師的 WebGL 學習心得系列 第 20

[WebGL - Day20] 在 three.js 裡寫 Shader

  • 分享至 

  • xImage
  •  

相較 PixiJS,three.js 應用 Shader 的方式就相當多種


先前的自己,看到程式碼裡有 Shader 時,會覺得
"啊,是Shader,看不懂啦,最多改改參數啦"
看著系列文到這,或多或少能看得懂原理了
本篇介紹一個 three.js 範例的寫法

WebGL buffergeometry rawshader

先前文章裡提到的範例:
three.js examples - WebGL buffergeometry rawshader
THREE.js WebGL buffergeometry rawshader

WebGL pipeline

系列文先前的文章,提到 WebGL 的運算流程:
WebGL pipeline

  • JS 透過 attribute 把值帶到 vertex shader
  • vertex shader 透過 varying 把值帶到 fragment shader
  • JS 透過 uniform 帶值給 vertex shaderfragment shader

接著,大概能看懂這個範例的寫法了 - Source Code


JavaScript

var positions = [];
var colors = [];
for ( var i = 0; i < vertexCount; i ++ ) {
	// adding x,y,z
	positions.push( Math.random() - 0.5 );
	positions.push( Math.random() - 0.5 );
	positions.push( Math.random() - 0.5 );
	// adding r,g,b,a
	colors.push( Math.random() * 255 );
	colors.push( Math.random() * 255 );
	colors.push( Math.random() * 255 );
	colors.push( Math.random() * 255 );
}
var positionAttribute = new THREE.Float32BufferAttribute( positions, 3 );
var colorAttribute = new THREE.Uint8BufferAttribute( colors, 4 );
colorAttribute.normalized = true; // this will map the buffer values to 0.0f - +1.0f in the shader
geometry.addAttribute( 'position', positionAttribute );
geometry.addAttribute( 'color', colorAttribute );

首先是用 attribute 把值帶進 Vertex Shader,帶了 positioncolor

Vertex Shader 程式碼

<script id="vertexShader" type="x-shader/x-vertex">
	precision mediump float;
	precision mediump int;
	uniform mat4 modelViewMatrix; // optional
	uniform mat4 projectionMatrix; // optional
	attribute vec3 position;
	attribute vec4 color;
	varying vec3 vPosition;
	varying vec4 vColor;
	void main()	{
		vPosition = position;
		vColor = color;
		gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
	}
</script>

attribute vec3 positionattribute vec4 color 是剛剛透過 attribute 帶進來的變數
接著再定義兩個 varying 的變數: vPositionvColor
會傳給 fragment shader

Fragment Shader 程式碼

<script id="fragmentShader" type="x-shader/x-fragment">
	precision mediump float;
	precision mediump int;
	uniform float time;
	varying vec3 vPosition;
	varying vec4 vColor;
	void main()	{
		vec4 color = vec4( vColor );
		color.r += sin( vPosition.x * 10.0 + time ) * 0.5;
		gl_FragColor = color;
	}
</script>

varying vec3 vPositionvarying vec4 vColorvertex shader 傳入

void main()	{
	vec4 color = vec4( vColor );
	color.r += sin( vPosition.x * 10.0 + time ) * 0.5;
	gl_FragColor = color;
}

輸出的顏色:

  • vColor 帶來
  • 輸出顏色的 R,會跟著時間做簡諧運動 (且與 vPosition 有關)
  • 變數使用 vPosition.x 變化,所以顏色變化看起來是直的往旁移動

time
Fragment Shader 還有一個值 - time

uniform float time

uniform 變數會由 JavaScript 帶入

var material = new THREE.RawShaderMaterial( {
	uniforms: {
		time: { value: 1.0 }
	},
	vertexShader: document.getElementById( 'vertexShader' ).textContent,
	fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
	side: THREE.DoubleSide,
	transparent: true
} );

與更新

function render() {
	var time = performance.now();
	var object = scene.children[ 0 ];
    ...
	object.material.uniforms.time.value = time * 0.005;
}

好像...看得懂了?

覺得從 WebGL pipeline 來理解 WebGL JavaScript library 的一些實作,
是學習與應用 Shader 方法之一

純 WebGL 應用的寫法會更複雜些,本系列暫不討論


同樣的,系列文希望大家不會覺得 Shader 很可怕
只是 Shader 需要前置學習的部分真的很多,
但真的很有趣


上一篇
[WebGL - Day19] PixiJS 濾鏡實作 - glowFilter、PixiJS v4 v5 版濾鏡寫法差異
下一篇
[WebGL - Day21] Shadertoy + PixiJS,電視雜訊效果實作
系列文
寫給工程師的 WebGL 學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言