debugging-glsl.html 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. Title: Debugging Three.js - GLSL
  2. Description: How to debug GLSL Shaders
  3. TOC: Debugging GLSL
  4. This site so far does not teach GLSL just like it does not teach JavaScript.
  5. Those are really large topics. If you want to learn GLSL consider checking out
  6. [these articles](https://webglfundamentals.org) as a starting place.
  7. If you already know GLSL then here are a few tips for debugging.
  8. When I'm making a new GLSL shader and nothing appears generally
  9. the first thing I do is change the fragment shader to return a solid
  10. color. For example at the very bottom of the shader I might put
  11. ```glsl
  12. void main() {
  13. ...
  14. gl_FragColor = vec4(1, 0, 0, 1); // red
  15. }
  16. ```
  17. If I see the object I was trying to draw then I know the issue is
  18. related to my fragment shader. It could be anything like bad textures,
  19. uninitialized uniforms, uniforms with the wrong values but at least
  20. I have a direction to look.
  21. To test some of those I might start trying to draw some of the inputs.
  22. For example if I'm using normals in the fragment shader then I might
  23. add
  24. ```glsl
  25. gl_FragColor = vec4(vNormal * 0.5 + 0.5, 1);
  26. ```
  27. Normals go from -1 to +1 so by multiplying by 0.5 and adding 0.5 we get
  28. values that go from 0.0 to 1.0 which makes them useful for colors.
  29. Try this with some things you know work and you'll start getting an idea
  30. of what normals *normally* look like. If your normals don't look normal
  31. then you have some clue where to look. If you're manipulating normals
  32. in the fragments shader you can use the same technique to draw the
  33. result of that manipulation.
  34. <div class="threejs_center"><img src="resources/images/standard-primitive-normals.jpg" style="width: 650px;"></div>
  35. Similarly if we're using textures there will be texture coordinates and we
  36. can draw them with something like
  37. ```glsl
  38. gl_FragColor = vec4(fract(vUv), 0, 1);
  39. ```
  40. The `fract` is there in case we're using texture coordinates that go outside
  41. the 0 to 1 range. This is common if `texture.repeat` is set to something greater
  42. than 1.
  43. <div class="threejs_center"><img src="resources/images/standard-primitive-uvs.jpg" style="width: 650px;"></div>
  44. You can do similar things for all values in your fragment shader. Figure out
  45. what their range is likely to be, add some code to set `gl_FragColor` with
  46. that range scaled to 0.0 to 1.0
  47. To check textures try a `CanvasTexture` or a `DataTexture` that you
  48. know works.
  49. Conversely, if after setting `gl_FragColor` to red I still see nothing
  50. then I have a hint my issue might be in the direction of the things
  51. related to the vertex shader. Some matrices might be wrong or my
  52. attributes might have bad data or be setup incorrectly.
  53. I'd first look at the matrices. I might put a breakpoint right after
  54. my call to `renderer.render(scene, camera)` and then start expanding
  55. things in the inspector. Is the camera's world matrix and projection
  56. matrix at least not full of `NaN`s? Expanding the scene and looking
  57. at its `children` I'd check that the world matrices look reasonable (no `NaN`s)
  58. and last 4 values of each matrix look reasonable for my scene. If I
  59. expect my scene to be 50x50x50 units and some matrix shows 552352623.123
  60. clearly something is wrong there.
  61. <div class="threejs_center"><img src="resources/images/inspect-matrices.gif"></div>
  62. Just like we did for the fragment shader we can also draw values from the
  63. vertex shader by passing them to the fragment shader. Declare a varying
  64. in both and pass the value you're not sure is correct. In fact if my
  65. shader use using normals I'll change the fragment shader to display them
  66. like is mentioned above and then just set `vNormal` to the value I want
  67. to display but scaled so the values go from 0.0 to 1.0. I then look at the
  68. results and see if they fit my expectations.
  69. Another good thing to do is use a simpler shader. Can you draw your data
  70. with `MeshBasicMaterial`? If you can then try it and make sure it shows
  71. up as expected.
  72. If not what's the simplest vertex shader that will let you visualize your
  73. geometry? Usually it's as simple as
  74. ```glsl
  75. gl_Position = projection * modelView * vec4(position.xyz, 1);
  76. ```
  77. If that works start adding in your changes a little at a time.
  78. Yet another thing you can do is use the
  79. [Shader Editor extension for Chrome](https://chrome.google.com/webstore/detail/shader-editor/ggeaidddejpbakgafapihjbgdlbbbpob?hl=en)
  80. or similar for other browsers. It's a great way to look at how other shaders
  81. are working. It's also good as you can make some of the changes suggested above
  82. live while the code is running.