From: Bruce S. <bas...@un...> - 2003-09-08 02:41:13
|
Dave Scherer explained to me why my grayscale calculations gave very dark scenes. I've put his gamma-correction formula (the second one given below) into the grayscale.py program found in the Contributed Programs at http://vpython.py. Here are his comments: ----------------------------------------- The problem is monitor gamma. I had forgotten that we had not already addressed this issue. For silly historical reasons, PC monitors have a "gamma" of approximately 2.5. This means that framebuffer intensity values are not proportional to the luminance of the monitor. For a color (r,g,b), the monitor is actually emitting light energy approximately proportional to (r**2.5, g**2.5, b**2.5). This means that (1,1,1) is not just twice as bright as (0.5, 0.5, 0.5), but more than 5 times brighter! This is not a huge problem for many of the things people do with computers, because color values are chosen by hand anyway (so all that matters is that everyone uses the same color space, which is very roughly true across PCs. Historically, however, Macs have used a gamma of 1.8 instead.) It is a big problem for 3D graphics, because it makes *all* lighting and blending calculations nonphysical unless they are specifically gamma corrected, which is expensive and can't be done in hardware (except after the framebuffer, see below). To apply this to your calculation, the color (1,0,0) is really being rendered as (.009, 0,0) instead of (.15, 0, 0). That is indeed very dark! It is possible to correct for this problem as far as your specific calculation goes: GAMMA = 2.5 s = ( .15 * r**GAMMA + .55 * g**GAMMA + .30 * b**GAMMA ) ** (1/GAMMA) Or, with a different set of coefficients (the above is rather odd: blue is definitely darker than red): s = ( .299 * r**GAMMA + .587 * g**GAMMA + .114 * b**GAMMA ) ** (1/GAMMA) I think you will agree that this last doesn't change the brightness of a scene much. In red/blue (as opposed to red/cyan) mode, the brightness *will* change a lot because the green channel, which is the most important for luminance, is being lost. Unfortunately there is no way to precisely compensate for this. The above calculation doesn't solve all of the problems of nonlinear gamma, which makes the vertex lighting, interpolation, antialiasing, alpha blending (if we had any), and other color calculations inaccurate in the same way. The correct thing to do is to correct the monitor gamma by changing the color tables used by the video card to convert framebuffer data to analog monitor signals. This method is used by almost all full-screen 3D applications. The problem is that there is (last I checked) no widely supported way of changing the gamma in a single window, and changing the system gamma makes everything else on the screen look washed out. This is probably why we haven't dealt with this before. If you want to experiment with gamma correction, there is probably a slider in your video card properties that allows you to play with it. You should also change scene.ambient, which defaults too high for gamma correct rendering. |