GLSL dot product in normalMatrix space


I was trying to make the UV of a plane slide according to its orientation relative to the down vector (0, -1, 0) (just like a liquid would flow on a surface).
For this, I use the tangent and bitangent in order to deduce how much they are colinear to this down vector, and make UV slide according to the dot values. When I am applying a rotation to the geometry before computing the tangent, the shader gives nice results. If I apply the rotation to the mesh instead, it does not work anymore, even though I projected every vectors into the base of the normalMatrix.

here are two images explaining the problem:

You can see the shaders below:

 uniforms: THREE.UniformsUtils.merge(
                normalMap: { value: null },
                uTime: { value: 0 }

    vertex: [
        'attribute vec4 tangent;',

        'varying vec3 vNormal;',
        'varying vec3 vTangent;',
        'varying vec3 vBinormal;',
        'varying vec2 vUv;',

        'varying vec3 vViewPosition;',

        'varying vec3 vDown;',

        'const vec3 DOWN = vec3(0.0, -1.0, 0.0);',

        'void main() {',

            'vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',

            'vViewPosition =;',

            'vNormal = normalize(normalMatrix * normal);',
            'vTangent = normalize(normalMatrix *;',
            'vBinormal = normalize(cross(vNormal, vTangent) * tangent.w);',
            'vDown = normalize(normalMatrix * DOWN);',
            'vUv = uv;',

            'gl_Position = projectionMatrix * mvPosition;',


    ].join( '\n' ),

    fragment: [

        '#define USE_NORMALMAP',

        'varying vec3 vNormal;',
        'varying vec3 vTangent;',
        'varying vec3 vBinormal;',
        'varying vec2 vUv;',

        'varying vec3 vViewPosition;',
        'varying vec3 vDown;',

        'uniform float uTime;',


        'void main() {',


            'float uSlide = dot(vTangent, vDown);',
            'float vSlide = dot(vBinormal, vDown);',
            'vec2 slideUV = vUv + vec2(-uSlide, -vSlide) * uTime;',

            '//#if NUM_DIR_LIGHTS > 0',
            '//for( int i = 0; i < NUM_DIR_LIGHTS; i++ ) {',

            'gl_FragColor = vec4(texture2D( normalMap, slideUV ).xyz, 0.65);',
            '//gl_FragColor = vec4(vec3(vTangent), 1.0);',



    ].join( '\n' )

I know the normalMatrix take the view into account, but the normalMatrix should be orthonormal and so projecting each vectors using it should not change the dot product. However, when I display the uSlide dot product, it is clear that is depend on the view.

If someone can help me figure out what’s the problem, it would be very nice, Thanks!

I finally found my mistake myself, I let it here for everyone looking for a way to achieve what I wanted to achieve. The key is just to replace, in the vertex shader:
'vDown = normalize(normalMatrix * DOWN);',
’vDown = normalize(viewMatrix * DOWN);’,

Obviously, projecting the DOWN vector into the model space was a non-sense!