为了赚点金币,转载我曾今写一篇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的教程,希望大家能喜欢。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!