three.js 04-08のShaderMaterial材質


今日紹介する高級な材質はTHREE.ShaderMaterialです.これはthree.jsライブラリの中で最も機能が豊富で、最も複雑な高級素材です.これにより、自分のカラータイマーを定義して、直接WebGLの環境で動作します.着色器は、three.jsのJavaScriptオブジェクトをスクリーン上の画素に変換することができる.これらのカスタムの着色器によって、オブジェクトをどのようにレンダリングし、覆い隠すかを明確に指定したり、three.jsライブラリのデフォルト値を変更したりすることができます.
    しかし、私たちの本はどのように色器をカスタマイズするかには関わりません.これはもう別の専門技術体系に属しています.次に、まずShader Materialで設定できるいくつかの一般的な属性を見てみます.ほとんどは他の基礎材質と似ています.wireframe、wireframe elinedth、flat Shading、fog、vertexColorsなどがあります.
    特にvertexColors属性は、頂点ごとに異なる色を定義することができます.Canvas Rendererの下では機能せず、WebGrenderの下でしか機能しません.この属性については、後述するLinese Baic Materialの例を参照することができる.
    上記のような属性以外にも、Shader Materialにはいくつかの特別な属性があります.それらを使って、データを入力して、あなたのカラータイマーをカスタマイズできます.しかし、それらは理解しにくいように見えます.「GSL着色器言語」に関する知識を組み合わせて、次の表に示します.
属性
説明
fragment Shader(画素着色器)
この着色器は、導入された各画素の色を定義する.
vertex Shader(頂点着色器)
この着色器は、各入力の頂点の位置を変更することができます.
uniforms(統一値)
この属性であなたのカラーライターにメッセージを送ることができます.同じ情報は各頂点とセグメントに送られます.
defines
この属性の値は、vertexShaderとfrangement Shaderの中の嗵defineコードに変換できます.この属性は、スケジュレータプログラムのグローバル変数の一部を設定するために使用できます.
atributes
この属性は、各頂点とセグメントを変更できます.位置データが法線ベクトルに関連するデータを伝達するために一般的に使用される.この属性を使うなら、幾何体のすべての頂点に情報を提供しますか?
lights
この属性は、光照射データが着色器に渡されるかどうかを定義します.デフォルトはfalseです
    その中で最も重要な部分は、Shader Materialの材質を使うには、二つの異なる色機が必要です.
  • vertexShader:幾何学体の各頂点で実行されます.この着色器で頂点の位置を変えて幾何体を変換できます.
  • fragment Shader:幾何学体の各ピクセルで実行されます.vertex Shaderでは、この特定のピクセルが表示すべき色を返します.
  •     今まで検討したすべての材質は、three.jsライブラリにそれぞれのvertexShaderとfrangement Shaderを提供します.私達自身で定義する必要はありません.
        次に、我々が提示するこの例は、動的な材質を作成します.中には簡単なvertex Shaderを使用して、ブロックの各頂点のx、y、z座標を変更します.もう一つのfragment Shaderも使用します. http://glslsandbox.com/ 連続的に変化する材質を作成するために、多くの着色器が提供されています.完全コードは以下の通りです.
    
    
    
           04.08 - ShaderMaterial
    	
    	
    	
    	
    	
        
    
    
    
    
    
    uniform float time; varying vec2 vUv; 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(position*(abs(sin(time)/2.0)+0.5),1.0); //gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0); } precision highp float; uniform float time; uniform float alpha; uniform vec2 resolution; varying vec2 vUv; void main2(void) { vec2 position = vUv; float red = 1.0; float green = 0.25 + sin(time) * 0.25; float blue = 0.0; vec3 rgb = vec3(red, green, blue); vec4 color = vec4(rgb, alpha); gl_FragColor = color; } #define PI 3.14159 #define TWO_PI (PI*2.0) #define N 68.5 void main(void) { vec2 center = (gl_FragCoord.xy); center.x=-10.12*sin(time/200.0); center.y=-10.12*cos(time/200.0); vec2 v = (gl_FragCoord.xy - resolution/20.0) / min(resolution.y,resolution.x) * 15.0; v.x=v.x-10.0; v.y=v.y-200.0; float col = 0.0; for(float i = 0.0; i < N; i++) { float a = i * (TWO_PI/N) * 61.95; col += cos(TWO_PI*(v.y * cos(a) + v.x * sin(a) + sin(time*0.004)*100.0 )); } col /= 5.0; gl_FragColor = vec4(col*1.0, -col*1.0,-col*4.0, 1.0); } // from http://glsl.heroku.com/e#7906.0 uniform float time; uniform vec2 resolution; // 2013-03-30 by @hintz #define CGFloat float #define M_PI 3.14159265359 vec3 hsvtorgb(float h, float s, float v) { float c = v * s; h = mod((h * 6.0), 6.0); float x = c * (1.0 - abs(mod(h, 2.0) - 1.0)); vec3 color; if (0.0 <= h && h < 1.0) { color = vec3(c, x, 0.0); } else if (1.0 <= h && h < 2.0) { color = vec3(x, c, 0.0); } else if (2.0 <= h && h < 3.0) { color = vec3(0.0, c, x); } else if (3.0 <= h && h < 4.0) { color = vec3(0.0, x, c); } else if (4.0 <= h && h < 5.0) { color = vec3(x, 0.0, c); } else if (5.0 <= h && h < 6.0) { color = vec3(c, 0.0, x); } else { color = vec3(0.0); } color += v - c; return color; } void main(void) { vec2 position = (gl_FragCoord.xy - 0.5 * resolution) / resolution.y; float x = position.x; float y = position.y; CGFloat a = atan(x, y); CGFloat d = sqrt(x*x+y*y); CGFloat d0 = 0.5*(sin(d-time)+1.5)*d; CGFloat d1 = 5.0; CGFloat u = mod(a*d1+sin(d*10.0+time), M_PI*2.0)/M_PI*0.5 - 0.5; CGFloat v = mod(pow(d0*4.0, 0.75),1.0) - 0.5; CGFloat dd = sqrt(u*u+v*v); CGFloat aa = atan(u, v); CGFloat uu = mod(aa*3.0+3.0*cos(dd*30.0-time), M_PI*2.0)/M_PI*0.5 - 0.5; // CGFloat vv = mod(dd*4.0,1.0) - 0.5; CGFloat d2 = sqrt(uu*uu+v*v)*1.5; gl_FragColor = vec4( hsvtorgb(dd+time*0.5/d1, sin(dd*time), d2), 1.0 ); } uniform vec2 resolution; uniform float time; vec2 rand(vec2 pos) { return fract( 0.00005 * (pow(pos+2.0, pos.yx + 1.0) * 22222.0)); } vec2 rand2(vec2 pos) { return rand(rand(pos)); } float softnoise(vec2 pos, float scale) { vec2 smplpos = pos * scale; float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x; float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x; float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x; float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x; vec2 a = fract(smplpos); return mix( mix(c0, c1, smoothstep(0.0, 1.0, a.x)), mix(c2, c3, smoothstep(0.0, 1.0, a.x)), smoothstep(0.0, 1.0, a.y)); } void main(void) { vec2 pos = gl_FragCoord.xy / resolution.y; pos.x += time * 0.1; float color = 0.0; float s = 1.0; for(int i = 0; i < 8; i++) { color += softnoise(pos+vec2(i)*0.02, s * 4.0) / s / 2.0; s *= 2.0; } gl_FragColor = vec4(color); } uniform float time; uniform vec2 resolution; vec2 rand(vec2 pos) { return fract( pow( pos+2.0, pos.yx+2.0 ) * 555555.0 ); } vec2 rand2(vec2 pos) { return rand(rand(pos)); } float softnoise(vec2 pos, float scale) { vec2 smplpos = pos * scale; float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x; float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x; float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x; float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x; vec2 a = fract(smplpos); return mix(mix(c0, c1, smoothstep(0.0, 1.0, a.x)), mix(c2, c3, smoothstep(0.0, 1.0, a.x)), smoothstep(0.0, 1.0, a.x)); } void main( void ) { vec2 pos = gl_FragCoord.xy / resolution.y - time * 0.4; float color = 0.0; float s = 1.0; for (int i = 0; i < 6; ++i) { color += softnoise(pos + vec2(0.01 * float(i)), s * 4.0) / s / 2.0; s *= 2.0; } gl_FragColor = vec4(color,mix(color,cos(color),sin(color)),color,1); } uniform float time; uniform vec2 resolution; // tie nd die by Snoep Games. void main( void ) { vec3 color = vec3(1.0, 0., 0.); vec2 pos = (( 1.4 * gl_FragCoord.xy - resolution.xy) / resolution.xx)*1.5; float r=sqrt(pos.x*pos.x+pos.y*pos.y)/15.0; float size1=2.0*cos(time/60.0); float size2=2.5*sin(time/12.1); float rot1=13.00; //82.0+16.0*sin(time/4.0); float rot2=-50.00; //82.0+16.0*sin(time/8.0); float t=sin(time); float a = (60.0)*sin(rot1*atan(pos.x-size1*pos.y/r,pos.y+size1*pos.x/r)+time); //a += 200.0*acos(pos.x*2.0+cos(time/2.0))+asin(pos.y*5.0+sin(time/2.0)); a=a*(r/50.0); a=200.0*sin(a*5.0)*(r/30.0); if(a>5.0) a=a/200.0; if(a<0.5) a=a*22.5; gl_FragColor = vec4( cos(a/20.0),a*cos(a/200.0),sin(a/8.0), 1.0 ); } 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; } var scene; var camera; var render; var webglRender; var canvasRender; var controls; var stats; var guiParams; var ground; var cube; var meshMaterial; var ambientLight; $(function() { stats = initStats(); scene = new THREE.Scene(); webglRender = new THREE.WebGLRenderer( {antialias: true, alpha: true} ); // antialias webglRender.setSize(window.innerWidth, window.innerHeight); webglRender.setClearColor(0x000000, 1.0); webglRender.shadowMap.enabled = true; // render = webglRender; camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000); // 2147483647 camera.position.set(30, 30, 30); var target = new THREE.Vector3(0, 0 , 0); controls = new THREE.OrbitControls(camera, render.domElement); controls.target = target; camera.lookAt(target); $('#webgl-output')[0].appendChild(render.domElement); window.addEventListener('resize', onWindowResize, false); ambientLight = new THREE.AmbientLight(0x0c0c0c); scene.add(ambientLight); // var cubeGeometry = new THREE.BoxGeometry(20, 20, 20); // meshMaterial = [ createMaterial('#vertex-shader', '#fragment-shader-1') // ,createMaterial('#vertex-shader', '#fragment-shader-2') // ,createMaterial('#vertex-shader', '#fragment-shader-3') // ,createMaterial('#vertex-shader', '#fragment-shader-4') // ,createMaterial('#vertex-shader', '#fragment-shader-5') // ,createMaterial('#vertex-shader', '#fragment-shader-6') // ] // cube = new THREE.Mesh(cubeGeometry, meshMaterial); scene.add(cube); /** */ guiParams = new function() { this.rotationSpeed = 0.02; this.vertexControl = false; } /** dat.GUI , guiParams */ var gui = new dat.GUI(); gui.add(guiParams, 'vertexControl'); renderScene(); }); /** */ function renderScene() { stats.update(); rotateMesh(); // changeVertex(); requestAnimationFrame(renderScene); render.render(scene, camera); } /** stats */ function initStats() { stats = new Stats(); stats.setMode(0); // 0 FPS;1 $('#stats-output').append(stats.domElement); return stats; } /** */ function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); render.setSize(window.innerWidth, window.innerHeight); } /** */ function rotateMesh() { scene.traverse(function(mesh) { if (mesh instanceof THREE.Mesh && mesh != ground) { mesh.rotation.x += guiParams.rotationSpeed; mesh.rotation.y += guiParams.rotationSpeed; mesh.rotation.z += guiParams.rotationSpeed; } }); } /** */ function changeVertex() { if (!guiParams.vertexControl) return; cube.material.forEach(function (e) { e.uniforms.time.value += 0.01; }); } /** ShaderMaterial */ function createMaterial(vertexShader, fragmentShader) { var vertShader = $(vertexShader).text(); var fragShader = $(fragmentShader).text(); var uniforms = { time: {type: 'f', value: 0.2}, scale: {type: 'f', value: 0.2}, alpha: {type: 'f', value: 0.6}, resolution: {type: 'v2', value: new THREE.Vector2()} }; uniforms.resolution.value.x = window.innerWidth; uniforms.resolution.value.y = window.innerHeight; var shaderMaterial = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: vertShader, fragmentShader: fragShader, transparent: true }); return shaderMaterial; }
        その中のid=「vertex-sharder」はvertex Shaderのカラーライターのシナリオで、クラスCのGSL言語でしか書けません.ここは深く入りません.大切な部分だけを説明します.JavaScriptで着色器と通信できるように、いわゆる統一値uniformを使用します.例えば、例では「uniflom float time」という文を使って外部データに入力します.このデータによって、着信頂点のx、y、z座標の値が変わります.コードセグメントは以下の通りです.
    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)));
    現在ベクトルpos Charngedに含まれる頂点の新しい座標は、着信するtime変数によって計算されます.最後に、この新しい座標をthree.jsライブラリに送ります.コードは以下の通りです.
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position*(abs(sin(time)/2.0)+0.5),1.0);
    gl_Positionは、最終位置を返すための特別な変数です.
        次に行うのは、Shader Materialオブジェクトを作成し、このvertex ShaderをShader Materialオブジェクトに渡すことです.このために、簡単な補助関数createMaterialを作成しました.この二つのパラメータはHTMLページでスクリプトの要素IDを指しています.この関数では、私達が作成したuniforms変数が見えます.これは私達のレンダリングから発信器に情報を伝達するためのものです.ここではレンダリング関数から呼び出します. change Vetex()関数はこの目的に到達します.このchange Verstex()関数では、レンダリング毎にtime変数の値を0.01増加させます.そうすると、ブロックの頂点ごとの新しい位置を計算するために情報を私達のvertex Shader着色器に伝達します.
        また、この例を実行することによって、ブロックの各面は絶えず変化しており、各面におけるfrangement Shaderセグメント着色器がこのような変化を作り出していることがわかる.fragment Shaderのこの部分については、関連するGSL着色器言語の知識を参考にしてもいいです.これはもう完全に別の専門の技術分野に属しています.読者自身で発掘してください.
    未完次号・・・