How can I add lighting ( ambient + directional ) to the shader that used with InstancedBufferGeometry?
For example, I want to add lighting to this:
https://threejs.org/examples/?q=inst#webgl_buffergeometry_instancing_dynamic
Here is my vertex shader:
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
attribute vec3 position;
attribute vec3 offset;
attribute vec3 normal;
attribute vec2 uv;
attribute vec4 orientation;
varying vec2 vUv;
// lighting
struct DirectionalLight {
vec3 direction;
vec3 color;
int shadow;
float shadowBias;
float shadowRadius;
vec2 shadowMapSize;
};
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
uniform vec3 ambientLightColor;
varying vec3 vLightFactor;
//
void main() {
vec3 vPosition = position;
vec3 vcV = cross(orientation.xyz, vPosition);
vPosition = vcV * (2.0 * orientation.w) + (cross(orientation.xyz, vcV) * 2.0 + vPosition);
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
// lighting
vec4 ecPosition = modelViewMatrix*vec4(offset + vPosition,1.0);
vec3 ecNormal= -(normalize(normalMatrix*normal));
vec3 fromLight = normalize(directionalLights[0].direction);
vec3 toLight = -fromLight;
vec3 reflectLight = reflect(toLight,ecNormal);
vec3 viewDir = normalize(-ecPosition.xyz);
float ndots = dot(ecNormal, toLight);
float vdotr = max(0.0,dot(viewDir,reflectLight));
vec3 ambi = ambientLightColor;
vec3 diff = directionalLights[0].color * ndots;
vLightFactor = ambi + diff;
//
}
Here is my fragment shader:
precision highp float;
uniform sampler2D map;
varying vec2 vUv;
// lighting
varying vec3 vLightFactor;
//
void main() {
gl_FragColor = texture2D(map, vUv) * vec4(vLightFactor,1.0);
}
Here is my material:
var uniforms = Object.assign(
THREE.UniformsLib['lights'],
{
map: { value: texture }
}
);
var material = new THREE.RawShaderMaterial({
lights: true,
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
});
Thanks
In a rendering, each mesh of the scene usually is transformed by the model matrix, the view matrix and the projection matrix.
The model matrix defines the location, orientation and the relative size of an mesh in the scene. The model matrix transforms the vertex positions from of the mesh to the world space.
The view matrix describes the direction and position from which the scene is looked at. The view matrix transforms from the world space to the view (eye) space.
Note, The model view matrix modelViewMatrix is the combination of the view matrix and the model matrix. But in your case, the model matrix is possibly the identity matrix, and the modelViewMatrix is possibly equal to the view matrix. I assume that, because you don't do the model transformations by a model matrix, but by the vectors orientation and offset.
The light can either be calculated in view space or in world space.
If the light is calculated in view space the light positions and light directions have to be transformed from world space to view space. Commonly this is done on the CPU (before every frame) and the light parameters uniforms are set up with view space coordinates. Since the view position is (0, 0, 0) in view space, is the view vector the the normalized and inverse vertex position (in view space).
If the light calculations are done in world space, then the view vector has to be calculated by the difference of the view position (eye position) and the vertex position (of course in world space).
You can do the light calculations in view space, because the light direction and position is set up in view space (see three.js - Light). You have to transform the normal vector to world space first and then you have to convert from world space to view space. This has to be done similar as you do it for the vertex position. Add the normal vector to the vertex position. Transform this position to world space. The normal vector in world space, is the difference of the calculated position and the vertex position in world space.
vec3 wNPosition = position + normal;
vec3 wNV = cross(orientation.xyz, wNPosition);
wNPosition = wNV * 2.0 * orientation.w + cross(orientation.xyz, wNV) * 2.0 + wNPosition;
vec3 wNormal = normalize( wNPosition - vPosition );
Under this assumption, your shader code might look like this:
vec3 wPosition = position;
vec3 wV = cross(orientation.xyz, wPosition);
wPosition = offset + wV * 2.0 * orientation.w + cross(orientation.xyz, wV) * 2.0 + wPosition;
vec4 ecPosition = modelViewMatrix * vec4(wPosition, 1.0);
vUv = uv;
gl_Position = projectionMatrix * ecPosition;
// transform normal vector to world space
vec3 wNPosition = position + normal;
vec3 wNV = cross(orientation.xyz, wNPosition);
wNPosition = offset + wNV * 2.0 * orientation.w + cross(orientation.xyz, wNV) * 2.0 + wNPosition;
vec3 ecNormal = normalize(mat3(modelViewMatrix) * (wNPosition - wPosition));
// ambient light
vLightFactor = ambientLightColor;
// diffuse light
vec3 ecToLight = normalize(directionalLights[0].direction);
float NdotL = max(0.0, dot(ecNormal, ecToLight));
vLightFactor += NdotL * directionalLights[0].color;
If you want to add specular light you have to do it like this:
// specular light
vec3 ecReflectLight = reflect( ecFromLight, ecNormal );
vec3 ecViewDir = normalize(-ecPosition.xyz);
float VdotR = max(0.0, dot(ecViewDir, ecReflectLight));
float kSpecular = 4.0 * pow( VdotR, 0.3 * shininess ); // <--- set up shininess parameter
vLightFactor += kSpecular * directionalLights[0].color;
Extension to the answer: Per fragment lighting
While Gouraud shading calculates the light in the the vertex shader, Phong shading calculates the light in the fragment shader.
(see further GLSL fixed function fragment program replacement)
Vertex shader:
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
attribute vec3 position;
attribute vec3 offset;
attribute vec3 normal;
attribute vec2 uv;
attribute vec4 orientation;
varying vec2 vUv;
varying vec3 ecPosition;
varying vec3 ecNormal;
void main()
{
vec3 wPosition = position;
vec3 wV = cross(orientation.xyz, wPosition);
pos = offset + wV * 2.0 * orientation.w + cross(orientation.xyz, wV) * 2.0 + wPosition;
vec4 vPos = modelViewMatrix * vec4(wPosition, 1.0);
ecPosition = vPos.xyz;
vUv = uv;
gl_Position = projectionMatrix * vPos;
// transform normal vector to world space
vec3 wNPosition = position + normal;
vec3 wNV = cross(orientation.xyz, wNPosition);
wNPosition = offset + wNV * 2.0 * orientation.w + cross(orientation.xyz, wNV) * 2.0 + wNPosition;
ecNormal = normalize(mat3(modelViewMatrix) * (wNPosition - wPosition));
}
Fragment shader:
precision highp float;
varying vec2 vUv;
varying vec3 ecPosition;
varying vec3 ecNormal;
uniform sampler2D map;
uniform mat4 modelViewMatrix;
struct DirectionalLight {
vec3 direction;
vec3 color;
int shadow;
float shadowBias;
float shadowRadius;
vec2 shadowMapSize;
};
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
uniform vec3 ambientLightColor;
void main()
{
// ambient light
float lightFactor = ambientLightColor;
// diffuse light
vec3 ecToLight = normalize(directionalLights[0].direction);
float NdotL = max(0.0, dot(ecNormal, ecToLight));
lightFactor += NdotL * directionalLights[0].color;
// specular light
vec3 ecReflectLight = reflect( ecFromLight, ecNormal );
vec3 ecViewDir = normalize(-ecPosition.xyz);
float VdotR = max(0.0, dot(ecViewDir, ecReflectLight));
float kSpecular = 4.0 * pow( VdotR, 0.3 * shininess ); // <--- set up shininess parameter
lightFactor += kSpecular * directionalLights[0].color;
gl_FragColor = texture2D(map, vUv) * vec4(vec3(lightFactor), 1.0);
}
see also
Transform the modelMatrix
How does this faking the light work on aerotwist?
GLSL fixed function fragment program replacement
what i mean is the fragment shader should look like this:
precision highp float;
varying vec2 vUv;
varying vec3 ecPosition;
varying vec3 ecNormal;
uniform sampler2D map;
uniform mat4 modelViewMatrix;
struct DirectionalLight {
vec3 direction;
vec3 color;
int shadow;
float shadowBias;
float shadowRadius;
vec2 shadowMapSize;
};
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
uniform vec3 ambientLightColor;
void main()
{
// ambient light
vec3 lightFactor = ambientLightColor;
// diffuse light
vec3 ecFromLight = normalize(directionalLights[0].direction);
//vec3 ecToLight = -ecFromLight;
float NdotL = max(0.0, dot(ecNormal, ecFromLight));
lightFactor += NdotL * directionalLights[0].color;
// specular light
/*
float shininess = 10.01;
vec3 ecReflectLight = reflect( ecFromLight, ecNormal );
vec3 ecViewDir = normalize(-ecPosition.xyz);
float VdotR = max(0.0, dot(ecViewDir, ecReflectLight));
float kSpecular = 4.0 * pow( VdotR, 0.3 * shininess ); // <--- set up shininess parameter
lightFactor += kSpecular * directionalLights[0].color;
*/
gl_FragColor = texture2D(map, vUv) * vec4(lightFactor, 1.0);
}
Related
I am completely new to opengl es shader and cook-torrance,
the following shader only output red, no texture color processed for ambient light and point light.
the cube is for testing,no shader applied to it, the right side rocket with texture with no output,just red color. Any opengl es guy can help?
no texture only red
original texture before apply cook-torrance and output by gl_FragColor =texture2D(texture,vertTexCoord.st).rgb*vertColor;
But what make CookTorance() below fail?
fragment shader
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PI 3.14159265
//copper
uniform vec3 diffuseColor = vec3(0.75164,0.60648,0.22648);
uniform vec3 specularColor = vec3(0.256777,0.137622,0.086014);
uniform float F0 = 0.8;
uniform float roughness = 0.1;
uniform float k = 0.2;
//uniform vec3 lightColor = vec3(1, 1, 1);
uniform sampler2D texture;
varying vec4 varyvertColor;
varying vec3 ecNormal; //eye normal
varying vec3 lightDir;
varying vec4 varyambient;
varying vec4 varyspecular;
varying float varyshininess; //0.1
varying vec4 vertTexCoord;
varying vec4 vposition;
vec3 CookTorrance(vec3 materialDiffuseColor,
vec3 materialSpecularColor,
vec3 normal,
vec3 lightDir,
vec3 viewDir,
vec3 lightColor)
{
float NdotL = max(0, dot(normal, lightDir));
float Rs = 0.0;
if (NdotL > 0)
{
vec3 H = normalize(lightDir + viewDir);
float NdotH = max(0, dot(normal, H));
float NdotV = max(0, dot(normal, viewDir));
float VdotH = max(0, dot(lightDir, H));
// Fresnel reflectance
float F = pow(1.0 - VdotH, 5.0);
F *= (1.0 - F0);
F += F0;
// Microfacet distribution by Beckmann
float m_squared = roughness * roughness;
float r1 = 1.0 / (4.0 * m_squared * pow(NdotH, 4.0));
float r2 = (NdotH * NdotH - 1.0) / (m_squared * NdotH * NdotH);
float D = r1 * exp(r2);
// Geometric shadowing
float two_NdotH = 2.0 * NdotH;
float g1 = (two_NdotH * NdotV) / VdotH;
float g2 = (two_NdotH * NdotL) / VdotH;
float G = min(1.0, min(g1, g2));
Rs = (F * D * G) / (PI * NdotL * NdotV);
}
return materialDiffuseColor * lightColor * NdotL + lightColor * materialSpecularColor * NdotL * (k + Rs * (1.0 - k));
}
void main(){
vec3 direction = normalize(lightDir);
//vec3 normal = normalize(ecNormal);
vec3 normal = -normalize(ecNormal);
vec4 vertColor = varyambient +
vec4(CookTorrance(texture2D(texture,vertTexCoord.st).rgb*varyvertColor.xyz,
varyspecular.xyz*specularColor,
vposition.xyz,
direction,
normal,
varyvertColor.rgb),1.0);
gl_FragColor = vertColor;
}
is there any error in the above cook-torrance?
please help on it.
the vertex shader
uniform mat4 modelviewMatrix;
uniform mat4 transformMatrix;
uniform mat3 normalMatrix;
uniform mat4 texMatrix;
attribute vec4 position;
attribute vec4 color;
attribute vec3 normal;
attribute vec4 ambient;
attribute vec4 specular;
attribute float shininess;
attribute vec2 texCoord;
varying vec4 vposition;
varying vec4 vertColor;
varying vec3 ecNormal;
varying vec3 lightDir;
varying vec4 varyambient;
varying vec4 varyspecular;
varying float varyshininess;
varying vec4 varyvertColor;
varying vec4 vertTexCoord;
void main() {
// Vertex in clip coordinates
gl_Position = transformMatrix * position;
vposition = transformMatrix * position;
// Vertex in eye coordinates
vec3 ecVertex = vec3(modelviewMatrix * position);
// Normal vector in eye coordinates
ecNormal = normalize(normalMatrix * normal);
varyambient=ambient;
varyspecular=specular;
varyshininess=shininess;
varyvertColor=color;
vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);
}
I have the following shaders used in a custom material shader in threeJS and applied to metaballs. Positions of each metaballs (2 in this example) are passed to an array allPos and they are compared in distance with vertex normal to find the closest one. Its index is used to assign a color blobColor which is then passed to the fragment shader.
vertex shader
uniform vec3 colChoice[2];
varying vec3 vNormal;
varying vec3 blobColor;
varying vec3 otherColor;
uniform vec3 allPos[2];
varying float mixScale;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vNormal = normalize( normalMatrix * normal );
float prevdist = 1000000000000000000000000000000.0;
for(int i=0;i<2;i++){
float distV = distance(allPos[i],normal.xyz);
if(distV<prevdist){
prevdist = distV;
mixScale = distV;
blobColor = colChoice[i];
otherColor = colChoice[i-1];
}
}
gl_Position = projectionMatrix * mvPosition;
}
fragment shader
"varying vec3 blobColor;",
"varying vec3 otherColor;",
"varying vec3 vNormal;",
"varying float mixScale;",
void main() {
finalColor = (0.45*vNormal) + mix(otherColor,blobColor,mixScale);
gl_FragColor = vec4( finalColor, 1.0 );
}
which gives me something like this:
It is a bit rough for now and I would like to apply a dot gradient between
the two colors. Any suggestion?
I'm displaying a grid of particle clouds using shaders. Every time a user clicks a cloud, that cloud disappears and a new one takes its place. The curious thing is that the memory usage in the GPU climbs every time a new cloud replaces an old one - regardless of whether that new cloud is larger or smaller (and the buffer sizes always stay the same - the unused points are simply displayed offscreen with no color). After less than 10 clicks the GPU maxes out and crashes.
Here is my physics shader where the new positions are updated - I pass in the new position values for the new cloud by updating certain values in the the tOffsets texture. After that are my two (vert and frag) visual effects shaders. Can you see my efficiency issue? Or could this be a garbage collection matter? - Thanks in advance!
Physics Shader (frag only):
// Physics shader: This shader handles the calculations to move the various points. The position values are rendered out to at texture that is passed to the next pair of shaders that add the sprites and opacity.
// the tPositions sampler is added to this shader by Three.js's GPUCompute script
uniform sampler2D tOffsets;
uniform sampler2D tGridPositionsAndSeeds;
uniform sampler2D tSelectionFactors;
uniform float uPerMotifBufferDimension;
uniform float uTime;
uniform float uXOffW;
...noise functions omitted for brevity...
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec4 offsets = texture2D( tOffsets, uv ).xyzw;
float alphaMass = offsets.z;
float cellIndex = offsets.w;
if (cellIndex >= 0.0) { // this point will be rendered on screen
float damping = 0.98;
float texelSize = 1.0 / uPerMotifBufferDimension;
vec2 perMotifUV = vec2( mod(cellIndex, uPerMotifBufferDimension)*texelSize, floor(cellIndex / uPerMotifBufferDimension)*texelSize );
perMotifUV += vec2(0.5*texelSize);
vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;
float swapState = selectionFactors.x;
vec4 gridPosition = texture2D( tGridPositionsAndSeeds, perMotifUV ).xyzw;
vec2 noiseSeed = gridPosition.zw;
vec4 nowPos;
vec2 velocity;
nowPos = texture2D( tPositions, uv ).xyzw;
velocity = vec2(nowPos.z, nowPos.w);
if ( swapState == 0.0 ) { // if no new position values are ready to be swapped in for this point
nowPos = texture2D( tPositions, uv ).xyzw;
velocity = vec2(nowPos.z, nowPos.w);
} else { // if swapState == 1, this means new position values are ready to be swapped in for this point
nowPos = vec4( -(uTime) + offsets.x, offsets.y, 0.0, 0.0 );
velocity = vec2(0.0, 0.0);
}
...physics calculations omitted for brevity...
vec2 newPosition = vec2(nowPos.x - velocity.x, nowPos.y - velocity.y);
// Write new position out to a texture for processing in the visual effects shader
gl_FragColor = vec4(newPosition.x, newPosition.y, velocity.x, velocity.y);
} else { // this point will not be rendered on screen
// Write new position out off screen (all -1 cellIndexes have off-screen offset values)
gl_FragColor = vec4( offsets.x, offsets.y, 0.0, 0.0);
}
From the physics shader the tPositions texture with the points' new movements is rendered out and passed to the visual effects shaders:
Visual Effects Shader (vert):
uniform sampler2D tPositions; // passed in from the Physics Shader
uniform sampler2D tSelectionFactors;
uniform float uPerMotifBufferDimension;
uniform sampler2D uTextureSheet;
uniform float uPointSize;
uniform float uTextureCoordSizeX;
uniform float uTextureCoordSizeY;
attribute float aTextureIndex;
attribute float aAlpha;
attribute float aCellIndex;
varying float vCellIndex;
varying vec2 vTextureCoords;
varying vec2 vTextureSize;
varying float vAlpha;
varying vec3 vColor;
...omitted noise functions for brevity...
void main() {
vec4 tmpPos = texture2D( tPositions, position.xy );
vec2 pos = tmpPos.xy;
vec2 vel = tmpPos.zw;
vCellIndex = aCellIndex;
if (vCellIndex >= 0.0) { // this point will be rendered onscreen
float texelSize = 1.0 / uPerMotifBufferDimension;
vec2 perMotifUV = vec2( mod(aCellIndex, uPerMotifBufferDimension)*texelSize, floor(aCellIndex / uPerMotifBufferDimension)*texelSize );
perMotifUV += vec2(0.5*texelSize);
vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;
float aSelectedMotif = selectionFactors.x;
float aColor = selectionFactors.y;
float fadeFactor = selectionFactors.z;
vTextureCoords = vec2( aTextureIndex * uTextureCoordSizeX, 0 );
vTextureSize = vec2( uTextureCoordSizeX, uTextureCoordSizeY );
vAlpha = aAlpha * fadeFactor;
vColor = vec3( 1.0, aColor, 1.0 );
gl_PointSize = uPointSize;
} else { // this point will not be rendered onscreen
vAlpha = 0.0;
vColor = vec3(0.0, 0.0, 0.0);
gl_PointSize = 0.0;
}
gl_Position = projectionMatrix * modelViewMatrix * vec4( pos.x, pos.y, position.z, 1.0 );
}
Visual Effects Shader (frag):
uniform sampler2D tPositions;
uniform sampler2D uTextureSheet;
varying float vCellIndex;
varying vec2 vTextureCoords;
varying vec2 vTextureSize;
varying float vAlpha;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( vColor, vAlpha );
if (vCellIndex >= 0.0) { // this point will be rendered onscreen, so add the texture
vec2 realTexCoord = vTextureCoords + ( gl_PointCoord * vTextureSize );
gl_FragColor = gl_FragColor * texture2D( uTextureSheet, realTexCoord );
}
}
Thanks to #Blindman67's comment above, I sorted out the problem. It had nothing to do with the shaders. In the Javascript (Three.js) I needed to signal the GPU to delete old textures before adding the updated ones.
Everytime I update a texture (most of mine are DataTextures) I need to call dispose() on the existing texture before creating and updating the new one, like so:
var textureHandle; // holds a reference to the current texture uniform value
textureHandle.dispose(); // ** deallocates GPU memory **
textureHandle = new THREE.DataTexture( textureData, dimension, dimension, THREE.RGBAFormat, THREE.FloatType );
textureHandle.needsUpdate = true;
uniforms.textureHandle.value = textureHandle;
I've been trying to implement a basic fog function, and some resources I've found have led me to try a linear fog function that my understanding has led me to believe is based on the original fixed function fog equation (though I could be wrong on that). However, when I try to implement it, all my surfaces become black. I'm pretty sure my problem lies in how I (attempt to) compute the eye distance, as the rest of the equation is pretty straightforward.
My vertex shader:
precision mediump float;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoordIn;
varying vec3 eyeNormal;
varying vec4 eyePos;
varying vec2 texCoordOut;
varying float eyeDistance;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 normalMatrix;
uniform vec3 cameraPosition;
void main()
{
eyeNormal = (normalMatrix * normal);
eyePos = modelViewMatrix * position;
eyeDistance = sqrt((eyePos.x - cameraPosition.x) * (eyePos.x - cameraPosition.x) + (eyePos.y - cameraPosition.y) * (eyePos.y - cameraPosition.y) + (eyePos.z - cameraPosition.z) * (eyePos.z - cameraPosition.z));
texCoordOut = texCoordIn;
gl_Position = modelViewProjectionMatrix * position;
}
My fragment shader:
precision mediump float;
varying vec3 eyeNormal;
varying vec4 eyePos;
varying vec2 texCoordOut;
varying float eyeDistance;
uniform sampler2D texture;
uniform vec3 flashlightPosition;
uniform vec3 diffuseLightPosition;
uniform vec4 diffuseComponent;
uniform float shininess;
uniform vec4 specularComponent;
uniform vec4 ambientComponent;
uniform float maxFogDistance;
uniform float minFogDistance;
uniform vec4 fogColor;
void main()
{
vec4 ambient = ambientComponent;
vec3 N = normalize(eyeNormal);
float nDotVP = max(0.0, dot(N, normalize(diffuseLightPosition)));
vec4 diffuse = diffuseComponent * nDotVP;
vec3 E = normalize(-eyePos.xyz);
vec3 L = normalize(flashlightPosition - eyePos.xyz);
vec3 H = normalize(L+E);
float Ks = pow(max(dot(N, H), 0.0), shininess);
vec4 specular = Ks*specularComponent;
if( dot(L, N) < 0.0 ) {
specular = vec4(0.0, 0.0, 0.0, 1.0);
}
float factor = (maxFogDistance - eyeDistance) / (maxFogDistance - minFogDistance);
factor = clamp(factor, 0.0, 1.0);
vec4 finalFogColor = factor * fogColor;
vec4 finalColor = (ambient + specular) * texture2D(texture, texCoordOut);
gl_FragColor = finalColor * factor + fogColor * (1.0 - factor);
gl_FragColor.a = 1.0;
}
Additionally, the minimum fog distance has been set to 1f and the maximum to 10f (my movement space is quite small, currently 5x5, so this should be appropriate) and the fog color is set to white.
Any help anybody could provide would be much appreciated. I can post additional code if the problem isn't in the shaders (though, I can't figure anywhere else it would be, the other aspects of the shaders worked fine before this).
Could someone please help me with my OpenGL GLSL 4.0 shader. The problem i am having is when a 3d (0bj file) is loaded and rendered, all works(lighting good, mesh vertices display great) well except the normals of the mesh file. Specifically, when the obj file is rotated in its local/model space the normal does not appear to light mesh in accordance with the light position and its current orientation (I hope that makes some sense).
I believe the problem is with my normal matrix.
Problem: when my 3d mesh rotates, the lighting is meshed up(does not reflect the light position).
Any help would be much appreciated. Thank in advance
VertexShader
#version 400
//Handle translation, projection, etc
struct Matrix {
mat4 mvp;
mat4 mv;
mat4 view;
mat4 projection;
};
struct Light {
vec3 position;
vec3 color;
vec3 direction;
float intensity;
vec3 ambient;
};
//---------------------------------------------------
//INPUT
//---------------------------------------------------
//Per-Vertex Data
//---------------------------------------------------
layout (location = 0) in vec3 inputPosition;
layout (location = 1) in vec3 inputNormal;
layout (location = 2) in vec3 inputTexture;
//--------------------------------------------
// UNIFORM:INPUT Supplied Data from C++ application
//--------------------------------------------
uniform Matrix matrix;
uniform Light light;
uniform vec3 cameraPosition;
out vec3 fragmentNormal;
out vec3 cameraVector;
out vec3 lightVector;
out vec2 texCoord;
void main() {
// output the transformed vertex
gl_Position = matrix.mvp * vec4(inputPosition,1.0);
//When using, (vec3,0.0)
mat3 Normal_Matrix = mat3( transpose(inverse(matrix.mv)) );
// set the normal for the fragment shader and
// the vector from the vertex to the camera
vec3 vertex = (matrix.mv * vec4(inputPosition,1.0)).xyz;
//----------------------------------------------------------
//The problem (i think) is here
//----------------------------------------------------------
fragmentNormal = normalize(Normal_Matrix * inputNormal);
cameraVector = (matrix.mv *vec4(cameraPosition,1.0)).xyz - vertex ;
lightVector = vertex - (matrix.mv * vec4(light.position,1.0)).xyz;
//store the texture data
texCoord = inputTexture.xy;
}
Fragment Shader
#version 400
const int NUM_LIGHTS = 3;
const float MAX_DIST = 15.0;
const float MAX_DIST_SQUARED = MAX_DIST * MAX_DIST;
const vec3 AMBIENT = vec3(0.152, 0.152, 0.152); //0.2 for all component is a good dark value
struct Light {
vec3 position;
vec3 color;
vec3 direction;
float intensity;
vec3 ambient;
};
//the image
uniform sampler2D textureSampler;
uniform Light light;
//in: used interpolation, must define both in vertex&fragment shader;
out vec4 finalOutput;
in vec2 texCoord; //Texture Coordinate
//in: used interpolation, must define both in vertex&fragment shader;
in vec3 fragmentNormal;
in vec3 cameraVector;
in vec3 lightVector;
void main() {
vec4 texColor = texture2D(textureSampler, texCoord);
// initialize diffuse/specular lighting
vec3 diffuse = vec3(0.005f, 0.005f, 0.005f);
vec3 specular = vec3(0.00f, 0.00f, 0.00f);
// normalize the fragment normal and camera direction
vec3 normal = normalize(fragmentNormal);
vec3 cameraDir = normalize(cameraVector);
// loop through each light
// calculate distance between 0.0 and 1.0
float dist = min(dot(lightVector, lightVector), MAX_DIST_SQUARED) / MAX_DIST_SQUARED;
float distFactor = 1.0 - dist;
// diffuse
vec3 lightDir = normalize(lightVector);
float diffuseDot = dot(normal, lightDir);
diffuse += light.color * clamp(diffuseDot, 0.0, 1.0) * distFactor;
// specular
vec3 halfAngle = normalize(cameraDir + lightDir);
vec3 specularColor = min(light.color + 0.8, 1.0);
float specularDot = dot(normal, halfAngle);
specular += specularColor * pow(clamp(specularDot, 0.0, 1.0), 16.0) * distFactor;
vec4 sample0 = vec4(1.0, 1.0, 1.0, 1.0);
vec3 ambDifCombo = (diffuse + AMBIENT);
//calculate the final color
vec3 color = clamp(sample0.rgb * ambDifCombo + specular, 0.0, 1.0);
finalOutput = vec4(color * vec3(texColor), sample0.a);
}
You should not transform your light position. Your light should remain stationary while your mesh rotates. Instead of this:
lightVector = vertex - (matrix.mv * vec4(light.position,1.0)).xyz;
Do this:
lightVector = vertex - light.position;
I would also try not transforming your camera position too.