Add support for GLSL dFdx, dFdy, and fwidth#48
Conversation
This makes use of the extension even more explicit, and avoids any possible performance overhead of attempting to enable the extension if it is not needed.
|
I just came to try use this extension in one of my shaders and found that I couldn't. Currently I am just exploring WebGL. The particular thing I was trying to do was calculate the face normals in the fragment shader for flat shading. I am using glslify to write modular glsl and use other libs from npm. In this particular case I wanted to use glsl-face-normal to calculate the normals from a position. Unfortunately this requires this extension and therefore is currently incompatible with elm. |
|
If memory serves correctly VSM shadows (low cost, soft, dynamic shadows) require standard derivatives as well. |
|
It should be possible to support this feature when we replace the glsl parser in the Elm compiler. This won't make it into Elm 0.19, but will be considered later. |
These 'standard derivative' functions are very useful for a variety of techniques such as edge detection and blurring without requiring a second rendering pass. They seem to have very good support across most browsers:
I believe this change should be safe even on browsers that don't support the extension (not sure how to test this!), since
getExtension()simply returns null if the extension is not available. Additionally, individual fragment shaders must still explicitly enable the extension by addingas the first line, so there is a strong hint to the shader writer that using these functions may not work on all browsers.
Unfortunately Elm's GLSL parser doesn't seem to recognize
#extensionas valid syntax; ideally that would be fixed in the upstream Haskell package, but in the meantime the workaround is to useunsafeShader.Update: I've added
standardDerivativesas anOptionthat must be explicitly enabled, since there's at least one report of extension-loading having measurable performance impact.As mentioned in the documentation I added for
WebGL.standardDerivatives, it's possible to detect the presence or absence of the extension using#ifdef GL_OES_standard_derivativesin the fragment shader to conditionally compile different fragment shader code (example).As far as I can tell, calling
getExtension()to attempt to enable a non-available extension (or enabling one that is then not used) has no effect other than the time taken to callgetExtension(). Shaders will only fail to compile (potential runtime error) ifdFdxetc. is used outside of an#ifdef GL_OES_standard_derivativesblock, on a browser where standard derivatives are not supported.What to do about
[glsl|...|]parsing?Right now, as mentioned above, Elm's GLSL parser doesn't recognize
#extensionlines (or even#ifdef, actually) so any shader using them has to be created withunsafeShader, which is messy. Additionally, if uniforms, attributes or varyings were added within#ifdefblocks then the inferred Elm type of the shader would change depending on the presence of the extension! Some potential solutions:#extensionand#ifdef, and disallow declaration of uniforms, attributes or varyings inside an#ifdef. Most flexible, but requires the most work. (This is the 'perfect world' that the currentWebGL.standardDerivativesdocumentation text assumes...)StandardDerivativesoption has been enabled. This way the shader writer doesn't have to remember to add the#extensionline to their shaders (just callWebGL.toHtmlWithwithWebGL.standardDerivativesas one of the options, then go ahead and start usingdFdxetc.). Since the GLSL parser also doesn't seem to support#ifdef, I think in this case the approach would be "if you want to usedFdxand friends, just realize that it may not work cross-browser". (It seems to me, though, that for practical purposes it's pretty safe to assume that the extension is available anywhere that WebGL is.) If people really want to support both cases, then there's alwaysunsafeShader...