看这一篇文章最好有webgl基础的同学看,如果没有webgl原生基础,你会看得很懵逼。
THREE.ShaderMaterial是Three.js库中最通用、最复杂的材质之一。通过它可以使用自己定制的着色器。直接在webgl环境中运行。着色器可以将Three.js中的JavaScript网格转换为屏幕上的像素。通过这些自定义的着色器,可以明确地指定对象如何渲染,以及如何覆盖或修改Three.js库中的默认值。
THREE.ShaderMaterial有一些前面见过的并且正常的属性如wireframe、linewidth、shading、vertexColors、fog以外,还有一些特别的属性,可以用来定制自己的着色器:
名称 | 描述 |
---|---|
fragmentShader | 这个属性是用来定义自己的片元着色器的 |
vertexShader | 这个属性是定义自己的顶点着色器的 |
uniforms | 通过这个属性可以给着色器传入uniform变量的值 |
defaultAttributeValues(原来为:attributes) | 该属性用于传递attribute变量的的值 |
defines | 转换成#define代码片段。这些片段可以用来设置着色器程序里的一些额外的全局变量 |
lights | 该属性定义光照数据是否传递给着色器,默认值为false |
var material = new THREE.ShaderMaterial( { uniforms: { time: { value: 1.0 }, resolution: { value: new THREE.Vector2() } }, attributes: { vertexOpacity: { value: [] } }, vertexShader: document.getElementById( 'vertexShader' ).textContent, fragmentShader: document.getElementById( 'fragmentShader' ).textContent } );
<!doctype html> <html lang="cn"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>ShaderMaterial案例</title> <script src="https://johnson2heng.github.io/three.js-demo/lib/three.js"></script> <script src="https://johnson2heng.github.io/three.js-demo/lib/js/libs/stats.min.js"></script> <script src="https://johnson2heng.github.io/three.js-demo/lib/js/libs/dat.gui.min.js"></script> <style type="text/css"> html, body { margin: 0; height: 100%; } canvas { display: block; } </style> </head> <body onload="draw()"> <script id="vertex-shader" type="x-shader/x-vertex"> 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); } </script> <script id="fragment-shader-1" type="x-shader/x-fragment"> 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); } </script> <script id="fragment-shader-2" type="x-shader/x-fragment"> // 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 ); } </script> <script id="fragment-shader-3" type="x-shader/x-fragment"> 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); } </script> <script id="fragment-shader-4" type="x-shader/x-fragment"> 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); } </script> <script id="fragment-shader-5" type="x-shader/x-fragment"> 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 ); } </script> <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> </body> <script> var renderer; function initRender() { renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(window.innerWidth, window.innerHeight); //告诉渲染器需要阴影效果 renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 默认的是,没有设置的这个清晰 THREE.PCFShadowMap document.body.appendChild(renderer.domElement); } var camera; function initCamera() { camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(30,30,30); camera.lookAt(new THREE.Vector3(0, 0, 0)); } var scene; function initScene() { scene = new THREE.Scene(); } //初始化dat.GUI简化试验流程 var gui; function initGui() { //声明一个保存需求修改的相关数据的对象 gui = { }; var datGui = new dat.GUI(); //将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值) } var ambientLight,spotLight; function initLight() { ambientLight = new THREE.AmbientLight(0x0c0c0c); scene.add(ambientLight); spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-40, 60, -10); spotLight.castShadow = true; scene.add(spotLight); } var cube; function initModel() { //声明一个立方体几何图形 var cubeGeometry = new THREE.BoxGeometry(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 = [meshMaterial6, meshMaterial5, meshMaterial4, meshMaterial3, meshMaterial2, meshMaterial1]; //实例化一个网格 cube = new THREE.Mesh(cubeGeometry, material); //将网格添加到场景当中 scene.add(cube); } //初始化性能插件 var stats; function initStats() { stats = new Stats(); document.body.appendChild(stats.dom); } var step = 0; function render() { cube.rotation.y = step += 0.01; cube.rotation.x = step; cube.rotation.z = step; cube.material.forEach(function (e) { e.uniforms.time.value += 0.01; }); renderer.render(scene, camera); } //窗口变动触发的函数 function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); render(); renderer.setSize(window.innerWidth, window.innerHeight); } function animate() { //更新控制器 render(); //更新性能插件 stats.update(); requestAnimationFrame(animate); } function draw() { initGui(); initRender(); initScene(); initCamera(); initLight(); initModel(); initStats(); animate(); window.onresize = onWindowResize; } //创建ShaderMaterial纹理的函数 function createMaterial(vertexShader, fragmentShader) { var vertShader = document.getElementById(vertexShader).innerHTML; //获取顶点着色器的代码 var fragShader = document.getElementById(fragmentShader).innerHTML; //获取片元着色器的代码 //配置着色器里面的attribute变量的值 var attributes = {}; //配置着色器里面的uniform变量的值 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(window.innerWidth, window.innerHeight)} }; var meshMaterial = new THREE.ShaderMaterial({ uniforms: uniforms, defaultAttributeValues : attributes, vertexShader: vertShader, fragmentShader: fragShader, transparent: true }); return meshMaterial; } </script> </html>