I am trying to apply an iridescence effect to an object. For this, I used the following shaders:
Vertex shader:
#version 300 es
uniform mat4 u_mvpMatrix;
uniform mat4 u_mvMatrix;
uniform mat4 u_vMatrix;
in vec4 a_position;
in vec2 a_textureCoordinates;
in vec3 a_normal;
out vec2 v_textureCoordinates;
out float v_CosViewAngle;
out float v_LightIntensity;
void main() {
// transform normal orientation into eye space
vec3 modelViewNormal = mat3(u_mvMatrix) * a_normal;
vec3 modelViewVertex = vec3(u_mvMatrix * a_position);
mediump vec3 eyeDirection = normalize(-modelViewVertex);
vec3 lightVector = normalize(lightPosition - modelViewVertex);
lightVector = mat3(u_vMatrix) * lightVector;
v_LightIntensity = max(dot(lightVector, modelViewNormal), 0.0);
v_CosViewAngle = max(dot(eyeDirection, modelViewNormal), 0.1);
...
}
Fragment shader:
#version 300 es
precision lowp float;
in vec2 v_textureCoordinates;
in float v_CosViewAngle;
in float v_LightIntensity;
out vec4 outColor;
uniform sampler2D s_texture;
// wave numbers for the iridescence effect: k = 2.0 * pi / wavelength (nm).
const mediump float PI = 3.141592654;
const mediump vec3 rgbK = 2.0 * PI * vec3(1.0/475.0, 1.0/510.0, 1.0/650.0);
const mediump float iridescence = 4.4;
const mediump float minThickness = 80.0;
const mediump float maxVariation = 50.0;
void main() {
float thickness = texture(s_texture, v_textureCoordinates).r
* maxVariation + minThickness; // or texture2D() - in OpenGL ES 2.0
float delta = (thickness / v_LightIntensity) + (thickness / v_CosViewAngle);
lowp vec3 color = cos(delta * rgbK) * iridescence * v_LightIntensity;
vec4 resultColor = vec4(color, 1.0);
outColor = resultColor;
}
Result:
Question: How to replace a black area with a common texture? In other words, to have a common texture instead of black color.
Note: I tryid as:
vec4 resultColor = texture(s_texture, v_textureCoordinates) * (vec4(color, 1.0) + 0.5);
And so:
if (color == vec3(0.0, 0.0, 0.0)) { // if black color
resultColor = texture(s_texture, v_textureCoordinates);
} else {
resultColor = texture(s_texture, v_textureCoordinates) * (vec4(color, 1.0) + 0.5);
}
But this did not solve the problem.
Thanks in advance!
The code of the shaders is partially taken from PVRShamanGUI.
Update: Based on the Rabbid76 answer, I also used delta, but only to check the wavelength (in nm):
...
if (delta > 1700.0 || delta < 370.0) {
resultColor = texture(s_texture, v_textureCoordinates) * v_commonLight;
} else {
resultColor = vec4(color, 1.0);
}
outColor = resultColor;
Result:
The color is not completely black, the values of the color channels is not exactly 0.0. Compute the average color (gray scale) and mix
the color and the texture color dependent on the gray scale:
vec4 texturColor = texture(s_texture, v_textureCoordinates);
float gray_scale = (color.r + color.g + color.b) / 3.0;
resultColor = mix(texturColor, color, gray_scale);
Another possibility is to mix the color dependent on the value of delta
:
vec4 texturColor = texture(s_texture, v_textureCoordinates);
resultColor = mix(texturColor, color, delta);