I've been trying to implement Morph Target animation in OpenGL with Facial Blendshapes but following this tutorial. The vertex shader for the animation looks something like this:
#version 400 core
in vec3 vNeutral;
in vec3 vSmile_L;
in vec3 nNeutral;
in vec3 nSmile_L;
in vec3 vSmile_R;
in vec3 nSmile_R;
uniform float left;
uniform float right;
uniform float top;
uniform float bottom;
uniform float near;
uniform float far;
uniform vec3 cameraPosition;
uniform vec3 lookAtPosition;
uniform vec3 upVector;
uniform vec4 lightPosition;
out vec3 lPos;
out vec3 vPos;
out vec3 vNorm;
uniform vec3 pos;
uniform vec3 size;
uniform mat4 quaternion;
uniform float smile_w;
void main(){
//float smile_l_w = 0.9;
float neutral_w = 1 - 2 * smile_w;
clamp(neutral_w, 0.0, 1.0);
vec3 vPosition = neutral_w * vNeutral + smile_w * vSmile_L + smile_w * vSmile_R;
vec3 vNormal = neutral_w * nNeutral + smile_w * nSmile_L + smile_w * nSmile_R;
//vec3 vPosition = vNeutral + (vSmile_L - vNeutral) * smile_w;
//vec3 vNormal = nNeutral + (nSmile_L - nNeutral) * smile_w;
normalize(vPosition);
normalize(vNormal);
mat4 translate = mat4(1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
pos.x, pos.y, pos.z, 1.0);
mat4 scale = mat4(size.x, 0.0, 0.0, 0.0,
0.0, size.y, 0.0, 0.0,
0.0, 0.0, size.z, 0.0,
0.0, 0.0, 0.0, 1.0);
mat4 model = translate * scale * quaternion;
vec3 n = normalize(cameraPosition - lookAtPosition);
vec3 u = normalize(cross(upVector, n));
vec3 v = cross(n, u);
mat4 view=mat4(u.x,v.x,n.x,0,
u.y,v.y,n.y,0,
u.z,v.z,n.z,0,
dot(-u,cameraPosition),dot(-v,cameraPosition),dot(-n,cameraPosition),1);
mat4 modelView = view * model;
float p11=((2.0*near)/(right-left));
float p31=((right+left)/(right-left));
float p22=((2.0*near)/(top-bottom));
float p32=((top+bottom)/(top-bottom));
float p33=-((far+near)/(far-near));
float p43=-((2.0*far*near)/(far-near));
mat4 projection = mat4(p11, 0, 0, 0,
0, p22, 0, 0,
p31, p32, p33, -1,
0, 0, p43, 0);
//lighting calculation
vec4 vertexInEye = modelView * vec4(vPosition, 1.0);
vec4 lightInEye = view * lightPosition;
vec4 normalInEye = normalize(modelView * vec4(vNormal, 0.0));
lPos = lightInEye.xyz;
vPos = vertexInEye.xyz;
vNorm = normalInEye.xyz;
gl_Position = projection * modelView * vec4(vPosition, 1.0);
}
Although the algorithm for morph target animation works, I get missing faces on the final calculated blend shape. The animation somewhat looks like the follow gif.
The blendshapes are exported from a markerless facial animation software known as FaceShift.
But also, the algorithm works perfectly on a normal cuboid with it's twisted blend shape created in Blender:
Could it something wrong with the blendshapes I am using for the facial animation? Or I am doing something wrong in the vertex shader?
--------------------------------------------------------------Update----------------------------------------------------------
So as suggested, I made the changes required to the vertex shader, and made a new animation, and still I am getting the same results.
Here's the updated vertex shader code:
#version 400 core
in vec3 vNeutral;
in vec3 vSmile_L;
in vec3 nNeutral;
in vec3 nSmile_L;
in vec3 vSmile_R;
in vec3 nSmile_R;
uniform float left;
uniform float right;
uniform float top;
uniform float bottom;
uniform float near;
uniform float far;
uniform vec3 cameraPosition;
uniform vec3 lookAtPosition;
uniform vec3 upVector;
uniform vec4 lightPosition;
out vec3 lPos;
out vec3 vPos;
out vec3 vNorm;
uniform vec3 pos;
uniform vec3 size;
uniform mat4 quaternion;
uniform float smile_w;
void main(){
float neutral_w = 1.0 - smile_w;
float neutral_f = clamp(neutral_w, 0.0, 1.0);
vec3 vPosition = neutral_f * vNeutral + smile_w/2 * vSmile_L + smile_w/2 * vSmile_R;
vec3 vNormal = neutral_f * nNeutral + smile_w/2 * nSmile_L + smile_w/2 * nSmile_R;
mat4 translate = mat4(1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
pos.x, pos.y, pos.z, 1.0);
mat4 scale = mat4(size.x, 0.0, 0.0, 0.0,
0.0, size.y, 0.0, 0.0,
0.0, 0.0, size.z, 0.0,
0.0, 0.0, 0.0, 1.0);
mat4 model = translate * scale * quaternion;
vec3 n = normalize(cameraPosition - lookAtPosition);
vec3 u = normalize(cross(upVector, n));
vec3 v = cross(n, u);
mat4 view=mat4(u.x,v.x,n.x,0,
u.y,v.y,n.y,0,
u.z,v.z,n.z,0,
dot(-u,cameraPosition),dot(-v,cameraPosition),dot(-n,cameraPosition),1);
mat4 modelView = view * model;
float p11=((2.0*near)/(right-left));
float p31=((right+left)/(right-left));
float p22=((2.0*near)/(top-bottom));
float p32=((top+bottom)/(top-bottom));
float p33=-((far+near)/(far-near));
float p43=-((2.0*far*near)/(far-near));
mat4 projection = mat4(p11, 0, 0, 0,
0, p22, 0, 0,
p31, p32, p33, -1,
0, 0, p43, 0);
//lighting calculation
vec4 vertexInEye = modelView * vec4(vPosition, 1.0);
vec4 lightInEye = view * lightPosition;
vec4 normalInEye = normalize(modelView * vec4(vNormal, 0.0));
lPos = lightInEye.xyz;
vPos = vertexInEye.xyz;
vNorm = normalInEye.xyz;
gl_Position = projection * modelView * vec4(vPosition, 1.0);
}
Also, my fragment shader looks something like this. (I just added new material settings as compared to earlier)
#version 400 core
uniform vec4 lightColor;
uniform vec4 diffuseColor;
in vec3 lPos;
in vec3 vPos;
in vec3 vNorm;
void main(){
//copper like material light settings
vec4 ambient = vec4(0.19125, 0.0735, 0.0225, 1.0);
vec4 diff = vec4(0.7038, 0.27048, 0.0828, 1.0);
vec4 spec = vec4(0.256777, 0.137622, 0.086014, 1.0);
vec3 L = normalize (lPos - vPos);
vec3 N = normalize (vNorm);
vec3 Emissive = normalize(-vPos);
vec3 R = reflect(-L, N);
float dotProd = max(dot(R, Emissive), 0.0);
vec4 specColor = lightColor*spec*pow(dotProd,0.1 * 128);
vec4 diffuse = lightColor * diff * (dot(N, L));
gl_FragColor = ambient + diffuse + specColor;
}
And finally the animation I got from updating the code:
As you can see, I am still getting some missing triangles/faces in the morph target animation. Any more suggestions/comments regarding the issue would be really helpful. Thanks again in advance. :)
Update:
So as suggested, I flipped the normals if dot(vSmile_R, nSmile_R) < 0 and I got the following image result.
Also, instead of getting the normals from the obj files, I tried calculating my own (face and vertex normals) and still I got the same result.
Not an answer attempt, I just need more formatting than available for comments.
I cannot tell which data was actually exported from Fasceshift and how that was put into the custom ADTs of the app; my crystal ball is currently busy with predicting the FIFA Wold Cup results.
But generally, a linear morph is a very simple thing:
There is one vector "I" of data for the initial mesh and a vector "F" of equal size for the position data of the final mesh; their count and ordering must match for the tessellation to remain intact.
Given j ∈ [0,count), corresponding vectors initial_ = I[j], final_ = F[j] and a morph factor λ ∈ [0,1] the j-th (zero-based) current vector current_(λ) is given by
current_(λ) = initial_ + λ . (final_ - initial_) = (1 - λ ) . initial_ + λ . final_.
From this perspective, this
vec3 vPosition = neutral_w * vNeutral +
smile_w/2 * vSmile_L + smile_w/2 * vSmile_R;
looks dubious at best.
As I said, my crystal ball is currently defunct, but the naming would imply that, given the OpenGL standard reference frame,
vSmile_L = vSmile_R * (-1,1,1),
this "*" denoting component-wise multiplication, and that in turn would imply cancelling out the morph x-component by above addition.
But apparently, the face does not degenerate into a plane (a line from the projected pov), so the meaning of those attributes is unclear.
That's the reason why I want to look at the effective data, as stated in the comments.
Another thing, not related to the effect in question, but to the the shading algorithm.
As stated in the answer to this
Can OpenGL shader compilers optimize expressions on uniforms?,
the shader optimizer could well optimize pure uniform expressions like the M/V/P calculations done with
uniform float left;
uniform float right;
uniform float top;
uniform float bottom;
uniform float near;
uniform float far;
uniform vec3 cameraPosition;
uniform vec3 lookAtPosition;
uniform vec3 upVector;
/* */
uniform vec3 pos;
uniform vec3 size;
uniform mat4 quaternion;
but I find it highly optimistic to rely on such assumed optimizations.
if it is not optimized accordingly doing this means doing it once per frame per vertex so for a human face with a LOD of 1000 vertices, and 60Hz that would be done 60,000 times per second by the GPU, instead of once and for all by the CPU.
No modern CPU would give up soul if these calculations are put once on her shoulders, so passing the common trinity of M/V/P matrices as uniforms seems appropriate instead of constructing those matrices in the shader.
For reusing the code from the shaders - glm provides a very glsl-ish way to do GL-related maths in C++.
I had a very similar problem some time ago. As you eventually noticed, your problem most probably lies in the mesh itself. In my case, it was inconsistent mesh triangulation. Using the Triangluate Modifier in Blender solved the problem for me. Perhaps you should give it a try too.
Related
So I am currently working on trying to create a spotlight in my vertex shader, currently I can produce directional and/or point light by using the Phong lighting model.
Im finding it hard to calculate the correct angles for the spotlight, basically just want a spotlight that comes from 0,0,0 in eye space and looks down the Z co-ord.
I am trying to just make everything (for now) in the cone to be bright white and everything outside it dark
#version 130
uniform mat4 model_view_matrix;
uniform mat4 projection_matrix;
uniform mat3 normal_matrix;
uniform int light_mode;
uniform vec4 light_pos;
uniform vec3 light_ambient;
uniform vec3 light_diffuse;
uniform vec3 light_specular;
uniform vec3 mtl_ambient;
uniform vec3 mtl_diffuse;
uniform vec3 mtl_specular;
uniform float mtl_shininess;
// Spotlight test
const float spotCutOff = 100.00f;
in vec3 position;
in vec3 normal;
in vec2 texCoord;
out vec2 st;
out vec4 litColour;
vec3 phongLight(in vec4 position, in vec3 norm)
{
// s is the direction from the light to the vertex
vec3 s;
if (light_pos.w == 0.0) {
s = normalize(light_pos.xyz);
}
else {
s = normalize(vec3(light_pos - position));
}
// v is the direction from the eye to the vertex
vec3 v = normalize(-position.xyz);
// r is the direction of light reflected from the vertex
vec3 r = reflect(-s, norm);
vec3 ambient = light_ambient * mtl_ambient;
// The diffuse component
float sDotN = max(dot(s,norm), 0.0);
vec3 diffuse = light_diffuse * mtl_diffuse * sDotN;
// Specular component
vec3 spec = vec3(0.0);
if (sDotN > 0.0)
spec = light_specular * mtl_specular * pow(max(dot(r,v), 0.0), mtl_shininess);
return ambient + diffuse + spec;
}
vec3 spotLight(in vec4 position, in vec3 norm)
{
vec3 ambient = vec3(0.2, 0.2, 0.2);
vec3 lightDir = normalize(vec3(light_pos - position));
vec3 spotDir = vec3(0.0, 0.0, -1.0);
float angle = degrees(acos(dot(spotDir, lightDir)));
//angle = max (angle, 0);
if ((angle) < spotCutOff) {
return vec3(1.0, 1.0, 1.0);
}
float dist = sqrt(positon.x * position.x + position.y + position.y + position.z * position.z);
if (dist < 1) {
return vec3(1.0,1.0,0.0);
}
return vec3(0.2, 0.2, 0.2);
}
void main(void)
{
// Convert normal and position to eye coords
vec3 eyeNorm = normalize(normal_matrix * normal);
vec4 eyePos = model_view_matrix * vec4(position, 1.0);
// No lighting effect
if (light_mode == 0)
{
litColour = vec4(1.0, 1.0, 1.0, 1.0);
}
// Directional overhead light
else if (light_mode == 1)
{
litColour = vec4(phongLight(eyePos, eyeNorm), 1.0);
}
// Point light
else if (light_mode == 2)
{
litColour = vec4(phongLight(eyePos, eyeNorm), 1.0);
}
else if (light_mode == 3)
{
litColour = vec4(spotLight(eyePos, eyeNorm), 1.0);
}
//litColour = vec4(normal*1000, 1.0);
gl_Position = projection_matrix * eyePos;
st = texCoord;
}
Your spotlight is defined by a position (ps) and a direction (ds). So for every vertex at position vp you can compute d=vp-ps, normalize that to dn=normalize(d), and then dot(dn,ds) will give you the angle in the spotlight. Just scale it or compare it to a cut off to get a scalar!
Alternatively, and in the long term better, is to think of a spotlight as a camera. Do the same as you do for your camera: A model and view matrix! Transform every vertex into that space, and project it from x,y,z,w to x,y,z. z is the distance which is always useful for lighting and x,y you can use to look up in a texture that has a round shape (or any other).
One thing to mind with both techniques is back projection: Make sure you check that the light only points forward! Check the sign of z or the dot product!
I found a good example of environment mapping equirectangular. Here's the code:
VERTEX SHADER
varying vec3 Normal;
varying vec3 EyeDir;
varying float LightIntensity;
uniform vec3 LightPos;
void main(void){
gl_Position = ftransform();
Normal = normalize(gl_NormalMatrix * gl_Normal);
vec4 pos = gl_ModelViewMatrix * gl_Vertex;
EyeDir = pos.xyz;
LightIntensity = max(dot(normalize(LightPos - EyeDir), Normal), 0.0);
}
FRAGMENT SHADER
const vec3 Xunitvec = vec3 (1.0, 0.0, 0.0);
const vec3 Yunitvec = vec3 (0.0, 1.0, 0.0);
uniform vec3 BaseColor;
uniform float MixRatio;
uniform sampler2D EnvMap;
varying vec3 Normal;
varying vec3 EyeDir;
varying float LightIntensity;
void main (void){
// Compute reflection vector
vec3 reflectDir = reflect(EyeDir, Normal);
// Compute altitude and azimuth angles
vec2 index;
index.y = dot(normalize(reflectDir), Yunitvec);
reflectDir.y = 0.0;
index.x = dot(normalize(reflectDir), Xunitvec) * 0.5;
// Translate index values into proper range
if (reflectDir.z >= 0.0)
index = (index + 1.0) * 0.5;
else
{
index.t = (index.t + 1.0) * 0.5;
index.s = (-index.s) * 0.5 + 1.0;
}
// if reflectDir.z >= 0.0, s will go from 0.25 to 0.75
// if reflectDir.z < 0.0, s will go from 0.75 to 1.25, and
// that's OK, because we've set the texture to wrap.
// Do a lookup into the environment map.
vec3 envColor = vec3 (texture2D(EnvMap, index));
// Add lighting to base color and mix
vec3 base = LightIntensity * BaseColor;
envColor = mix(envColor, base, MixRatio);
gl_FragColor = vec4 (envColor, 1.0);
}
My problem is in the vertex shader.
LightIntensity = max(dot(normalize(LightPos - EyeDir), Normal), 0.0);
I'm subtracting the eye direction to the direction of light. But if I have more than one light source ... What I should do the calculation?
I use version 1.2 of GLSL.
Light is additive, so you just need to sum up the contributions of each light. If you have a fixed number of them, you can do that in a single pass through the shader—you just define a uniform for each light (position to start with, though you’ll probably want intensity/color as well) and calculate the final intensity like this:
LightIntensity = max(dot(normalize(Light1Pos - EyeDir), Normal), 0.0) + max(dot(normalize(Light2Pos - EyeDir), Normal), 0.0) + max(dot(normalize(Light3Pos - EyeDir), Normal), 0.0);
I'm trying to do point source directional lighting in OpenGL using my textbooks examples. I'm showing a rectangle centered at the origin, and doing the lighting computations in the shader. The rectangle appears, but it is black even when I try to put colored lights on it. Normals for the rectangle are all (0, 1.0, 0). I'm not doing any non-uniform scaling, so the regular model view matrix should also transform the normals.
I have code that sets the light parameters(as uniforms) and material parameters(also as uniforms) for the shader. There is no per vertex color information.
void InitMaterial()
{
color material_ambient = color(1.0, 0.0, 1.0);
color material_diffuse = color(1.0, 0.8, 0.0);
color material_specular = color(1.0, 0.8, 0.0);
float material_shininess = 100.0;
// set uniforms for current program
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialAmbient"), 1, material_ambient);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialDiffuse"), 1, material_diffuse);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialSpecular"), 1, material_specular);
glUniform1f(glGetUniformLocation(Programs[lightingType], "shininess"), material_shininess);
}
For the lights:
void InitLight()
{
// need light direction and light position
point4 light_position = point4(0.0, 0.0, -1.0, 0.0);
color light_ambient = color(0.2, 0.2, 0.2);
color light_diffuse = color(1.0, 1.0, 1.0);
color light_specular = color(1.0, 1.0, 1.0);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightPosition"), 1, light_position);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightAmbient"), 1, light_ambient);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightDiffuse"), 1, light_diffuse);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightSpecular"), 1, light_specular);
}
The fragment shader is a simple pass through shader that sets the color to the one input from the vertex shader. Here is the vertex shader :
#version 150
in vec4 vPosition;
in vec3 vNormal;
out vec4 color;
uniform vec4 materialAmbient, materialDiffuse, materialSpecular;
uniform vec4 lightAmbient, lightDiffuse, lightSpecular;
uniform float shininess;
uniform mat4 modelView;
uniform vec4 lightPosition;
uniform mat4 projection;
void main()
{
// Transform vertex position into eye coordinates
vec3 pos = (modelView * vPosition).xyz;
vec3 L = normalize(lightPosition.xyz - pos);
vec3 E = normalize(-pos);
vec3 H = normalize(L + E);
// Transform vertex normal into eye coordinates
vec3 N = normalize(modelView * vec4(vNormal, 0.0)).xyz;
// Compute terms in the illumination equation
vec4 ambient = materialAmbient * lightAmbient;
float Kd = max(dot(L, N), 0.0);
vec4 diffuse = Kd * materialDiffuse * lightDiffuse;
float Ks = pow(max(dot(N, H), 0.0), shininess);
vec4 specular = Ks * materialSpecular * lightSpecular;
if(dot(L, N) < 0.0) specular = vec4(0.0, 0.0, 0.0, 1.0);
gl_Position = projection * modelView * vPosition;
color = ambient + diffuse + specular;
color.a = 1.0;
}
Ok, it's working now. The solution was to replace glUniform3fv with glUniform4fv, I guess because the glsl counterpart is a vec4 instead of a vec3. I thought that it would be able to recognize this and simply add a 1.0 to the end, but no.
I am trying to use this tutorial for per-fragment shading and adapt it to GLSL #version 140. The results I am getting are obviously not correct. Seems to me that I am doing something wrong with the supplied normals, since there is a direct change between light and shade on some triangles which are next to each other on the same plane.
The vertex shader code:
#version 140
in vec3 position;
in vec2 texIn;
in vec3 normal;
smooth out vec2 texCoor;
out vec4 v_position; // position of the vertex (and fragment) in world space
out vec3 NormalDirection; // surface normal vector in world space
uniform mat4 mP, mV, mM; // transformation matrices
uniform mat3 m_3x3_inv_transp;
void main() {
v_position = mM * vec4(position, 1.0);
NormalDirection = normalize(m_3x3_inv_transp * normal);
mat4 mvp = mP*mV*mM;
gl_Position = mvp * vec4(position, 1.0);
texCoor = texIn;
}
The fragment shader:
#version 140
uniform mat4 mM, mV, mP;
uniform mat4 mV_inv;
uniform sampler2D texSampler; // sampler for texture access
smooth in vec2 texCoor; // from Vertex shader
in vec4 v_position; // position of the vertex (and fragment) in world space
in vec3 NormalDirection; // surface normal vector in world space
out vec4 colorOut; // fragment color
struct lightSource {
vec4 position;
vec4 diffuse;
vec4 specular;
float constantAttenuation, linearAttenuation, quadraticAttenuation;
float spotCutoff, spotExponent;
vec3 spotDirection;
};
lightSource light0 = lightSource(
vec4(5.0, 5.0, 5.0, 1.0),
vec4(2.0, 2.0, 2.0, 1.0),
vec4(2.0, 2.0, 2.0, 1.0),
0.0, 1.0, 0.0,
180.0, 0.0,
vec3(0.0, 0.0, 0.0)
);
vec4 scene_ambient = vec4(1.2, 1.2, 1.2, 1.0);
struct material {
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
material frontMaterial = material(
vec4(0.2, 0.2, 0.2, 1.0),
vec4(1.0, 0.8, 0.8, 1.0),
vec4(1.0, 1.0, 1.0, 1.0),
5.0
);
void main() {
vec3 normalDirection = normalize(NormalDirection);
vec3 viewDirection = normalize(vec3(mV_inv * vec4(0.0, 0.0, 0.0, 1.0) - v_position));
vec3 lightDirection;
float attenuation;
if (0.0 == light0.position.w) // directional light?
{
attenuation = 1.0; // no attenuation
lightDirection = normalize(vec3(light0.position));
}
else // point light or spotlight (or other kind of light)
{
vec3 positionToLightSource = vec3(light0.position - v_position);
float distance = length(positionToLightSource);
lightDirection = normalize(positionToLightSource);
attenuation = 1.0 / (light0.constantAttenuation
+ light0.linearAttenuation * distance
+ light0.quadraticAttenuation * distance * distance);
if (light0.spotCutoff <= 90.0) // spotlight?
{
float clampedCosine = max(0.0, dot(-lightDirection, light0.spotDirection));
if (clampedCosine < cos(radians(light0.spotCutoff))) // outside of spotlight cone?
{
attenuation = 0.0;
}
else
{
attenuation = attenuation * pow(clampedCosine, light0.spotExponent);
}
}
}
vec3 ambientLighting = vec3(scene_ambient) * vec3(frontMaterial.ambient);
vec3 diffuseReflection = attenuation
* vec3(light0.diffuse) * vec3(frontMaterial.diffuse)
* max(0.0, dot(normalDirection, lightDirection));
vec3 specularReflection;
if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side?
{
specularReflection = vec3(0.0, 0.0, 0.0); // no specular reflection
}
else // light source on the right side
{
specularReflection = attenuation * vec3(light0.specular) * vec3(frontMaterial.specular)
* pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), frontMaterial.shininess);
}
colorOut = vec4(ambientLighting + diffuseReflection + specularReflection, 1.0) * texture(texSampler, texCoor);
}
C++ code (uniforms):
// matrices to vertex shader
glm::mat4 modelMatrix = glm::mat4(1.0); // identity matrix - table is static
glUniformMatrix4fv(locations.Mmatrix, 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(locations.Pmatrix, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glUniformMatrix4fv(locations.Vmatrix, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glm::mat3 m_inv_transp = glm::transpose(glm::inverse(glm::mat3(modelMatrix)));
glUniformMatrix3fv(locations.m_3x3_inv_transp, 1, GL_FALSE, glm::value_ptr(m_inv_transp));
glm::mat3 v_inv = glm::inverse(glm::mat3(viewMatrix));
glUniformMatrix4fv(locations.Vmatrix_inv, 1, GL_FALSE, glm::value_ptr(v_inv));
I'm trying to implement very simple diffuse shader in GLSL/openGL.
Here's what I got:
Vertex shader:
#version 130
in vec3 vertPos3D;
in vec3 vertNormal3D;
uniform mat3 transpMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform vec3 lightPosition;
varying vec3 vertNormal;
varying vec3 lightVector;
void main()
{
vec4 res_pos = projectionMatrix * viewMatrix * vec4(vertPos3D.xyz, 1.0);
gl_Position = res_pos;
mat4 pm = projectionMatrix * viewMatrix;
vertNormal = (viewMatrix * vec4(vertNormal3D, 0)).xyz;
lightVector = (viewMatrix * vec4(lightPosition, 1.0)).xyz - (viewMatrix * vec4(vertPos3D.xyz, 1.0)).xyz;
}
Fragment Shader:
#version 130
out vec4 color;
varying vec3 lightVector;
varying vec3 vertNormal;
void main()
{
float dot_product = max(normalize(dot(lightVector, vertNormal)), 0.0);
color = dot_product * vec4( 1.0, 1.0, 1.0, 1.0 );
}
As soon as I multiply final color with dot_product, nothing displays. I remove dot_product, everything works (except diffuse lightning ofc.). I'm afraid it's something obvious I'm missing.
A problem:
normalize(dot(lightVector, vertNormal))
dot in GLSL 1.3 returns a float.
normalize accepts a vector, not a float.
documentation for dot
documentation for normalize
A Solution, at least to this problem:
In Fragment shader, replace
float dot_product = max(normalize(dot(lightVector, vertNormal)), 0.0);
with
float dot_product = clamp(dot(lightVector, vertNormal), 0., 1.);
It looks like you are using max and normalize to avoid negative numbers returned from dot. This is exactly what clamp is for. Here's the documentation for clamp
Use
float dot_product = max(dot(normalize(lightVector), normalize(normalVector)), 0.0);
Dylan Holmes answer is slightly incorrect:
Still the lightVector needs to be normalized!
And clamping is unnecessary. max was correct. A dot product never returns a value higher then 1.0 if input vectors are normalized.