hello there
i’m currently working on custom vertex animation texture
the process is like this
- import animated 3d models into bledner
- run custom python script that export glb file and bake animation on png file
- import glb file and texture into babylon
- run animation with help of GPU “vertex shader”
at begin i do all of that with shader material
and work very well in amination section
import { Effect, ShaderMaterial, Texture } from "@babylonjs/core";
import Editor from "./Editor";
export default class VatMaterial extends ShaderMaterial {
constructor(name: string, textureName: string) {
const { scene, assetManager } = Editor.GetInstance()
super(name, scene, "vat", {
attributes: ["position", "normal", "uv", "indexX", "minMaxX", "minMaxY", "minMaxZ"],
defines: ["#define INSTANCES"],
uniforms: ["worldViewProjection", "posTex", "frame"]
});
Effect.ShadersStore.vatVertexShader = `
precision highp float;
attribute vec3 position;
attribute vec2 uv;
attribute float indexX;
attribute vec2 minMaxX;
attribute vec2 minMaxY;
attribute vec2 minMaxZ;
uniform mat4 worldViewProjection;
uniform sampler2D posTex;
uniform float frame;
uniform float posTexWidth;
uniform float posTexHeight;
void main() {
vec4 texturePos = texture2D(posTex,vec2(indexX, 1.0 - frame));
float minX = minMaxX.x;
float maxX = minMaxX.y;
float minY = minMaxY.x;
float maxY = minMaxY.y;
float minZ = minMaxZ.x;
float maxZ = minMaxZ.y;
float posX = texturePos.x * (maxX - minX) + minX;
float posY = texturePos.y * (maxY - minY) + minY;
float posZ = texturePos.z * (maxZ - minZ) + minZ;
// gl_Position = worldViewProjection * vec4(position.x,position.y,position.z, 1.0);
gl_Position = worldViewProjection * vec4(posX,posY,posZ, 1.0);
}`;
Effect.ShadersStore.vatPixelShader = `
precision highp float;
void main(void) {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}`;
const posTexture = assetManager.getTexture(textureName)
posTexture.wrapU = Texture.WRAP_ADDRESSMODE;
posTexture.wrapV = Texture.WRAP_ADDRESSMODE;
const size = posTexture.getSize()
this.setTexture("posTex", posTexture);
this.setFloat("posTexWidth", size.width);
this.setFloat("posTexHeight", size.height);
let a = 0
scene.onBeforeRenderObservable.add(() => {
a += 0.002
if (a > 1) a = 0.0
this.setFloat("frame", a)
})
}
}
but material do not render good picture
because of fragment shader
after some research i find out
i can customize default materials with
help of “Material Plugin”
import { Material, MaterialDefines, MaterialPluginBase, ShaderLanguage, Texture, UniformBuffer } from "@babylonjs/core";
export default class VatMaterialPlugin extends MaterialPluginBase {
texture: Texture
textureWidth: number
textureHeight: number
frame: number
constructor(material: Material, texture: Texture) {
super(material, "VatMaterialPlugin", 200, { VAT: false });
this.texture = texture;
this.texture.wrapU = Texture.WRAP_ADDRESSMODE;
this.texture.wrapV = Texture.WRAP_ADDRESSMODE;
const size = this.texture.getSize()
this.textureWidth = size.width
this.textureHeight = size.height
this.frame = 0.0
this._enable(true);
}
prepareDefines(defines: MaterialDefines) {
defines["VAT"] = true;
}
getClassName() {
return "VatMaterialPlugin";
}
getSamplers(samplers: string[]) {
samplers.push("posTex", "posTexWidth", "posTexHeight", "frame")
}
getAttributes(attributes: string[]) {
attributes.push("indexX", "minMaxX", "minMaxY", "minMaxZ")
}
bindForSubMesh(uniformBuffer: UniformBuffer): void {
uniformBuffer.setTexture("posTex", this.texture);
uniformBuffer.updateFloat("posTexWidth", this.textureWidth);
uniformBuffer.updateFloat("posTexHeight", this.textureHeight);
uniformBuffer.updateFloat("frame", this.frame)
}
getUniforms() {
return {
"ubo": [
{ name: "posTexWidth", size: 1, type: "float" },
{ name: "posTexHeight", size: 1, type: "float" },
{ name: "frame", size: 1, type: "float" },
],
"vertex":
`#ifdef VAT
uniform float posTexWidth;
uniform float posTexHeight;
uniform float frame;
#endif
`,
}
}
// This is used to inform the system which language is supported
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;
uniform mat4 worldViewProjection;
uniform sampler2D posTex;
`,
"CUSTOM_VERTEX_MAIN_END": `
vec4 texturePos = texture2D(posTex,vec2(indexX, 1.0 - frame));
float minX = minMaxX.x;
float maxX = minMaxX.y;
float minY = minMaxY.x;
float maxY = minMaxY.y;
float minZ = minMaxZ.x;
float maxZ = minMaxZ.y;
float posX = texturePos.x * (maxX - minX) + minX;
float posY = texturePos.y * (maxY - minY) + minY;
float posZ = texturePos.z * (maxZ - minZ) + minZ;
gl_Position = worldViewProjection * vec4(posX,posY,posZ, 1.0);
`
}
}
}
return null;
}
}
but is not working at all
i think problem is with my “worldViewProjection”
is that valid way to import that like this “uniform mat4 worldViewProjection;”
or should I passed some way to my material plugin?
source code is available on github
thanks for helping