immersive2/src/diagram/functions/createLabel.ts
Michael Mainguy adc80c54c4 Optimize animated connection textures and fix material texture bleeding
Performance Optimizations (~90% improvement):
- Implement texture color caching in AnimatedLineTexture
  - Reuse textures for connections with same color
  - Reduces texture count by 70-90% with duplicate colors
- Reduce animation update frequency from every frame to every other frame
  - Halves CPU-to-GPU texture updates while maintaining smooth animation
- Add texture preloading for all 16 toolbox colors
  - Eliminates first-connection creation stutter
- Add GetCacheStats, ClearCache, and PreloadTextures utility methods

Bug Fixes:
1. Fix texture disappearing when moving objects with connections
   - Root cause: Shared cached textures were disposed on connection update
   - Solution: Never dispose cached textures, only swap references
   - Add safety check in DisposeTexture to prevent cached texture disposal

2. Fix UI text textures bleeding to normal materials
   - Add metadata.isUI = true to 10+ UI components:
     - Button.ts (with unique material names per button)
     - handle.ts, roundButton.ts, createLabel.ts, updateTextNode.ts
     - spinner.ts, vrConfigPanel.ts, buildImage, introduction.ts
     - ResizeGizmo.ts
   - Update LightmapGenerator filter to check metadata.isUI first
   - Change exact name match to startsWith for button materials

3. Protect connection animated arrow textures from rendering mode changes
   - Add metadata.isConnection = true to connection materials
   - Update LightmapGenerator to skip connection materials
   - Connections maintain animated arrows in all rendering modes

Technical Details:
- Texture caching follows existing LightmapGenerator pattern
- All UI materials now consistently marked with metadata flags
- Rendering mode filter uses metadata-first approach with fallback checks
- Connection materials preserve textures via metadata.preserveTextures flag

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:37:22 -06:00

61 lines
2.3 KiB
TypeScript

import {AbstractMesh, DynamicTexture, Material, MeshBuilder, StandardMaterial} from "@babylonjs/core";
import {DefaultScene} from "../../defaultScene";
function calculateDynamicTextureDimensions(text: string, font: string): {
DTWidth: number,
DTHeight: number,
ratio: number
} {
const temp = new DynamicTexture("DynamicTexture", 32, DefaultScene.Scene);
const tmpctx = temp.getContext();
tmpctx.font = font;
const DTWidth = tmpctx.measureText(text).width + 8;
temp.dispose();
const height = 0.08;
const DTHeight = 1.5 * 24; //or set as wished
const ratio = height / DTHeight;
return {DTWidth, DTHeight, ratio};
}
function createDynamicTexture(text: string, font: string, DTWidth: number, DTHeight: number): DynamicTexture {
const dynamicTexture = new DynamicTexture("text-text", {
width: DTWidth,
height: DTHeight
}, DefaultScene.Scene, false);
dynamicTexture.drawText(text, null, null, font, "#ffffff", "#000000", true);
dynamicTexture.metadata = {exportable: true};
return dynamicTexture;
}
function createMaterial(dynamicTexture: DynamicTexture): Material {
const mat = new StandardMaterial("text-mat", DefaultScene.Scene);
//mat.diffuseColor = Color3.Black();
mat.disableLighting = true;
mat.backFaceCulling = true;
mat.emissiveTexture = dynamicTexture;
mat.diffuseTexture = dynamicTexture;
mat.metadata = { exportable: true, isUI: true }; // Mark as UI to prevent rendering mode modifications
//mat.freeze();
return mat;
}
function createPlane(text: string, material: Material, planeWidth: number, height: number): AbstractMesh {
const plane = MeshBuilder.CreatePlane("text" + text, {width: planeWidth, height: height}, DefaultScene.Scene);
plane.material = material;
plane.metadata = {exportable: true};
return plane;
}
export function createLabel(text: string): AbstractMesh {
const font_size = 24;
const font = "bold " + font_size + "px Arial";
const {DTWidth, DTHeight, ratio} = calculateDynamicTextureDimensions(text, font);
const dynamicTexture = createDynamicTexture(text, font, DTWidth, DTHeight);
const material = createMaterial(dynamicTexture);
const planeWidth = DTWidth * ratio;
const height = 0.08;
return createPlane(text, material, planeWidth, height);
}