0
\$\begingroup\$

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);

enter image description here

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]));

enter image description here

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

enter image description here

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$
vec3 lightDirection = normalize(vLightPosition - vPosition.xyz);

vPosition is in view/camera space, vLightPosition is in world space, hence the buggy results.

You need to transform your light from world coordinates to view coordinates, i.e. multiply the light coordinates by the view matrix (just as you multiplied the position by the model-view matrix).

\$\endgroup\$
12
  • \$\begingroup\$ I did vLightPosition = uMVMatrix * uLightPosition but since light position is a vec3 and not vec4 (like vPosition) it doesnt allow me. \$\endgroup\$
    – user43436
    Commented Mar 17, 2014 at 23:49
  • \$\begingroup\$ So make it a vec4: uMVMatrix * vec4(vLightPosition, 1.0); \$\endgroup\$
    – Fault
    Commented Mar 17, 2014 at 23:51
  • \$\begingroup\$ I tried that too with error ERROR: 0:56: 'assign' : cannot convert from '-component vector of float' to 'varying mediump -component vector of float' \$\endgroup\$
    – user43436
    Commented Mar 17, 2014 at 23:55
  • \$\begingroup\$ It's probably complaining about trying to assign a vec4 to a vec3. Try it like this: vLightPosition = (uMVMatrix * vec4(uLightPosition, 1.0)).xyz; \$\endgroup\$
    – Fault
    Commented Mar 17, 2014 at 23:58
  • \$\begingroup\$ Lots of errors now :). They are: ERROR: 0:57: '*' : wrong operand types no operation '*' exists that takes a left-hand operand of type 'uniform mediump X matrix of float' and a right operand of type 'uniform mediump -component vector of float' (or there is no acceptable conversion) ERROR: 0:57: 'xyz' : illegal length of matrix field selection ERROR: 0:57: 'assign' : cannot convert from 'float' to 'varying mediump -component vector of float' \$\endgroup\$
    – user43436
    Commented Mar 18, 2014 at 0:00

You must log in to answer this question.