Search code examples
shaderfragment-shadervertex-shaderpixel-shaderglsles

GLSL ES update object positions


lately I've been working on a per pixel point light shader. And it all works perfectly as it should, for the exception that if I change the position of a model, the position itself doesn't seem to update in the shader.

Some information that could help fixing the problem: The model itself isn't drawn in the shader, I import the data of the drawn model.

Shader vertex code:

attribute vec3 in_Position;                  // (x,y,z)
attribute vec3 in_Normal;                    // (x,y,z)     unused in this shader.
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec3 v_vPosition;
varying vec3 v_vNormal;
varying vec4 v_vColour;

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;

    v_vColour = in_Colour;
    v_vPosition = in_Position;

    v_vNormal = in_Normal;
    v_vTexcoord = in_TextureCoord;
}

Shader fragment code:

varying vec2 v_vTexcoord;
varying vec3 v_vPosition;
varying vec3 v_vNormal;
varying vec4 v_vColour;

uniform vec3 Light_Pos;
uniform vec3 Ball_Pos;

vec4 lightIntensity(vec3 ploc,vec3 plig,vec3 col,float rad,vec3 norm){
    float dist = distance(ploc,plig);
    float intens = max((rad-dist)/rad*0.8,0.0);

    vec3 l = vec3(normalize(plig - ploc));

    intens = intens*max(dot(norm,l), 0.0);
    vec4 res = vec4(col.x,col.y,col.z,intens);

    return res;
}

void main()
{
    vec3 pos = v_vPosition;
    vec3 norm = normalize(v_vNormal);
    vec4 col = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
    vec4 lcol = vec4(col.r,col.g,col.b,0.0);

    vec4 intens;

    intens = lightIntensity(pos,Light_Pos,vec3(1.0,0.0,0.0),40.0,   v_vNormal);
    lcol = vec4((lcol.x+intens.x*(intens.w+0.2))/(1.2+intens.w)
        ,(lcol.y+intens.y*(intens.w+0.2))/(1.2+intens.w)
        ,(lcol.z+intens.z*(intens.w+0.2))/(1.2+intens.w),lcol.w+intens.w);

    intens = lightIntensity(pos,vec3(10.0,-10.0,10.0),vec3(0.0,0.0,1.0),40.0,   v_vNormal);
    lcol = vec4((lcol.x+intens.x*(intens.w+0.2))/(1.2+intens.w)
        ,(lcol.y+intens.y*(intens.w+0.2))/(1.2+intens.w)
        ,(lcol.z+intens.z*(intens.w+0.2))/(1.2+intens.w),lcol.w+intens.w);

    gl_FragColor = vec4(lcol.x*lcol.w,lcol.y*lcol.w,lcol.z*lcol.w,col.a);
}

It seems like the v_vPosition is always like the model is at xyz equals 0. Because when the location of the ball isn't at the zero point, it will still have lighting on it like it is at the zero point.

Here's a gif of the shader doing it's job (as you can see, I didn't change the location of the ball for this reason): https://i.sstatic.net/HFUsE.jpg


Solution

  • Your vertex shader is setting v_vPosition to the position of the vertices in model space. Most likely, what you intended was to use the position of the vertices in world space.

    Your vertex shader needs to transform the position using the world matrix. So the line:

    v_vPosition = in_Position;
    

    Might become something like:

    v_vPosition = gm_Matrices[MATRIX_WORLD] * object_space_pos;