So, I am trying to port this sample to jogl.
Kind of ironic because he is using compute shaders with deprecated opengl, but anyway, I'd like to emulate that.
He sets light:
ambient
diffuse
specular
cut-off
exponent
Material:
ambient
diffuse
specular
shininess
emission
I found an almost perfect link, where all the parameters he sets are cited, but one, the material emission
I also found another nice link where I can see all the default values for the fixed pipeline and I am going to use them to set what he doesn't.
So, where (and how) shall I insert the material emission in the function?
Edit: for the undervoter, I find it hard being more clear and explicit than the question above, maybe if you tell me what you did not comprehend I can try to help you, but you should have some basic notions about opengl and lighting first in order to get it
The emission color is similar to the ambient color, in the sense that both of them are used for terms that are independent of the light/normal directions.
The overall lighting calculation can be expressed as a sum of different terms:
emission + ambient + diffuse + specular
The difference between emission and ambient is:
The material emission color is used directly as a term in the overall lighting calculation.
The material ambient color is multiplied with the light model ambient color, and the ambient colors of each active light source. These terms are then all summed up to obtain the overall ambient contribution.
For details, check out the section "The Mathematics of Lighting" in the Red Book, which is available for free online (direct link to the section).
Related
I am facing a problem, My specular lighting is also coloured.. In my code I have mentioned,
LightColor = ambient+diffuse+specular;
FragColor = BodyColor * LightColor;
//My specular light appears in the same color as that of body. Can somebody help me to fix this?
Of course it is the same color as the body - because you're doing a component-wise multiplication of BodyColor against LightColor. That means the specular highlight is influenced by the body color just as much as the diffuse and ambient are, which is obviously not what you want.
For example, if BodyColor is [1.0 0.0 0.0], aka red (let's ignore alpha for argument's sake), and the combined light color is [0.8 0.8 0.8], aka light gray, then:
FragColor = [1.0 0.0 0.0] * [0.8 0.8 0.8] = [0.8 0.0 0.0]
Which is not-quite-full red.
You can never escape the output being based upon the body color with the math you have. At least, without going through a convoluted division, and even then, it won't work with zero components.
There are a number of solutions to your problem, of varying degrees of accuracy, but the simplest (and what it seems you are trying to do) is to multiply the body by the combined lighting except specular, and add specular:
FragColor = BodyColor * (LightDiffuse + Ambient) + LightSpecular;
Specular lighting represents a fundamentally different phenomena than diffuse/ambient: it is the light bounced off of the surface, or out of a thin layer at the surface (as colored specular usually represents). As such, it should not be multiplied against the color of the body. It might be multiplied against a separate surface specular color, but usually is not.
You still need some rather complex linear algebra to arrive at the LightSpecular term, since it is not applied flat to the surface, but depends upon the angle of the camera to the object and from the object to the light. Since you didn't ask, I am assuming you have that; although since you probably don't, I will suggest that there are many pages about that topic all over the internet.
I've got an issue with changing the specular power component in my opengl 4.3 shader. What happens is the specular is working fine when I use a shininess value of between 0-10, however, as the value is increased to make the material more shiny, the lighting decreases in intensity. Here is my code:
//Direct Lighting
vec3 L = normalize(worldPos.xyz - lightPos.xyz);
vec3 D = normalize(lightDir.xyz);
float dist = length(-L);
float I = max(dot(N.xyz, -L), 0.0);
vec3 h = normalize(-L.xyz + E);
float specLighting = 0.0;
specLighting = pow(max(dot(N.xyz, h), 0.0),50.0);
fColor.xyz = vec3(specLighting);
So if increase the shininess value to something like 50, there is no lighting at all. By the way, in this code, I am only displaying specular to debug the problem.
[EDIT]
Sorry for the lack of detail in the explanation, I have attached some screenshots of the results of changing the specular shininess value from 1 to 7. As you can see, as the specular highlight reduces in size (which is what I want), the lighting also fades (which is not what I want). It gets to the point where after about 10, it becomes completely black.
By the way, I am doing this entirely in the pixel/fragment shader.
I have also added a screenshot from my directx 11 test engine using the exact same code for specular lighting but with a shininess factor of 100.
Directx 11:
If you want to maintain a minimal lighting-based illumination, you should add a non-specular compenent. The specular component is typically used to add highlights to a material, not as the sole contributor.
Anyway, the darkening you report is a natural result of increasing the exponent. Think about it: because the vectors are pre-normalized, dot(N.xyz, h) is no more than 1.0. Raising a number between 0 and 1 to a high power will naturally tend to make the result very small very quickly... which is exactly what you want for a sharp specular highlight!
Of course, reducing the size of the highlight will reduce the average specular reflection (unless you made the maximum specular value much brighter, of course...). But, very few actual objects have only specular reflection. And, if an object did have only specular reflection, it would look very dark except for the specular spots.
Another way to look at it: your formula gives you a specular brightness whose maximum value is 1.0 (which is in some ways practically convenient for conventional, low-dynamic range computer graphics where each color channel maxes out at 1.0). However, in the real world, a shinier surface will typically cause the specular highlights to get brighter as well as smaller, such that the average specular brightness stays the same. It is the contrast between these to cases which makes the situation confusing. For practical purposes the formula is "working as designed -- will not fix"; typically, the artist will simply adjust the specular exponent and brightness until he gets the appearance he wants.
Thanks for all your help guys,
It turned out that it was just a silly mistake in the vertex shader:
instead of:
fNorm = vec4(mat3(worldSpace)*vNorm.xyz,0);
I had just:
fNorm = vNorm;
I originally wrote this answer before the question was updated with enough information. So it's obviously not the right answer in this case, but may apply to someone with a similar problem...
One possible explanation as to why specular lighting would decrease in intensity with increasing power, is if you are calculating it at a vertex level, rather than per-pixel. If the highlight point happens to fall in the middle of a polygon, rather than right at a vertex, then as it decreases in size with increasing shininess, the vertex contributions will drop off rapidly, and the highlight will disappear. Really for good specular (and really for good lighting generally), you need to calculate per-pixel, and only interpolate things that actually vary smoothly across the polygon, such as position or normal.
If you increase the "shininess" you're material will be less shiny.
I have implemented PSSM (Parallel-Split Shadow Map) for my RPG. It uses only the "sun" (one directional light high above.
So my question is, is there a special technique to add say max 4 omni-directional lights to the pixel shader?
It would work somewhat along these lines :
At the shadowmap application (or maybe at its creation):
if in light: do as usual
else: check if any light is close enough to light this pixel (and if, don't shadow it).
Maybe this can even be done in the shadowmap generation (so filtering will be applied to those omni lights too)
Any hints or tips warmly welcomed!
The answer to this question is so obvious that the question itself suggests that you've gone too far into the hacks of 3D graphics and need to remember what all of this is actually supposed to be doing.
A shadowmap is a way to tell whether a particular location on a surface is in shadow relative to a particular light in the scene. The shadowmap answers the question, "Is there something solid between the point on the surface and the light source?"
If the answer to this question is "yes", then that light source does not contribute to the lighting computations for that point. If the answer is "no", then it does.
The color of a point on a surface is based on the incoming light from all light sources and the surface characteristics of that point on the surface (diffuse color, specular shininess, normal, etc). All of the computations from each light add into one another to produce the final color value that the point represents.
You generally also have various hacks. The ambient term is often used to represent lots of indirect illumination. Light maps can take the place of light from other sources that you're not computing dynamically in the shader. And so on. But in the end, they are all just lights.
Your lighting equation takes the light parameters (color, direction/position, or just the ambient intensity for the ambient light) and the surface characteristics (as stated above), and produces the quantity of light reflected from the surface. Since the reflectance from one light is not affected by the reflectance from other lights, you can compute this independently for each light.
All of these values are added together to produce the final value.
The fact that you can short-circuit the computation of one of these via a shadowmap test is irrelevant to the overall scheme. Just add the various lighting terms to one another, and that's your answer. There is no "special technique" to doing this; you just do it.
From graphics view, is material just the the images applying to geometric object?
We can define material as a set of data which describes how a surface reacts to light.
In the Phong-Blinn shading model, the material is defined by several sets of data:
(rgb) ambient - (see below)
(rgb) diffuse - how strongly it diffuses the incoming light of a given color
(rgb) specular - how well it reflects the incoming light of a given color
(number) shininess - how perfect (how small and focused) is the reflection. Bigger value = smaller "shining spot".
The ambient value is just added to the final color - it is there to emulate "secondary light reflections". It's usually set to the same hue as diffuse, but usually of smaller intensity.
By balancing ambient/diffuse/specular/shininess parameters, you may make the surface resemble different real-world materials.
Also, those parameters may be defined either per-vertex or per-pixel (as a texture). It is common to take the values of ambient and diffuse from a colourful texture and specify constant specular and shininess, but you also could have 3 different textures for ambient, diffuse and specular colours - in order to simulate a sophisticated material which reflects the light in different way depending on the position.
There might be more parameters involved depending on what effects you want to use, for example an additional value for glowing surfaces, etc.
Material usually refers to the colour of the geometric object, while the image is the texture. The material will specify how the object reacts to ambient and direct lighting, it's reflectance, transparency etc.
They can be combined in various ways to produce different effects.
For example the texture might completely override the material so that the underlying colour has no effect on the final scene.
In other cases the texture might be blended with the material so that the same texture effect can be applied to different objects (red car, blue car etc.).
I think this is an extremely stupid and newbie question, but then I am a newbie in graphics and openGL. Having drawn a sphere and put a light source nearby, also having specified ambient light, I started experimenting with light and material values and came to a surprising conclusion: the colors which we specify with glColor* do not matter at all when lighting is enabled. Instead, the equivalent is the material's ambient component. Is this conclusion correct? Thanks
If the lighting is enabled, then instead of the vertex color, the material color (well, colors - there are several of them for different types of response to light) is used. Material colors are specified by glMaterial* functions.
If you want to reuse your code, you can use glEnable(GL_COLOR_MATERIAL) and glColorMaterial(GL_AMBIENT_AND_DIFFUSE) to have your old glColor* calls mapped to material color automatically.
(And please switch to shaders as fast as possible - the shader approach is both easier and more powerful)
I suppose you don't use fragment shader yet. From glprogramming.com:
vertex color =
the material emission at that vertex +
the global ambient light scaled by the materials ambient
property at that vertex +
the ambient, diffuse, and specular contributions from all the
light sources, properly attenuated
So yes, vertex color is not used.
Edit: You can also look for GL lightning equation in GL specification (you have one nearby, do you? ^^)