moai / moai-dev

This is the development repo of Moai SDK.
http://getmoai.com
943 stars 313 forks source link

1.7 - MOAIShaderProgram and MOAIShader - World transform matrix (GLOBAL_WORLD) not being set #1168

Closed sshukul closed 5 years ago

sshukul commented 8 years ago

As per the second to last entry in the forum post.

It looks like the World transform matrix is not being set or properly in the shader using the new MOAIShaderProgram class and the GLOBAL_WORLD enum introduced in 1.6, instead of the pre 1.6 UNIFORM_WORLD enum. It looks like the matrix may be getting initialised and bound in the shader but isn't getting updated for things like scale or rotation transforms.

I'm using it for a normal mapped point lighting shader which worked well pre-1.6 but with the changes the world matrix doesn't seem to account for such transforms (for example when the player prop is flipped to face another direction, the lighting flips with it instead of adjusting as if it kept coming from the same point).

Here is the full shader code:

function point_lighting_shader(lightx, lighty, lightz, intensity, range, red, green, blue, am_red, am_green, am_blue, move_with_prop, isBlack)  
  local fsh = [[  
    varying MEDP vec2 uvVarying;
    varying MEDP vec4 positionVarying;
    varying MEDP vec4 colourVarying;

    varying MEDP vec4 light;
    varying MEDP vec3 lightColour;

    uniform MEDP float isBlack;
    uniform sampler2D diffuseMap;
    uniform sampler2D normalMap;

    uniform float light_intensity, light_range;

    uniform MEDP float ambientColourR;
    uniform MEDP float ambientColourG;
    uniform MEDP float ambientColourB;

    vec2 resolution = vec2(1.0, 1.0);
    vec3 attenuation = vec3(1.0, 1.0, 1.0);

    void main()
    {
        //sample color & normals from our textures
        vec4 color = texture2D(diffuseMap, uvVarying);
        vec3 nColor = texture2D(normalMap, uvVarying).rgb;

        //normals need to be converted to [-1.0, 1.0] range and normalized
        vec3 normal = normalize(nColor * 2.0 - 1.0);

        //here we do a simple distance calculation
        vec3 deltaPos = vec3(light.xy - positionVarying.xy, light.z );

        float vertex_dist = length (deltaPos);

        //gl_FragColor = vec4(deltaPos, light.a);
        // Decay light factor depending on the vertex distance from light source
        float decay = max( 0.0, (light_range - vertex_dist )/ light_range ) * 2.0;

        vec3 lightDir = normalize(deltaPos);
        float lambert = clamp(dot(normal, lightDir), 0.0, 1.0);

        //now let's get a nice little falloff
        float d = sqrt(dot(deltaPos, deltaPos));      
        float att = ( attenuation.x + (attenuation.y*d) + (attenuation.z*d*d) );

        vec3 ambientColor = vec3(ambientColourR, ambientColourG, ambientColourB);

        vec3 result = ambientColor + (lightColour.rgb * lambert * light_intensity * decay) * att;
        result *= color.rgb;

        if(isBlack == 1.0)
          result *= vec3(.35, .35, .35);

        gl_FragColor = vec4(result, color.a);

    }
  ]]

  local vsh = [[ 
    attribute vec4 position;
    attribute vec2 uv;

    uniform MEDP float lightX;
    uniform MEDP float lightY;
    uniform MEDP float lightZ;

    uniform MEDP float lightColourR;
    uniform MEDP float lightColourG;
    uniform MEDP float lightColourB;

    uniform MEDP float moveWithProp;

    uniform mat4 worldMatrix;               // Sum of all MOAITransforms on object

    varying vec2 uvVarying;
    varying vec4 positionVarying;   
    varying vec4 light;
    varying vec3 lightColour;

    void main () {
      uvVarying = uv;

      positionVarying = position * worldMatrix;

      if(moveWithProp > 0.0)
        light = positionVarying + vec4(lightX, lightY, lightZ, 1.0);
      else
        light = vec4(lightX, lightY, lightZ, 1.0) * worldMatrix;

      lightColour = vec3(lightColourR, lightColourG, lightColourB);

      gl_Position = position;
    }
  ]]

  local shader = MOAIShader.new ()

  if MOAIShaderProgram then
    -- V1.6
    local program = MOAIShaderProgram.new ()
    program:setVertexAttribute ( 1, 'position' )
    program:setVertexAttribute ( 2, 'uv' )
    program:setVertexAttribute ( 3, 'colour' )

    program:reserveUniforms ( 16 )

    program:declareUniformSampler( 1, 'diffuseMap', 1 )
    program:declareUniformSampler( 2, 'normalMap', 2 )
    program:declareUniformFloat( 3, 'lightX', lightx )
    program:declareUniformFloat( 4, 'lightY', lighty )
    program:declareUniformFloat( 5, 'lightZ', lightz )
    program:declareUniformFloat( 6, 'lightColourR', red)
    program:declareUniformFloat ( 7, 'lightColourG', green )
    program:declareUniformFloat( 8, 'lightColourB', blue )
    program:declareUniformFloat( 9, 'light_intensity', (intensity * .4) )
    program:declareUniformFloat( 10, 'light_range', range )
    program:declareUniformFloat( 11, 'ambientColourR', am_red)
    program:declareUniformFloat( 12, 'ambientColourG', am_green )
    program:declareUniformFloat( 13, 'ambientColourB', am_blue )

    if move_with_prop then
      program:declareUniformFloat( 14, 'moveWithProp', 1.0)
    else 
      program:declareUniformFloat( 14, 'moveWithProp', 0.0)
    end

    if isBlack then
      program:declareUniformFloat( 15, 'isBlack', 1.0)
    else 
      program:declareUniformFloat( 15, 'isBlack', 0.0)
    end 

    program:declareUniform(16, 'worldMatrix', MOAIShaderProgram.UNIFORM_MATRIX_F4 )

    program:reserveGlobals(1)
    program:setGlobal( 1, 16, MOAIShaderProgram.GLOBAL_WORLD )

    program:load ( vsh, fsh )

    shader:setProgram(program)
  else
    shader:setVertexAttribute ( 1, 'position' )
    shader:setVertexAttribute ( 2, 'uv' )
    shader:setVertexAttribute ( 3, 'colour' )

    shader:reserveUniforms ( 16 )

    shader:declareUniformSampler( 1, 'diffuseMap', 1 )
    shader:declareUniformSampler( 2, 'normalMap', 2 )
    shader:declareUniformFloat( 3, 'lightX', lightx )
    shader:declareUniformFloat( 4, 'lightY', lighty )
    shader:declareUniformFloat( 5, 'lightZ', lightz )

    shader:declareUniformFloat( 6, 'lightColourR', red)
    shader:declareUniformFloat ( 7, 'lightColourG', green )
    shader:declareUniformFloat( 8, 'lightColourB', blue )
    shader:declareUniformFloat( 9, 'light_intensity', (intensity * .4) )
    shader:declareUniformFloat( 10, 'light_range', range )
    shader:declareUniformFloat( 11, 'ambientColourR', am_red)
    shader:declareUniformFloat( 12, 'ambientColourG', am_green )
    shader:declareUniformFloat( 13, 'ambientColourB', am_blue )

    if move_with_prop then
      shader:declareUniformFloat( 14, 'moveWithProp', 1.0)
    else 
      shader:declareUniformFloat( 14, 'moveWithProp', 0.0)
    end

    shader:declareUniform( 15, 'worldMatrix', MOAIShader.UNIFORM_WORLD )

    if isBlack then
      shader:declareUniformFloat( 16, 'isBlack', 1.0)
    else 
      shader:declareUniformFloat( 16, 'isBlack', 0.0)
    end

    shader:load ( vsh, fsh )
  end

  return shader
end

Is this a bug or does the transform matrix need to be set differently somehow?

Many thanks for looking into it, as of now I am unable to release on iOS without upgrading to 1.6 because of 64 bit compilation, and this is holding it back.

sshukul commented 8 years ago

So I looked into this a bit more and got the issue "semi-fixed" now by adding this to line 241 of MOAIGfxDeviceMtxCache.cpp inside SetVertexTransform() :

 this->UpdateShaderGlobals ();

It looks like there was an UpdatePipelineTransforms() call at the end of the SetVertexTransform() function in 1.5 but this is missing from 1.7. The UpdateShaderGlobals() function looks like it's new equivalent.

This almost fixes the issue to where the world global is being updated for things like scale.

The problem is it's not consistent and occasionally doesn't update ... for example, in my game I've got a player character that's made of a MOAITransform which is the parent to many separate MOAIProp2D objects for the body parts (like head, arms, legs etc.). It's done that way using a Moai plugin for Spriter. With this new fix, the world transform updates most of the time, but after a few switches back and forth to the scale, one of the props will not get the updated transform, so it's lighting is backwards compared to the rest of the body, like so:

http://i.imgur.com/4mY2wp2.jpg

Notice the shoulder / upper arm prop is lighted backwards compared to the rest ... this is because it's GLOBAL_WORLD matrix is not being updated in the shader after the -1 scale is applied to the prop, even when the rest of the props are updated with the correct matrix value.

Any guesses as to why this could be happening or where I should look to investigate further guys? This has me stumped for the last few days even after making what looks like progress on the issue.

sshukul commented 8 years ago

I can confirm this issue is somehow fixed in the latest version, closing.

sshukul commented 7 years ago

Nope sorry, not fixed, still reproduceable. If someone is willing to look into this I can provide some sample code to reproduce, thanks.

sshukul commented 7 years ago

This is finally fixed in Moai 2.0! Will mark as closed once merged into moai-dev.