The viewer JS/HTML/bundles are now committed in javascript/ (declared via pyproject [tool.comfy] web = "javascript") instead of being copied from the shared comfy-3d-viewers pip package at prestartup. Consequences: - requirements.txt is now just comfy-env (host env installs nothing else, per the never-touch-the-host-env principle) - prestartup_script.py no longer copies viewers or web_src; it keeps only setup_env() and the input-asset copies - WEB_DIRECTORY attribute removed; the pyproject declaration is the single source (served at /extensions/comfyui-geometrypack/, keyed by project name) - web_src/ deleted; its 6 widgets now live in javascript/js/ as the tracked source, edited directly - viewer_pbr.html hardcoded-fallback URL updated to the new mount name Iframe URLs auto-detect the mount from import.meta.url, so the folder rename and mount-name change are transparent at runtime.
162 lines
4.5 KiB
JavaScript
162 lines
4.5 KiB
JavaScript
/**
|
|
* TexturedViewer - VTK viewer for textured GLTF/GLB meshes
|
|
*
|
|
* Specialized for displaying textured 3D models with proper:
|
|
* - Material handling (metallic=0, roughness=1)
|
|
* - Texture extraction and application
|
|
* - Two-sided lighting
|
|
* - Closer camera distance for better texture viewing
|
|
*/
|
|
|
|
import { BaseViewer } from '../core/BaseViewer.js';
|
|
import { SettingTypes } from '../ui/SettingsPanel.js';
|
|
import { StandardControls } from '../ui/ControlsBar.js';
|
|
|
|
/**
|
|
* Textured viewer configuration
|
|
*/
|
|
const TEXTURED_CONFIG = {
|
|
// Camera - closer for texture detail
|
|
cameraDistanceMultiplier: 2.0,
|
|
|
|
// Lighting
|
|
twoSidedLighting: true,
|
|
|
|
// Features
|
|
enableFields: false,
|
|
enableTextures: true,
|
|
enableScreenshot: true,
|
|
enableAxisIndicator: false,
|
|
enableSettings: true,
|
|
enableControls: true,
|
|
|
|
// Appearance
|
|
backgroundColor: [0.15, 0.15, 0.15],
|
|
defaultMeshColor: [1.0, 1.0, 1.0],
|
|
showEdges: false
|
|
};
|
|
|
|
export class TexturedViewer extends BaseViewer {
|
|
/**
|
|
* Create a TexturedViewer
|
|
* @param {HTMLElement} container - Container element
|
|
* @param {Object} config - Additional configuration
|
|
*/
|
|
constructor(container, config = {}) {
|
|
// Merge with textured config
|
|
const mergedConfig = {
|
|
...TEXTURED_CONFIG,
|
|
...config,
|
|
// Settings panel configuration
|
|
settingsConfig: {
|
|
title: 'Settings',
|
|
fields: [
|
|
{
|
|
type: SettingTypes.COLOR,
|
|
id: 'backgroundColor',
|
|
label: 'Background',
|
|
defaultValue: config.backgroundColor || TEXTURED_CONFIG.backgroundColor
|
|
},
|
|
{
|
|
type: SettingTypes.CHECKBOX,
|
|
id: 'showEdges',
|
|
label: 'Show Edges',
|
|
defaultValue: false
|
|
}
|
|
]
|
|
},
|
|
// Controls bar configuration
|
|
controlsConfig: {
|
|
controls: [
|
|
StandardControls.CAMERA_VIEWS,
|
|
StandardControls.SCREENSHOT,
|
|
StandardControls.SETTINGS
|
|
]
|
|
}
|
|
};
|
|
|
|
super(container, mergedConfig);
|
|
|
|
// Texture state
|
|
this.textureInfo = null;
|
|
}
|
|
|
|
/**
|
|
* Configure loaded actors for textured display
|
|
* @private
|
|
* @override
|
|
*/
|
|
_configureLoadedActors(result) {
|
|
if (this.textureManager && result.actors.length > 0) {
|
|
// Apply texture fixes to all actors
|
|
this.textureInfo = this.textureManager.applyTextureFixesMultiple(result.actors);
|
|
|
|
// Configure renderer for texture display
|
|
this.textureManager.configureRenderer(this.renderer);
|
|
|
|
console.log('[TexturedViewer] Texture info:', this.textureInfo);
|
|
|
|
// If no textures found, apply default white color
|
|
if (!this.textureInfo.hasTexture) {
|
|
result.actors.forEach(actor => {
|
|
this.textureManager.setActorColor(actor, this.config.defaultMeshColor);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update info overlay with texture information
|
|
* @private
|
|
* @override
|
|
*/
|
|
_updateInfoOverlay(result) {
|
|
if (!this.infoOverlay) return;
|
|
|
|
const lines = [`File: ${this.currentFilename}`];
|
|
|
|
if (result.actors) {
|
|
lines.push(`Actors: ${result.actors.length}`);
|
|
}
|
|
|
|
if (this.textureInfo) {
|
|
lines.push(`Textured: ${this.textureInfo.hasTexture ? 'Yes' : 'No'}`);
|
|
if (this.textureInfo.texturedActors > 0) {
|
|
lines.push(`Textured actors: ${this.textureInfo.texturedActors}`);
|
|
}
|
|
}
|
|
|
|
this.infoOverlay.innerHTML = lines.join('<br>');
|
|
}
|
|
|
|
/**
|
|
* Get texture information
|
|
* @returns {Object|null}
|
|
*/
|
|
getTextureInfo() {
|
|
return this.textureInfo;
|
|
}
|
|
|
|
/**
|
|
* Check if current mesh has textures
|
|
* @returns {boolean}
|
|
*/
|
|
hasTextures() {
|
|
return this.textureInfo?.hasTexture || false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a TexturedViewer instance
|
|
* @param {HTMLElement} container
|
|
* @param {Object} config
|
|
* @returns {TexturedViewer}
|
|
*/
|
|
export function createTexturedViewer(container, config = {}) {
|
|
const viewer = new TexturedViewer(container, config);
|
|
viewer.initialize();
|
|
return viewer;
|
|
}
|
|
|
|
export default TexturedViewer;
|