如何在你的H5项目中使用shaderToy上的GLSL代码

本文介绍如何把shaderToy上的案例插入到H5项目中。希望对你有用。

为了赚点金币,转载我曾今写一篇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的教程,希望大家能喜欢。

  • 发表于 2018-08-16 18:46
  • 阅读 ( 1364 )
  • 分类:Html5前端

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
不写代码的码农
快乐小球球

交互工程师

2 篇文章

作家榜 »

  1. 大北兔 15 文章
  2. 皮卡丘先生 13 文章
  3. hero 10 文章
  4. vien007 7 文章
  5. ningbnii 4 文章
  6. Even 4 文章
  7. 炸天 4 文章
  8. anlun214 4 文章