Custom Opal Shader - Part 2
Progress
As it turns out, there has been some work done in computer graphics to replicate the form of diffraction found in CDs and DVDs using custom shaders. The work was originally published in GPU Gems and it is available here. Adaptations of the code are also available elsewhere. For example, it has been converted for use in Unity by Alan Zucconi, who wrote a great tutorial on implementing the shader and understanding the math behind it. This tutorial can be found here. Zucconi’s version is a surface shader in Unity while the original version relies on only vertex shader to achieve the effect.
With all of that in mind, there is still a big difference between the visual appearance of diffraction seen in optical media like CDs and the appearance of a high-quality opal. In terms of physics, the main difference is that diffraction in optical media comes from a uniform diffraction grating, whereas the play-of-color in opals is produced by non-uniform volume diffraction. Simulating volume diffraction is a more advanced subject that likely requires volume textures, parallax effects, and/or ray tracing to produce truly accurate results. Therefore, I have decided to opt for a surface-only approximation of the effect for the time being.
While I was early in the process of adapting the shader to create the opal effect, I created a version of the shader that created some interesting results, albeit not the results I was looking for. The video below shows one of the early iterations of the mapped diffraction which creates an interesting prismatic effect here.
To achieve this, I started by making some tweaks to Zucconi’s version of the shader to fix a few minor issues and make it map slightly better onto surfaces other than planes and flat disks. Then I began reworking it to make use of some additional textures that are used to create the opal effect (including opal-normals and opal-tangents that factor into how my shader attempts to simulate the non-uniform diffraction model). I also made changes to how the diffraction calculation is performed when the light and camera are both directly in front of the object. Originally this would cause the diffraction color to disappear, but many opals still display play-of-color under these conditions, so, in my opinion, this produces better results for my purposes.
The following video shows a short demo of the shader in action. In this case, I configured the settings and the texture maps to produce an effect that is relatively similar to the actual opal from the previous post. However, the most notable difference is that the base color is definitely too dark to match it accurately. This is likely caused by how the opal color (diffraction) is layered on top of the standard shader. This is something that I am currently investigating a fix for.
At the moment, I am layering the diffraction coloring on top of the base PBR calculated color/reflection, but this is not creating the level of glossy finish that polished opals have. I have tried manually running the PBR lighting calculations after calculating diffraction, but I was getting strange results that ruined the coloration, so I have reverted to the lighting model shown here. For the time being, I am using a simple lambert-style lighting calculation to shade out the diffraction on the sides that are not lit by the light. This of course ignores GI and only handles a maximum of one light at a time. The next major improvement that I plan to make is figuring out how to correctly layer the opal color and the outputs from the standard lighting functions such as BRDF.
Other future work includes:
- Adding some additional variations of the opal maps to try to achieve even more realistic patterns.
- Trying out a color ramp that determines the range of diffracted color instead of the runtime color function.
- Testing out multi-layered objects with partial transparency to try to simulate the depth-effect that crystal opal often has.
Overall, I think that my work on this shader has made significant progress toward a realistic model for the play-of-color in opals. That being said, I want to continue to make these improvements and experiment with some changes in hopes of perfecting the shader. Stay tuned for updates!