Reputation: 201
I've been playing with Lesson 4 of "Learn OpenGL ES 2.0" by Kevin Brothaler.
Here's its fragment shader:
precision mediump float; // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
uniform vec3 u_LightPos; // The position of the light in eye space.
uniform sampler2D u_Texture; // The input texture.
varying vec3 v_Position; // Interpolated position for this fragment.
varying vec4 v_Color; // This is the color from the vertex shader interpolated across the
// triangle per fragment.
varying vec3 v_Normal; // Interpolated normal for this fragment.
varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment.
// The entry point for our fragment shader.
void main()
{
// Will be used for attenuation.
float distance = length(u_LightPos - v_Position);
// Get a lighting direction vector from the light to the vertex.
vec3 lightVector = normalize(u_LightPos - v_Position);
// Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
// pointing in the same direction then it will get max illumination.
float diffuse = max(dot(v_Normal, lightVector), 0.0);
// Add attenuation.
diffuse = diffuse * (1.0 / (1.0 + (0.10 * distance)));
// Add ambient lighting
diffuse = diffuse + 0.3;
// Multiply the color by the diffuse illumination level and texture value to get final output color.
//===================== original
gl_FragColor = (v_Color * diffuse * texture2D(u_Texture, v_TexCoordinate));
//=====================
}
I see a light's position is defined and passed into the shader, but I don't see the light's color/intensity being defined anywhere in the source code.
How can I define the light's color/intensity and have it affect the fragment shader's output, gl_FragColor?
I don't see the light's color/intensity defined anywhere in the source code, but the program shows cubes lit by a moving light source.
Upvotes: 1
Views: 2399
Reputation: 16774
If you look close this shader uses 2 "magic" numbers:
diffuse = diffuse * (1.0 / (1.0 + (0.10 * distance)));
The .10
will effect as a linear factor depending on the distance. This value might be the first for you to convert to an uniform so you can set it from the application itself.
diffuse = diffuse + 0.3;
The 0.3
is the ambient lighting so the darkest corner of your scene is still lit 30%. This as well might be converted to an uniform.
Beside this there are a bunch of ones and zeroes which could effect the light strength. For instance the diffuse
could be multiplied by a direct light strength just before adding ambient light to it. This value does not need to be in range of [0,1].
The lighting itself is actually very hard to generate and the values you end up using make little sense if any at all:
If you look at the physics then you can specify a certain value J
which represents the strength of the spot light. What you see is a reflection of that light from the surface. So the first thing you need to do is drop the strength of the light affecting the surface by applying the distance from the light and the surface, this value drops by square distance = J/(distance*distance)
(note*). Next it is important to include how surface is turned which is defined with the normal
if the normal and the way from the point in surface to the light center (lightVector
) are facing the same direction you will get a maximum light shining. If this angle is 90 degrees or more it will have no lighting at all. This factor can be achieved with a dot product as used in your shader. Using this approach you may have only one factor that effects the light strength and that would be J
. What the issue here is that this kind of lighting would exist only in a complete vacuum, having no other objects around and even the object would have to be of such shape that it does not reflect the light to itself (a sphere would do).
That being said the standard physics procedure does not look very natural and some extra additions are required to fake the natural lighting. It is most common to add different powers then the square to the distance effect. For such parameters you should either search for some good results or experiment yourself.
Why I am telling all of this to you is because you simply have infinite ways of defining the nature of light and its strength so it is best for you to experiment or look for some other solutions online knowing that none of them is the best or correct since you simply have too little computational power to create a true light source in a computer scene.
(note*) Just to be clear about the J/(distance*distance)
: A true formula adds a constant as well since this is defined with the sphere surface area as J' = J / (4*Phi*r*r)
but the constant can be removed and added either to the light strength or the distance unit.
Also note there are other light effects you might want to consider for later shuch as the light reflection (like a mirror), already used ambient light and the most consuming art of drawing shadows.
Upvotes: 1