Any shader wizards out there have an idea of how to achieve an oily/polluted water effect, similar to this:
Ideally, the water would not be uniformly oily, but instead the oil could be generated from some source (such as a polluting drain from a chemical plant) and then diffuse throughout the water body. My thought for this part would be to keep an "oil map" as a 2D texture that determines the density of oil at each point on the water surface. It would diffuse and move naturally with the water vel;ocity at that point (I have a wave-particle simulation for dynamic waves, and am already doing something similar for foam on the water surface). However, I'm not sure how physically correct that would be, since oil might not move at the same velocity as the water.
And I have no idea how to make all those trippy colors :-). Thoughts?
Answer
The physical basis of the colors of an oil slick is iridescence, and also related to Newton's rings. Specifically, the thickness of the oil layer is on the order of the wavelength of light. Since light reflects from both the top and bottom surface of the oil, at any given wavelength, at some angles the two reflections will be out of phase and cancel each other out; at other angles the reflections will be in phase and add together. This happens at different angles for every wavelength, so illuminating the oil with white light produces all those colors. If you illuminated it with a single frequency (e.g. laser light) you would only see a series of light and dark rings.
If you ignore refraction in the oil layer, just working out the geometry of the situation, you can find that the brightness of the reflected light for any given wavelength should vary like
sin(2.0 * pi * oilThickness / (dot(L, H) * wavelength)) * 0.5 + 0.5
Theoretically this should be integrated over all wavelengths, but in practice you can probably just do it for red, green, and blue - let's say 700, 550, and 400 nm, respectively. Changing the oil thickness will change the apparent radius of the rings of color. I would probably wrap the 2.0 * pi * oilThickness / wavelength
into a single RGB value provided to the shader as a uniform value. You could multiply it by a texture to simulate varying thickness of oil, if desired - that's probably what gives most of the interesting texture in the image above.
That produces an RGB color value that you can multiply into your BRDF. The dot(L, H)
factor would be used for point/directional lights, and you can substitute dot(N, V)
in there for applying this to an environment map reflection as well.
Disclaimer: I haven't tried this out in a shader, just drawn some diagrams and convinced myself it "should work"...so let me know the results if you do try it! :)
No comments:
Post a Comment