Dear babylonJs developers.
I am very happy to share my first post.
I am a babylonJs beginner and need your help.
I tried to create a createCustomMaterial function and apply normal map/roughness map but normal map is not working at all.
I don’t know what is causing this. Please take a look at my current code and give me some advice.
Thanks.
// Modified createCustomMaterial to preserve original material name
function createCustomMaterial(originalMaterial, scene) {
const originalName = originalMaterial.name;
BABYLON.Effect.ShadersStore[originalName + "VertexShader"] = `
precision highp float;
attribute vec3 position;
attribute vec2 uv;
attribute vec2 uv2;
attribute vec3 normal;
attribute vec3 tangent;
uniform mat4 world;
uniform mat4 viewProjection;
uniform mat4 view;
varying vec2 vUV;
varying vec2 vUV2;
varying vec3 vNormal;
varying vec3 vPosition;
varying vec3 vTangent;
varying vec3 vBitangent;
void main() {
vec4 worldPos = world * vec4(position, 1.0);
gl_Position = viewProjection * worldPos;
vUV = uv;
vUV2 = uv2;
vNormal = normalize(mat3(world) * normal);
vTangent = normalize(mat3(world) * tangent);
vBitangent = cross(vNormal, vTangent);
vPosition = worldPos.xyz;
}
`;
BABYLON.Effect.ShadersStore[originalName + "FragmentShader"] = `
precision highp float;
varying vec2 vUV;
varying vec2 vUV2;
varying vec3 vNormal;
varying vec3 vPosition;
varying vec3 vTangent;
varying vec3 vBitangent;
uniform vec3 baseColor;
uniform sampler2D patternTexture;
uniform vec3 patternTint;
uniform sampler2D lightmapTexture;
uniform float lightmapIntensity;
uniform bool hasPattern;
uniform sampler2D normalMap;
uniform sampler2D roughnessMap;
uniform bool hasRoughnessMap;
uniform sampler2D specularMap;
uniform bool hasSpecularMap;
uniform vec3 cameraPosition;
void main() {
// Normal mapping
vec3 normalMapColor = texture2D(normalMap, vUV).rgb;
vec3 normalFromMap = normalize(normalMapColor * 2.0 - 1.0);
mat3 TBN = mat3(normalize(vTangent), normalize(vBitangent), normalize(vNormal));
vec3 normal = normalize(TBN * normalFromMap);
// Base color calculation
vec3 finalColor = baseColor;
if (hasPattern) {
vec4 pattern = texture2D(patternTexture, vUV);
finalColor = mix(baseColor, patternTint * pattern.rgb, pattern.a);
}
// View direction for specular
vec3 viewDir = normalize(cameraPosition - vPosition);
vec3 reflectDir = reflect(-viewDir, normal);
// Roughness and specular calculation
float roughness = hasRoughnessMap ? texture2D(roughnessMap, vUV).r : 0.5;
float shininess = (1.0 - roughness) * 256.0;
float specularStrength = hasSpecularMap ? texture2D(specularMap, vUV).r : 1.0;
float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
vec3 specularColor = vec3(specularStrength * spec);
// Combine all lighting components
finalColor = finalColor + specularColor;
// Apply lightmap
vec3 lightmap = texture2D(lightmapTexture, vUV2).rgb * lightmapIntensity;
finalColor *= lightmap;
gl_FragColor = vec4(finalColor, 1.0);
}
`;
const material = new BABYLON.ShaderMaterial(originalName, scene, {
vertex: originalName,
fragment: originalName,
}, {
attributes: ["position", "normal", "uv", "uv2", "tangent"],
uniforms: [
"world",
"viewProjection",
"view",
"baseColor",
"patternTint",
"lightmapIntensity",
"hasPattern",
"cameraPosition",
"hasRoughnessMap",
"hasSpecularMap"
],
samplers: [
"patternTexture",
"lightmapTexture",
"normalMap",
"roughnessMap",
"specularMap"
],
defines: []
});
// Copy properties from original material if possible
if (originalMaterial instanceof BABYLON.StandardMaterial) {
const color = originalMaterial.diffuseColor || RESET_COLOR;
material.setVector3("baseColor", new BABYLON.Vector3(color.r, color.g, color.b));
if (originalMaterial.diffuseTexture) {
material.setTexture("patternTexture", originalMaterial.diffuseTexture);
material.setFloat("hasPattern", 1);
} else {
material.setFloat("hasPattern", 0);
}
} else {
material.setVector3("baseColor", new BABYLON.Vector3(1.0, 1.0, 1.0));
material.setFloat("hasPattern", 0);
}
material.setVector3("patternTint", new BABYLON.Vector3(1, 1, 1));
material.setFloat("lightmapIntensity", 1.0);
material.setFloat("hasRoughnessMap", 0);
material.setFloat("hasSpecularMap", 0);
return material;
}
const normalTexture = new BABYLON.Texture(
data.texture.normal.content,
currentScene,
true,
false,
BABYLON.Texture.TRILINEAR_SAMPLINGMODE
);
normalTexture.wrapU = normalTexture.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
material.setTexture("normalMap", normalTexture);