Vertex animation texture with material plugin

yep!
that was the problem I should also bake normal and process in “CUSTOM_VERTEX_UPDATE_NORMAL” section

final material plugin is look like this

import { Material, MaterialDefines, MaterialPluginBase, ShaderLanguage, Texture, UniformBuffer } from "@babylonjs/core";

export default class VatMaterialPlugin extends MaterialPluginBase {
    texture: Texture
    normalTexture: Texture
    frame: number

    constructor(material: Material, texture: Texture, normalTexture: Texture) {
        super(material, "VatMaterialPlugin", 200, { VAT: false });
        this.texture = texture;
        this.normalTexture = normalTexture;

        this.texture.wrapU = Texture.WRAP_ADDRESSMODE;
        this.texture.wrapV = Texture.WRAP_ADDRESSMODE;

        this.frame = 0.0

        this._enable(true);
    }

    prepareDefines(defines: MaterialDefines) {
        defines["VAT"] = true;
    }

    getClassName() {
        return "VatMaterialPlugin";
    }

    getSamplers(samplers: string[]) {
        samplers.push("posTex", "norTex", "frame")
    }

    getAttributes(attributes: string[]) {
        attributes.push("indexX", "minMaxX", "minMaxY", "minMaxZ", "minMaxNX", "minMaxNY", "minMaxNZ")
    }

    bindForSubMesh(uniformBuffer: UniformBuffer): void {
        uniformBuffer.setTexture("posTex", this.texture);
        uniformBuffer.setTexture("norTex", this.normalTexture);
        uniformBuffer.updateFloat("frame", this.frame)
    }

    getUniforms() {
        return {
            "ubo": [
                { name: "frame", size: 1, type: "float" },
            ],
            "vertex":
                `#ifdef VAT
                    uniform float frame;
                #endif
                `,
        }
    }

    isCompatible(shaderLanguage: ShaderLanguage) {
        switch (shaderLanguage) {
            case ShaderLanguage.GLSL:
                return true;
            case ShaderLanguage.WGSL:
            default:
                return false;
        }
    }

    getCustomCode(shaderType: string, shaderLanguage: ShaderLanguage) {
        if (shaderType === "vertex") {
            if (shaderLanguage === ShaderLanguage.GLSL) {
                return {
                    "CUSTOM_VERTEX_DEFINITIONS": `
                    attribute float indexX;

                    attribute vec2 minMaxX;
                    attribute vec2 minMaxY;
                    attribute vec2 minMaxZ;

                    attribute vec2 minMaxNX;
                    attribute vec2 minMaxNY;
                    attribute vec2 minMaxNZ;

                    uniform sampler2D posTex;
                    uniform sampler2D norTex;
                `,
                    "CUSTOM_VERTEX_UPDATE_POSITION": `
                    vec4 texturePos = texture2D(posTex,vec2(indexX, 1.0 - frame));


                    float posX = texturePos.x * (minMaxX.y - minMaxX.x) + minMaxX.x;
                    float posY = texturePos.y * (minMaxY.y - minMaxY.x) + minMaxY.x;
                    float posZ = texturePos.z * (minMaxZ.y - minMaxZ.x) + minMaxZ.x;

                    positionUpdated = vec3(posX,posY,posZ);
                    `,
                    "CUSTOM_VERTEX_UPDATE_NORMAL": `
                    vec4 textureNor = texture2D(norTex,vec2(indexX, 1.0 - frame));

                    float norX = textureNor.x * (minMaxNX.y - minMaxNX.x) + minMaxNX.x;
                    float norY = textureNor.y * (minMaxNY.y - minMaxNY.x) + minMaxNY.x;
                    float norZ = textureNor.z * (minMaxNZ.y - minMaxNZ.x) + minMaxNZ.x;

                    normalUpdated = vec3(norX,norY,norZ);
                    `
                }
            }
        }
        return null;
    }
}

and small demo of result
source is also available in github