为了赚点金币,转载我曾今写一篇shaderToy和threejs结合的入门文章。至于和anniejs引擎结合上,可以使用两层canvas就可以把酷炫的shader效果整合到你的H5中。方法如下。
1、先创建一个index.html,并引入threeJs类库并创建一个空的容器:
<body> <div id="container"></div> <script src="js/three.min.js"></script> </body>
2、在three环境里初始化好场景,摄像机和渲染器,并开始渲染。
var container; var camera, scene, renderer; init(); animate(); function init() { container = document.getElementById( 'container' ); camera = new THREE.Camera(); camera.position.z = 1; scene = new THREE.Scene(); renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio( window.devicePixelRatio ); container.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); render(); } function render() { renderer.render( scene, camera ); }
3、创建一个plane,给他设置ShaderMaterial,并让他大小适合整个canvas。
var uniforms={} var geometry = new THREE.PlaneBufferGeometry( 2, 2 ); var material = new THREE.ShaderMaterial( { uniforms: uniforms, } ); var mesh = new THREE.Mesh( geometry, material ); scene.add( mesh );
4、设置uniforms,使其和shadertoy内置的uniforms一致。
uniforms = { resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight ) }, iTime: { type: "f", value: 1.0 }, iResolution: { type: "v2", value: new THREE.Vector2() }, iMouse: { type: "v2", value: new THREE.Vector2() };
5、把iMouse以及iTime的真实值传入,并把相应的uniforms里的设置改一下。
var imouse:THREE.Vector2 = new THREE.Vector2(); window.addEventListener("touchmove", function (evt) { imouse.x = evt["touches"][0].clientX; imouse.y = evt["touches"][0].clientY; }) function render() { uniforms.iTime.value += 0.05; renderer.render( scene, camera ); }
这样我们在Three里的基础代码就部署完毕了。
6、然后,我们需要传入着色器代码。
先书写顶点着色器,可以通过<script>标签写,也可以加载外部文件,但我个人更倾向于使用glslify,这样在webpack中可以使用glslify-loader进行打包。
//顶点着色器 void main() { gl_Position = vec4( position, 1.0 ); }
这样基础框架就完成了,所有的shadertoy代码都是基于片元着色器进行书写的。因此写shadertoy就是对于片元着色器编程。
//片元着色器 uniform vec2 iResolution; uniform float iTime; uniform vec2 iMouse; void main() { vec2 st = gl_FragCoord.xy/iResolution.xy; gl_FragColor=vec4(st.x,st.y,0.0,1.0); }
把两个着色器放到material 中,我用stack.gl里的glslfy进行插入的,当然你可以用其他方式。
var vertex = require("vertex.glsl"); var frag = require('frag.glsl'); var material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: vertex, fragmentShader: frag });
如果以上部分你都对了,应该出现一个渐变的效果
如果没出来,或者跟不上我刚才说的步骤,请直接去The Book of Shaders这个网站上下载代码拷贝进html文件。
接下来,我们去shadertoy上找一个demo进行移植。就取造型函数大神 Danguafer 的作品 Shadertoy来试试吧:
第一步:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
改成
void main()
第二步:
fragCoord.xy
改成
gl_FragCoord.xy
第三步:
fragColor
改成
gl_FragColor
经过以上几步的修改,最终片元着色代码完整版是
uniform float iTime; uniform vec2 iResolution; float t=iTime; vec2 r=iResolution.xy; void main() { vec3 c; float l,z=t; for(int i=0;i<3;i++) { vec2 uv,p=gl_FragCoord.xy/r; uv=p; p-=.5; p.x*=r.x/r.y; z+=.07; l=length(p); uv+=p/l*(sin(z)+1.)*abs(sin(l*9.-z*2.)); c[i]=.01/length(abs(mod(uv,1.)-.5)); } gl_FragColor=vec4(c/l,t); }
效果出来了么?如果没有,请从下面复制完整源代码贴近html里并在http模式下从浏览器观看。记得下载three类库[https://raw.githubusercontent.com/mrdoob/three.js/dev/build/three.min.js]
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="container"></div> <script src="three.min.js"></script> <script id="vertexShader" type="x-shader/x-vertex"> void main() { gl_Position = vec4( position, 1.0 ); } </script> <script id="fragmentShader" type="x-shader/x-fragment"> uniform float iTime; uniform vec2 iResolution; float t=iTime; vec2 r=iResolution.xy; void main() { vec3 c; float l,z=t; for(int i=0;i<3;i++) { vec2 uv,p=gl_FragCoord.xy/r; uv=p; p-=.5; p.x*=r.x/r.y; z+=.07; l=length(p); uv+=p/l*(sin(z)+1.)*abs(sin(l*9.-z*2.)); c[i]=.01/length(abs(mod(uv,1.)-.5)); } gl_FragColor=vec4(c/l,t); } </script> <script> var container; var camera, scene, renderer; var uniforms; init(); animate(); function init() { container = document.getElementById('container'); camera = new THREE.Camera(); camera.position.z = 1; scene = new THREE.Scene(); var geometry = new THREE.PlaneBufferGeometry(2, 2); var imouse = new THREE.Vector2(); window.addEventListener("touchmove", function(evt) { imouse.x = evt["touches"][0].clientX; imouse.y = evt["touches"][0].clientY; }) uniforms = { resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) }, iTime: { type: "f", value: 1.0 }, iResolution: { type: "v2", value: new THREE.Vector2() }, iMouse: { type: "v2", value: imouse }}; var material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: document.getElementById('vertexShader').textContent, fragmentShader: document.getElementById('fragmentShader').textContent }); var mesh = new THREE.Mesh(geometry, material); scene.add(mesh); renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); container.appendChild(renderer.domElement); onWindowResize(); window.addEventListener('resize', onWindowResize, false); } function onWindowResize(event) { renderer.setSize(window.innerWidth, window.innerHeight); uniforms.iResolution.value.x = renderer.domElement.width; uniforms.iResolution.value.y = renderer.domElement.height; } function animate() { requestAnimationFrame(animate); render(); } function render() { uniforms.iTime.value += 0.05; renderer.render(scene, camera); } </script> </body> </html>
这篇主要是写给新人看的,如果你是前端大神你们请轻点拍砖。另外之后打算系统性的写一些关于webgl、shader以及ray-maching的教程,希望大家能喜欢。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!