着色器

SpriteJSNext的3D扩展预置了一些默认的着色器,能够方便开发者快速创建应用。

这些预置着色器定义在这个文件里

包括:

  • NORMAL 一个简单的根据法向量来确定表面颜色的着色器,主要用于测试
  • NORMAL_GEOMETRY 支持光照、表面颜色的通用着色器,一般的几何元素可以使用它
  • NORMAL_TEXTURE 支持光照、纹理的通用着色器,带纹理的几何元素可以使用它
  • GEOMETRY_WITH_TEXTURE 支持光照、表面颜色和纹理的通用着色器,半透明纹理的几何元素可以使用它
  • GEOMETRY_WITH_SHADOW 支持光照、表面颜色和阴影的通用着色器
  • TEXTURE_WITH_SHADOW 支持光照、纹理和阴影的通用着色器
  • GEOMETRY_WITH_TEXTURE_AND_SHADOW 支持光照、表面颜色、纹理和阴影的通用着色器
  • TEXTURE_CUBE 支持立方体纹理的通用着色器

这些着色器我们都可以根据情况直接用,例如:

  1. const program = layer.createProgram({
  2. ...shaders.GEOMETRY_WITH_SHADOW,
  3. cullFace: null,
  4. texture,
  5. });

当然我们也可以用自己定义的着色器,比如:

  1. const {Scene} = spritejs;
  2. const {Cube, shaders} = spritejs.ext3d;
  3. const container = document.getElementById('container');
  4. const scene = new Scene({container});
  5. const layer = scene.layer3d('fglayer', {
  6. camera: {
  7. fov: 35, // 相机的视野
  8. pos: [3, 3, 5], // 相机的位置
  9. },
  10. });
  11. const vertex = `
  12. precision highp float;
  13. precision highp int;
  14. attribute vec3 position;
  15. attribute vec3 normal;
  16. uniform mat4 modelViewMatrix;
  17. uniform mat4 projectionMatrix;
  18. varying vec3 vNormal;
  19. void main() {
  20. vNormal = normalize(normal);
  21. gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  22. }
  23. `;
  24. const fragment = `
  25. precision highp float;
  26. precision highp int;
  27. varying vec3 vNormal;
  28. highp float noise(vec3 p) {
  29. vec3 i = floor(p);
  30. vec4 a = dot(i, vec3(1.0, 57.0, 21.0)) + vec4(0.0, 57.0, 21.0, 78.0);
  31. vec3 f = cos((p - i) * acos(-1.0)) * (-0.5) + 0.5;
  32. a = mix(sin(cos(a) * a), sin(cos(1.0 + a) * (1.0 + a)), f.x);
  33. a.xy = mix(a.xz, a.yw, f.y);
  34. return mix(a.x, a.y, f.z);
  35. }
  36. // Function from Iñigo Quiles
  37. // https://www.shadertoy.com/view/MsS3Wc
  38. vec3 hsb2rgb(vec3 c){
  39. vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), 6.0)-3.0)-1.0, 0.0, 1.0);
  40. rgb = rgb * rgb * (3.0 - 2.0 * rgb);
  41. return c.z * mix(vec3(1.0), rgb, c.y);
  42. }
  43. uniform float uTime;
  44. void main() {
  45. vec3 normal = vNormal * uTime;
  46. gl_FragColor.rgb = hsb2rgb(vec3(noise(normal), 0.5, 0.5));
  47. gl_FragColor.a = 1.0;
  48. }
  49. `;
  50. const program = layer.createProgram({
  51. vertex,
  52. fragment,
  53. cullFace: null,
  54. }, {
  55. uniforms: {
  56. uTime: {value: 0},
  57. },
  58. });
  59. const cube = new Cube(program);
  60. layer.append(cube);
  61. layer.bindTime(program, {playbackRate: 0.2});
  62. layer.setOrbit(); // 开启旋转控制

上面的代码我们定义了一个随着时间随机渐变的shader。

💡注意,layer上有一个bindTime函数,它允许我们将layer.timeline作为uTime的uniform传给对应的program,这样我们就可以方便地让shader的渲染随时间变化而变化了。