8 ms·
This is pretty cool. I've written a couple of toy ray tracers, but always in a language that runs on a CPU, so it's interesting to see how you would do it on a
by ThatOtherPerson 10y ago
This is pretty cool. I've written a couple of toy ray tracers, but always in a language that runs on a CPU, so it's interesting to see how you would do it on a GPU. And I noticed that this is from the Ken Perlin, which is cool - I'm mostly just used to seeing his name as the "Perlin" in Perlin noise.
There's one thing I'm curious about - does anyone know why he's taking the square root of the color to produce the final pixel color?
- Keyframe 10y agodoes anyone know why he's taking the square root of the color to produce the final pixel color? Probably to approximate gamma correction without getting too involved.
- ThatOtherPerson 10y agoI thought about that, but some of the results I found on Google suggest that output from WebGL shaders is supposed to be in a linear color space [0] [1]. Then again, some of the comments here [2] suggest that you do have to do gamma correction manually. Incidentally, I didn't know to do gamma correction until I came across [3], which explained why the output from my raytracers always looked a little off ;) [0] http://stackoverflow.com/questions/10843321/should-webgl-shader-output-be-adjusted-for-gamma http://stackoverflow.com/questions/10843321/should-webgl-sha... [1] https://www.khronos.org/webgl/public-mailing-list/archives/1009/msg00018.php https://www.khronos.org/webgl/public-mailing-list/archives/1... [2] https://www.shadertoy.com/view/Xdl3WM https://www.shadertoy.com/view/Xdl3WM [3] http://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-about-gamma/ http://blog.johnnovak.net/2016/09/21/what-every-coder-should...
- Keyframe 10y agoI have absolutely no experience with WebGL, so I have no idea. Sqrt would diminish intensity in highlights, if nothing else. So, in that way it would seem to be an approximation of gamma correction. I'd have to see the result (can't on tablet).
- sheltron 10y agoIf you load a texture like from a JPEG and use that in a shader, the texture is converted to gamma space when loaded, so you need no correction. If you are generating colors in the shader, you will need to correct for gamma. GL does have the capability to handle linear color space buffers correctly, but you have to enable SRGB, and initialize the framebuffer correctly with SRGB color space, and I'm not sure if GLES (WebGL) can do this.
- ThatOtherPerson 10y agoWhat happens if you need to alter the color of a texture that's been loaded? For example, if you want to do diffuse shading on a sphere with a texture mapped to it. Do you first need to convert the texture pixel back to linear space, apply the shading, and then correct for gamma?
- tomjakubowski 10y agoI believe that, in WebGL, if you sample the texture in a shader the resulting color is in a linear space. And output colors from a fragment shader are meant to be linear as well. I realize now that I can't fully answer your question, because I'm unsure whether WebGL implementations are supposed to respect color correction information in the image file format. But I'm pretty sure that the color space in WebGL "shader land" is always linear.
- upops 10y agoTry it without `sqrt(c)`! It adds a bit of ambient lighting so you can see the sphere when the light is added in. Without it, the dark side of the sphere fades into the background.
- duncan-donuts 10y agoI wonder if taking the square root of the color inverts the original color. I also wonder why he is taking the square root and don't know why.
- Keyframe 10y agoNah, you'd subtract your color from white in order to get negative. This would diminish original. Sqrt is there for poorman's gamma.
- deleted 10y ago[deleted]
- sheltron 10y agoGamma correction is achieved by raising the color to a power, the power being the gamma value. So sqrt is the same as gamma correction with gamma = 2.0; On typical monitors, gamma is 2.2 , so this is close and maybe faster if the GPU has optimizations for fast square root. More info : http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html
- deleted 10y ago[deleted]
- Impossible 10y agoHe's assuming lighting is in linear space and doing gamma correction at the end of the shader. Sqrt is a faster approximation of pow(c,1.0/2.2). I first saw this trick in writing in this article (by the co-creator of shader toy). http://www.iquilezles.org/www/articles/outdoorslighting/outdoorslighting.htm http://www.iquilezles.org/www/articles/outdoorslighting/outd.... For reasons why linear space lighting is important read (http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html) The gist of it is gamma space lighting tends to look unnatural and blown out, and it becomes more of a problem the more math you do in the lighting (adding specular, multiple lights, etc.)
- deleted 10y ago[deleted]
- darkmighty 10y agoA small note, linear space lightning is important because the lightning equations are linear equations with respect to physical quantities (unless you specifically introduce materials with non-linear response, which are quite rate). So simply intensity(pixel)=intensity(pixel illuminated by source 1)+intensity(pixel illuminated by source 2)+... It's perception that is non-linear, so you can separate it as a last non-linear step instead of always calculating perceived_intensity(pixel)=pow(x,pow(1/x,perceived_intensity(pixel illuminated by source 1))+pow(1/x,perceived_intensity(pixel illuminated by source 2))+...)
- yorwba 10y ago> It's perception that is non-linear, Since perception happens when you look at the image on your screen, applying an explicit "perception" step in rendering is actually counterproductive, since those nonlinearities would compound. Gamma correction is used to allow for better contrast resolution for the brightness levels where the eye is most sensitive, when you have to compress your color values down to 8 bits per channel. The display then inverts this to produce ordinary linear space intensities.
- 10y ago
- jharger 10y agoIf you're interested in GPU ray tracing, I played with nVidia's OptiX a few years. It was a fun (and pretty easy, IIRC) way to do it on a GPU (nVidia anyway). https://developer.nvidia.com/optix https://developer.nvidia.com/optix
- VMG 10y agoKen Perlin has an interesting collection of Java applet based graphics demos that is rapidly falling into obsolescence https://cs.nyu.edu/~perlin/ https://cs.nyu.edu/~perlin/
- Silhouette 10y agoIt's not that those demos are obsolete, just that browsers and Oracle have screwed up Java so much that access to this kind of resource is being lost. :-(
- gavanwoolery 10y agoSquare rooting the color is a trick I have used for ages, but I have not frequently seen it elsewhere. It will do pretty much the opposite of multiplying the color by itself - i.e. decrease the contrast and produce a "softer" color space still in the 0-1 range. In general, you can produce a variety of interesting color-space transformations with simple math on the current fragment, as opposed to more complex methods that rely on sampling output, like HDR processing. Here is a page on more advanced color space manipulation: http://filmicworlds.com/blog/linear-space-lighting-i-e-gamma/ http://filmicworlds.com/blog/linear-space-lighting-i-e-gamma...
- panic 10y agoPaste this into the editor to see the difference: varying vec3 vPos; float sRGB(float x) { if (x <= 0.00031308) return 12.92 * x; else return 1.055 * pow(x, 1./2.4) - 0.055; } void main() { float v = (vPos.y + 1.) / 2.; if (vPos.x < -0.5) gl_FragColor = vec4(pow(v, 1./2.2)); // 2.2 Gamma else if (vPos.x < 0.0) gl_FragColor = vec4(sRGB(v)); // sRGB else if (vPos.x < 0.5) gl_FragColor = vec4(sqrt(v)); // sqrt approximation else gl_FragColor = vec4(v); // unadjusted } The sqrt() function adjusts for the output curve of your display (usually sRGB nowadays, but in the past various gamma values have been used). The strips on the left should have an approximately linear gradient between light and dark, whereas the rightmost gradient will be too dark. The question of why your display doesn't just output linear colors is more interesting. Small differences in dark colors are more easily perceived than differences in lighter colors, so it's useful to spend more encoding space on the low end. With more bits, you could use linear colors throughout, but all color data would take up proportionally more memory. It ends up more efficient to just decode from sRGB, do your computation, and encode into sRGB again each time. Modern graphics APIs can automate this sRGB coding for you by letting you specify an sRGB format for textures: each time you read from an sRGB texture, the system will decode the color into linear space, and all writes will automatically encode back into sRGB.
- nightcracker 10y agoWebGL + GLSL should already adjust this for you, giving a linear colorspace. Notice that 'unadjusted' actually looks correct (at least on my browser, Chrome @ Linux).
- yoklov 10y agoShould as in "it would be nice"? Maybe. Should as in it does already and this sort of thing is unnecessary? Definitely not. Hence EXT_sRGB.
- nightcracker 10y ago
- jwatte 10y agoSquare root of color sounds like gamma encoding. He had a linear color, and wants to store it as sRGB; raising it to 1/2.2 is "correct" but sqrt is close enough. (Or it's just for tone mapping.)