|
|
Help with basic lighting shader in opengles
Hi everybody.
I'm learning lighting in opengles, and I'm posting here because I want to be
sure that I pass to the shader the correct uniform matrices and other
parameters.
So far I've got in my C++ code (I use the glm math header only library):
glm::mat4 projectionMatrix; // the camera projection matrix
glm::mat4 modelviewMatrix; //the camera modelview (i.e.
gluLookAt(...))
glm::mat4 modelMatrix; // this is my object's modelview matrix
(i.e. I can render my object without lighting if I pass to a basic vertex
shader the single matrix: "mp = projectionMatrix * modelviewMatrix *
modelMatrix")
glm::vec3 lightPosInWorldSpace;
OK, this is what I got in my C++ code.
Now my lighting shader needs these uniforms (I will use the leading u_
notation here):
mat4 u_projectionMatrix; // some versions get the full
modelviewprojectionMatrix here...
mat4 u_modelviewMatrix;
mat3 u_normalMatrix;
vec3 u_lightPosInEyeSpace;
From now on I'm not 100% sure of what I'm doing; please check CAREFULLY if
it's correct:
-----------------------------------------------------------------------------
C++ -> VERTEX
SHADER
------------------------------------------------------------------------------
projectionMatrix -> u_projectionMatrix (or in some versions:
projectionMatrix * modelviewMatrix * modelMatrix ->
modelviewprojectionMatrix )
modelviewMatrix*modelMatrix -> u_modelviewMatrix
((modelviewMatrix*modelMatrix )inverse)transpose -> u_normalMatrix
vec3((modelviewMatrix*modelMatrix)*vec4(lightPosInWorldSpace,0.0)) ->
u_lightPosInEyeSpace
My questions:
1) Is this correct ? I've read a lot of articles (and a book) about it, and
none of them showed how to assign the shader uniforms in a clear and
concise way.
Now I got two more questions:
2) when using a directional light (glm::vec3 lightDirInWorldSpace) how do I
transform it in eye space ? My guess:
((modelviewMatrix*modelMatrix )inverse)transpose *
ghtDirInWorldSpace -> u_lightDirInEyeSpace (provided the assignments
above are correct, which I'm not too sure of)
3) I've read that when u_modelviewMatrix has no scaling at all inside it,
or just uniform scaling, it can be: u_normalMatrix =
mat3(u_modelviewMatrix ) (I don't know if this compiles
in the shader, it does in C++ with glm).
Furthermore if no scaling at all is present, the normalization used in the
vertex shader for lighting calculation can be avoided.
So I ask: is it possible to pass such a scaling (or better its inverse) as a
vec3 uniform to the vertex shader and to apply it later (i.e. always using
u_normalMatrix = mat3(u_modelviewMatrix ) and
no normalization at all)?
Most likely the answer should be negative, otherwise this faster procedure
would have become a standard already...
Thanks in advance for your answers/contributions
|
|
0
|
|
|
|
Reply
|
writeme7597 (2)
|
8/15/2012 7:54:13 AM |
|
Just to say that I've changed my mind about how to calculate
u_lightPosInEyeSpace: it should be:
vec3((cameraModelviewMatrix)*vec4(lightPosInWorldSpace,0.0)) ->
u_lightPosInEyeSpace,
so that it's not object-dependent.
I've also found on the web
(http://www.learnopengles.com/android-lesson-two-ambient-and-diffuse-lighting/)
a well commented vertex shader,
that I have further modified in this way (the fragment shader is trivial):
uniform mat4 u_MVPMatrix; // A constant representing the combined
model/view/projection matrix.
uniform mat4 u_MVMatrix; // A constant representing the combined
model/view matrix.
uniform vec3 u_MVMatrixScaleInverse; // To be tested. default (1,1,1). Note
that the scale usually refers to the model matrix only, since the view
matrix is usually orthonormal (gluLookAt(...) and similiar are OK)
uniform vec3 u_LightPos; // The position of the light in eye space
(vec3(view matrix * vec4(lightPosInWorldSpace,0) AFAIK).
uniform float u_LightAttenuationFactor; // Maybe it can be inglobed into
u_LightPos.w. default 0.25 (or simply 0.0 = no attenuation)
attribute vec4 a_Position; // Per-vertex position information we will
pass in.
attribute vec4 a_Color; // Per-vertex color information we will pass
in.
attribute vec3 a_Normal; // Per-vertex normal information we will pass
in.
varying vec4 v_Color; // This will be passed into the fragment
shader.
void main() // The entry point for our vertex shader.
{
vec3 modelViewVertex = vec3(u_MVMatrix * a_Position); // Transform
the vertex into eye space.
vec3 modelViewNormal = vec3(u_MVMatrix * vec4(a_Normal,
0.0))*u_MVMatrixScaleInverse; // Transform the normal's orientation
into eye space and (to be tested) correct scaling errors.
float distance = length(u_LightPos - modelViewVertex); // Will be
used for attenuation. (slow IMO: refactor code using length2 if available,
since "distance * distance" is used)
vec3 lightVector = normalize(u_LightPos - modelViewVertex); // Get a
lighting direction vector from the light to the vertex.
// 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(modelViewNormal, lightVector), 0.1);
diffuse = diffuse * (1.0 / (1.0 + (u_LightAttenuationFactor * distance *
distance))); // Attenuate the light based on distance.
v_Color = a_Color * diffuse; // Multiply the color by the
illumination level. It will be interpolated across the triangle.
// gl_Position is a special variable used to store the final position.
// Multiply the vertex by the matrix to get the final point in normalized
screen coordinates.
gl_Position = u_MVPMatrix * a_Position; // Some versions of this shader
replace u_MVPMatrix with u_ProjectionMatrix, and multiply it with a vec4
modelViewVertex (see first line of the shader).
// This could be faster, because u_MVPMatrix does not need to be
calculated in the C++ code anymore...
}
I still have to test it: hope it works.
Feel free to post comments/suggestions about it...
|
|
0
|
|
|
|
Reply
|
writeme7597 (2)
|
8/15/2012 2:04:27 PM
|
|
|
1 Replies
59 Views
(page loaded in 0.07 seconds)
|
|
|
|
|
|
|
|
|