I'm using an FPS-like camera, this is the code:
CAMERA
mat4.identity(mat.mvMatrix);
mat4.rotate(mat.mvMatrix,degToRad(-camera.pitch),[1,0,0]);
mat4.rotate(mat.mvMatrix,degToRad(-camera.yaw),[0,1,0]);
mat4.translate(mat.mvMatrix,[-camera.pos[0],-camera.pos[1],-camera.pos[2]]);
The above code produces the model-view matrix as i roam the map (handling the camera position via WSAD style keys)
The uMVMatrix
from vertex shader is the passed mat.mvMatrix
from the above code.
I'm also using a shader for point lighting per-fragment in WebGL, the fragments are:
VS
vPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
gl_Position = uPMatrix * vPosition;
vTransformedNormal = uNMatrix * aVertexNormal;
// pass to fragment shader
vColorLight = uColorLight;
vColorAmbient = uColorAmbient;
vLightPosition = uLightPosition;
FS
vec3 lightDirection = normalize(vLightPosition - vPosition.xyz);
float directionalLightWeighting = max(dot(normalize(vTransformedNormal), lightDirection), 0.0);
vec3 lightWeighting = vColorAmbient + vColorLight * directionalLightWeighting;
vec4 textureColor = texture2D(uTex0, vec2(vTextureCoord.s, vTextureCoord.t));
gl_FragColor = vec4(textureColor.rgb * lightWeighting, textureColor.a);
The vLightPosition
is actually the camera's position (the light position moves as i move around)
I don't have a problem by moving around and putting correctly transformed objects.
But my lighting position seems to run away from me (i can't describe it better) as i roam the map. At position [0,0,0] is good, but as i move from there i can see actually the light source goes far away, and actually sinking (although i'm not changing my height =Y position)
Surprisingly, i solved the above problem by multiplying the input vLightPosition
by 0.00054687 (!) before i send it to shader, where it gave me a centered bulb in the terrain. I post 2 images to illustrate this:
When i multiply my light position by the above number...
var lightPosition = [5,2,5]; // just example
gl.uniform3f(gl.getUniformLocation(program,"uLightPosition"),
parseFloat(lightPosition[0])*0.00054687,
parseFloat(lightPosition[1])*0.00054687,
parseFloat(lightPosition[2])*0.00054687);
When i'm passing light position directly as camera position..
var lightPosition = [5,2,5]; // just example
gl.uniform3f(gl.getUniformLocation(program,"uLightPosition"),
parseFloat(lightPosition[0]),
parseFloat(lightPosition[1]),
parseFloat(lightPosition[2]));
In fact you can hardly see a light source that comes from far, far away (stones are lit).
It seems i need to scale down my input light position to microscope level, yet i dont understand why and though i solved it mostly by luck, i would like to know where's the problem to prevent future issues. Thanx
EDIT
My full shader fragments:
VS
precision mediump float;
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;
// lighting
uniform int uLightType;
// general
uniform vec3 uColorAmbient;
uniform vec3 uColorLight;
// directional light
uniform vec3 uLightDirection;
// point light
uniform vec3 uLightPosition;
varying vec3 vTransformedNormal;
varying vec4 vPosition;
// lighting on fragment shader
varying vec3 vColorAmbient;
varying vec3 vColorLight;
varying vec3 vLightPosition;
varying vec2 vTextureCoord;
varying vec3 vLightWeighting;
void main(void) {
vTextureCoord = aTextureCoord;
// none light
if (uLightType==0) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vLightWeighting = vec3(1.0, 1.0, 1.0);
}
// directional light
else if (uLightType==1) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vec3 transformedNormal = uNMatrix * aVertexNormal;
float directionalLightWeighting = max(dot(transformedNormal, uLightDirection), 0.0);
vLightWeighting = uColorAmbient + uColorLight * directionalLightWeighting;
}
// point light (per-fragment)
else if (uLightType==2) {
vPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
gl_Position = uPMatrix * vPosition;
vTransformedNormal = uNMatrix * aVertexNormal;
// pass to fragment shader
vColorLight = uColorLight;
vColorAmbient = uColorAmbient;
vLightPosition = uLightPosition;
// vLightPosition = uMVMatrix * uLightPosition;
// vLightPosition = uMVMatrix * vec4(uLightPosition, 1.0);
// vLightPosition = (uMVMatrix * uLightPosition).xyz;
vLightPosition = (uMVMatrix * vec4(uLightPosition, 1.0)).xyz;
}
}
FS
precision mediump float;
varying vec2 vTextureCoord;
varying vec3 vLightWeighting;
uniform sampler2D uTex0;
uniform int fLightType;
varying vec4 vPosition;
varying vec3 vTransformedNormal;
// lighting
varying vec3 vColorAmbient;
varying vec3 vColorLight;
varying vec3 vLightPosition;
void main(void) {
// point light (per-fragment)
if (fLightType==2) {
vec3 lightDirection = normalize(vLightPosition - vPosition.xyz);
float directionalLightWeighting = max(dot(normalize(vTransformedNormal), lightDirection), 0.0);
vec3 lightWeighting = vColorAmbient + vColorLight * directionalLightWeighting;
vec4 textureColor = texture2D(uTex0, vec2(vTextureCoord.s, vTextureCoord.t));
gl_FragColor = vec4(textureColor.rgb * lightWeighting, textureColor.a);
}
else {
vec4 textureColor = texture2D(uTex0, vec2(vTextureCoord.s, vTextureCoord.t));
gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);
}
}
EDIT2