Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 126 additions & 67 deletions api/material.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -138,6 +138,20 @@ export const flockMaterial = {
if (flock.sky) {
flock.glowLayer.addExcludedMesh(flock.sky);
}
flock.glowLayer.customEmissiveColorSelector = (
mesh,
_subMesh,
_material,
result,
) => {
const glowColor = mesh.metadata?.glowColor;
if (glowColor) {
const c = flock.BABYLON.Color3.FromHexString(glowColor);
result.set(c.r, c.g, c.b, 1);
} else {
result.set(0, 0, 0, 0);
}
};
}

return new Promise((resolve) => {
Expand All@@ -152,29 +166,66 @@ export const flockMaterial = {
});
});
},
getMaterialParamsFromMesh(mesh) {
const mat = mesh.material;
if (!mat) return null;

if (mat.metadata?.cacheKey) {
const parts = mat.metadata.cacheKey.split("_");
const lastPart = parts[parts.length - 1];
const hasGlowPart = lastPart === "glow" || lastPart === "noglow";
const colorPart = parts[1];
const color = colorPart.includes("-")
? colorPart.split("-")
: colorPart;
const parsedAlpha = parseFloat(parts[2]);
return {
color,
materialName:
mat.metadata.texName ||
parts.slice(3, hasGlowPart ? -1 : parts.length).join("_") ||
"none.png",
alpha: Number.isFinite(parsedAlpha) ? parsedAlpha : (mat.alpha ?? 1),
glow: hasGlowPart ? lastPart === "glow" : (mesh.metadata?.glow ?? false),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
};
}

const matColor = mat.diffuseColor || mat.albedoColor;
const textureName =
mat.diffuseTexture?.name?.split("/").pop() ||
mat.albedoTexture?.name?.split("/").pop() ||
"none.png";
return {
color: matColor ? "#" + matColor.toHexString().slice(1) : "#ffffff",
materialName: textureName,
alpha: mat.alpha ?? 1,
glow: mesh.metadata?.glow ?? false,
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
glowMesh(mesh, glowColor = null) {
const applyGlow = (m) => {
m.metadata = m.metadata || {};
m.metadata.glow = true;

if (m.material) {
const currentMat = m.material;
const color = glowColor
? flock.getColorFromString(glowColor)
: currentMat.diffuseColor
? "#" + currentMat.diffuseColor.toHexString().slice(1)
: currentMat.albedoColor
? "#" + currentMat.albedoColor.toHexString().slice(1)
: "#ffffff";

const params = m.material ? flock.getMaterialParamsFromMesh(m) : null;
const baseColor = params?.color;
m.metadata.glowColor = glowColor
? flock.getColorFromString(glowColor)
: Array.isArray(baseColor)
? flock.getColorFromString(baseColor[0])
: baseColor
? flock.getColorFromString(baseColor)
: "#ffffff";

if (params) {
const materialParams = {
color: color,
materialName:
currentMat.metadata?.cacheKey?.split("_")[3] || "none.png",
alpha: currentMat.alpha ?? 1,
...params,
color:
glowColor && !Array.isArray(baseColor)
? flock.getColorFromString(glowColor)
: baseColor,
glow: true,
};

flock.setMaterialWithCleanup(m, materialParams);
}
};
Expand All@@ -192,34 +243,10 @@ export const flockMaterial = {
);

allMeshes.forEach((nextMesh) => {
const oldMat = nextMesh.material;
if (!oldMat) return;

let color, texPart, glowFlag;

if (oldMat.metadata?.cacheKey) {
const parts = oldMat.metadata.cacheKey.split("_");
const colorPart = parts[1];
texPart = parts[3];
glowFlag = parts[4] === "glow";
color = colorPart.includes("-") ? colorPart.split("-") : colorPart;
} else {
// Raw GLTF material (e.g. character with no managed material yet)
// Extract color from the material directly
const matColor = oldMat.diffuseColor || oldMat.albedoColor;
color = matColor
? "#" + matColor.toHexString().slice(1)
: "#ffffff";
texPart = "none.png";
glowFlag = nextMesh.metadata?.glow ?? false;
}
if (!nextMesh.material) return;

const materialParams = {
color: color,
materialName: texPart,
alpha: value,
glow: glowFlag,
};
const params = flock.getMaterialParamsFromMesh(nextMesh);
const materialParams = { ...params, alpha: value };

flock.setMaterialWithCleanup(nextMesh, materialParams);

Expand All@@ -240,20 +267,8 @@ export const flockMaterial = {
console.log(`Clear effects from ${meshName}:`);
const removeEffects = (targetMesh) => {
if (targetMesh.material) {
const currentMat = targetMesh.material;
const color = currentMat.diffuseColor
? "#" + currentMat.diffuseColor.toHexString().slice(1)
: currentMat.albedoColor
? "#" + currentMat.albedoColor.toHexString().slice(1)
: "#ffffff";

const materialParams = {
color: color,
materialName:
currentMat.metadata?.cacheKey?.split("_")[3] || "none.png",
alpha: 1,
glow: false,
};
const params = flock.getMaterialParamsFromMesh(targetMesh);
const materialParams = { ...params, alpha: 1, glow: false };

flock.setMaterialWithCleanup(targetMesh, materialParams);

Expand All@@ -265,6 +280,7 @@ export const flockMaterial = {

targetMesh.metadata = targetMesh.metadata || {};
targetMesh.metadata.glow = false;
delete targetMesh.metadata.glowColor;

if (flock.glowLayer) {
const anyGlowing = flock.scene.meshes.some(
Expand DownExpand Up@@ -968,30 +984,45 @@ export const flockMaterial = {
return material;
},
createMultiColorGradientMaterial(name, colors) {
// Register shaders once under dedicated keys to avoid collision with createMultiGradientShaderMaterial
if (!flock.BABYLON.Effect.ShadersStore["multiColorGradientVertexShader"]) {
flock.BABYLON.Effect.ShadersStore["multiColorGradientVertexShader"] = `
if (
!flock.BABYLON.Effect.ShadersStore["multiColorGradientFogVertexShader"]
) {
flock.BABYLON.Effect.ShadersStore["multiColorGradientFogVertexShader"] = `
precision highp float;
attribute vec3 position;
uniform mat4 worldViewProjection;
uniform mat4 world;
uniform mat4 view;
uniform vec2 minMax;
varying float vGradient;
varying vec3 vFogPosition;

void main(void) {
vec4 worldPosition = world * vec4(position, 1.0);
vec4 viewPosition = view * worldPosition;
gl_Position = worldViewProjection * vec4(position, 1.0);
vGradient = (position.y - minMax.x) / (minMax.y - minMax.x);
vFogPosition = viewPosition.xyz;
}
`;
}
if (
!flock.BABYLON.Effect.ShadersStore["multiColorGradientFragmentShader"]
!flock.BABYLON.Effect.ShadersStore["multiColorGradientFogFragmentShader"]
) {
flock.BABYLON.Effect.ShadersStore["multiColorGradientFragmentShader"] = `
flock.BABYLON.Effect.ShadersStore[
"multiColorGradientFogFragmentShader"
] = `
precision highp float;
varying float vGradient;
varying vec3 vFogPosition;
uniform int colorCount;
uniform vec3 colors[16];
uniform float alpha;
uniform vec3 fogColor;
uniform float fogDensity;
uniform float fogStart;
uniform float fogEnd;
uniform int fogMode;

void main(void) {
float t = clamp(vGradient, 0.0, 1.0);
Expand All@@ -1013,7 +1044,19 @@ export const flockMaterial = {
vec3 color2 = colors[segment + 1];
vec3 finalColor = mix(color1, color2, localT);

gl_FragColor = vec4(finalColor, alpha);
float fogDistance = length(vFogPosition);
float fogFactor = 1.0;
if (fogMode == 1) {
fogFactor = exp(-fogDensity * fogDistance);
} else if (fogMode == 2) {
fogFactor = exp(-pow(fogDensity * fogDistance, 2.0));
} else if (fogMode == 3) {
fogFactor = (fogEnd - fogDistance) / max(0.0001, fogEnd - fogStart);
}
fogFactor = clamp(fogFactor, 0.0, 1.0);

vec3 foggedColor = mix(fogColor, finalColor, fogFactor);
gl_FragColor = vec4(foggedColor, alpha);
}
`;
}
Expand All@@ -1022,17 +1065,24 @@ export const flockMaterial = {
name,
flock.scene,
{
vertex: "multiColorGradient",
fragment: "multiColorGradient",
vertex: "multiColorGradientFog",
fragment: "multiColorGradientFog",
},
{
attributes: ["position"],
uniforms: [
"worldViewProjection",
"world",
"view",
"colorCount",
"colors",
"alpha",
"minMax",
"fogColor",
"fogDensity",
"fogStart",
"fogEnd",
"fogMode",
],
},
);
Expand All@@ -1057,6 +1107,9 @@ export const flockMaterial = {
shaderMaterial.setFloat("alpha", 1.0);
shaderMaterial.setVector2("minMax", new flock.BABYLON.Vector2(-1, 1));

flock.registerFogAwareShaderMaterial(shaderMaterial);
flock.updateFogUniformsForShaderMaterial(shaderMaterial);

return shaderMaterial;
},
// Create shader material for color replacement
Expand DownExpand Up@@ -1495,6 +1548,7 @@ export const flockMaterial = {
if (!newMat.metadata) newMat.metadata = {};
newMat.metadata.cacheKey = cacheKey;
newMat.metadata.isManaged = true;
newMat.metadata.texName = texName;

if (finalAlpha < 1) {
newMat.transparencyMode = flock.BABYLON.Material.MATERIAL_ALPHABLEND;
Expand DownExpand Up@@ -1554,9 +1608,14 @@ export const flockMaterial = {
? rawColor.join("-")
: flock.getColorFromString(rawColor) || "#ffffff";
const texName = String(getTexName(v));
const alpha = getAlpha(v);

return `mat_${colorKey.toLowerCase()}_${alpha}_${texName}`.toLowerCase();
const alphaKey = parseFloat(getAlpha(v)).toFixed(2);
const glow =
typeof v === "object" && v !== null && !Array.isArray(v)
? (v.glow ?? false)
: false;
const glowKey = glow ? "glow" : "noglow";

return `mat_${colorKey}_${alphaKey}_${texName}_${glowKey}`.toLowerCase();
};

const applyOne = (m, v, index) => {
Expand Down
20 changes: 20 additions & 0 deletions generators/generators-material.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,4 +147,24 @@ export function registerMaterialGenerators(javascriptGenerator) {
const code = `"${colour}"`;
return [code, javascriptGenerator.ORDER_ATOMIC];
};

// Gradient material --------------------------------------------
javascriptGenerator.forBlock["gradient_material"] = function (block) {
const color =
javascriptGenerator.valueToCode(
block,
"COLOR",
javascriptGenerator.ORDER_ATOMIC,
) || '"#ffffff"';

const alpha =
javascriptGenerator.valueToCode(
block,
"ALPHA",
javascriptGenerator.ORDER_ATOMIC,
) || "1";

const code = `{ color: ${color}, materialName: "none.png", alpha: ${alpha} }`;
return [code, javascriptGenerator.ORDER_ATOMIC];
};
}
Loading
Loading