show texture icon

This commit is contained in:
Syoyo Fujita
2025-11-14 09:14:07 +09:00
parent f9fc1589db
commit 8fa07dd274
2 changed files with 193 additions and 8 deletions

View File

@@ -165,6 +165,124 @@
width: 55% !important;
}
/* Floatable Controls Panel */
#controls-wrapper {
position: absolute;
top: 150px;
right: 10px;
z-index: 200;
background: rgba(0, 0, 0, 0.85);
border-radius: 5px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
overflow: visible;
min-width: 350px;
max-width: 600px;
}
#controls-wrapper.minimized .lil-gui {
display: none;
}
#controls-header {
background: linear-gradient(135deg, #2196F3 0%, #1976D2 100%);
color: white;
padding: 8px 12px;
cursor: move;
user-select: none;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 13px;
font-weight: 500;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
position: relative;
z-index: 1;
}
#controls-header:active {
cursor: grabbing;
}
#controls-title {
display: flex;
align-items: center;
gap: 8px;
}
#controls-buttons {
display: flex;
gap: 5px;
}
.control-btn {
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
width: 24px;
height: 24px;
border-radius: 3px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
transition: background 0.2s;
}
.control-btn:hover {
background: rgba(255, 255, 255, 0.3);
}
.control-btn:active {
background: rgba(255, 255, 255, 0.4);
}
#controls-wrapper .lil-gui {
position: relative !important;
top: 0 !important;
right: 0 !important;
max-height: calc(100vh - 200px);
overflow-y: auto;
border-radius: 0 0 5px 5px;
z-index: 2;
pointer-events: auto;
}
#controls-wrapper .lil-gui * {
pointer-events: auto;
}
/* Override resize cursor when dragging */
#controls-wrapper.dragging,
#texture-panel-wrapper.dragging {
cursor: grabbing !important;
}
#controls-wrapper.dragging .lil-gui,
#controls-wrapper.dragging .lil-gui * {
cursor: default !important;
}
#texture-panel-wrapper.dragging * {
cursor: grabbing !important;
}
/* Floatable Texture Panel */
#texture-panel-wrapper {
resize: both;
min-width: 300px;
max-width: 600px;
z-index: 150;
}
#texture-panel-wrapper.minimized #texture-panel {
display: none;
}
#texture-panel-header:active {
cursor: grabbing;
}
/* Texture panel styling */
#texture-panel .texture-item {
margin: 10px 0;
@@ -316,9 +434,19 @@
</div>
</div>
<div id="texture-panel" style="display: none; position: absolute; bottom: 10px; right: 10px; background: rgba(0, 0, 0, 0.8); color: white; padding: 15px; border-radius: 5px; font-size: 12px; max-width: 400px; max-height: 500px; overflow-y: auto;">
<h3 style="margin: 0 0 10px 0; font-size: 14px; border-bottom: 1px solid #666; padding-bottom: 5px;">Textures</h3>
<div id="texture-list"></div>
<div id="texture-panel-wrapper" style="display: none; position: absolute; bottom: 10px; right: 10px;">
<div id="texture-panel-header" style="background: linear-gradient(135deg, #4CAF50 0%, #388E3C 100%); color: white; padding: 8px 12px; cursor: move; user-select: none; display: flex; justify-content: space-between; align-items: center; font-size: 13px; font-weight: 500; border-radius: 5px 5px 0 0; border-bottom: 1px solid rgba(255, 255, 255, 0.1);">
<div style="display: flex; align-items: center; gap: 8px;">
<span>🖼️</span>
<span>Textures</span>
</div>
<div style="display: flex; gap: 5px;">
<button class="control-btn" id="texture-minimize-btn" style="background: rgba(255, 255, 255, 0.2); border: none; color: white; width: 24px; height: 24px; border-radius: 3px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 14px; transition: background 0.2s;"></button>
</div>
</div>
<div id="texture-panel" style="background: rgba(0, 0, 0, 0.85); color: white; padding: 15px; border-radius: 0 0 5px 5px; font-size: 12px; max-width: 400px; max-height: 500px; overflow-y: auto; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);">
<div id="texture-list"></div>
</div>
</div>
<div id="loading-overlay">

View File

@@ -1569,6 +1569,42 @@ function applyTextureToMaterial(material, paramName, texture, isEnabled = true)
material.needsUpdate = true;
}
// Map OpenPBR parameter names to Three.js texture map names
function getMapNameForParameter(groupName, paramName) {
const paramKey = `${groupName}_${paramName}`;
const mapping = {
'base_color': 'map',
'specular_roughness': 'roughnessMap',
'geometry_normal': 'normalMap',
'coat_normal': 'clearcoatNormalMap',
'emission_color': 'emissiveMap',
'base_metalness': 'metalnessMap'
};
return mapping[paramKey] || null;
}
// Get texture info for a material parameter (from userData.textures)
function getTextureInfoForParameter(material, groupName, paramName) {
if (!material || !material.threeMaterial || !material.threeMaterial.userData.textures) {
return null;
}
const mapName = getMapNameForParameter(groupName, paramName);
if (!mapName) {
return null;
}
const texInfo = material.threeMaterial.userData.textures[mapName];
if (texInfo) {
return {
...texInfo,
mapName: mapName
};
}
return null;
}
// Get texture info for a material parameter
function getTextureInfo(materialData, category, paramName) {
if (!materialData || !materialData.hasOpenPBR || !materialData.openPBR) {
@@ -3105,8 +3141,8 @@ function extractOpenPBRParams(materialData) {
// It's wrapped - return the actual value
return val.value;
} else if (val.textureId !== undefined && val.value === undefined) {
// It's a texture-only reference, skip for now (GUI doesn't handle texture editing yet)
return null;
// It's a texture-only reference, preserve the object so GUI can show it with texture info
return val;
}
}
// It's already a plain value
@@ -3915,10 +3951,13 @@ function createParameterControls(material) {
let rawValue = params[groupName][paramName];
if (rawValue === undefined) return;
// Check if this parameter has a texture
const hasTexture = rawValue && typeof rawValue === 'object' && rawValue.textureId !== undefined;
// Extract actual value if it's wrapped in an object with {name, type, value} structure
const value = (rawValue && typeof rawValue === 'object' && rawValue.value !== undefined)
? rawValue.value
: rawValue;
: (hasTexture ? [1, 1, 1] : rawValue); // Default color if texture-only
if (paramDef.type === 'color') {
// Color picker
@@ -3927,7 +3966,7 @@ function createParameterControls(material) {
//color: [colorValue[0] * 255, colorValue[1] * 255, colorValue[2] * 255]
color: [colorValue[0], colorValue[1], colorValue[2]]
};
groupFolder.addColor(colorObj, 'color').name(paramName).onChange(val => {
const controller = groupFolder.addColor(colorObj, 'color').name(paramName).onChange(val => {
const r = val[0]; // / 255;
const g = val[1]; // / 255;
const b = val[2]; // / 255;
@@ -3935,6 +3974,21 @@ function createParameterControls(material) {
params[groupName][paramName] = [r, g, b];
updateMaterialFromParams(threeMat, params);
});
// Add texture view button if this parameter has a texture
if (hasTexture) {
const textureInfo = getTextureInfoForParameter(material, groupName, paramName);
if (textureInfo && textureInfo.texture) {
const viewBtn = document.createElement('button');
viewBtn.textContent = '🖼️';
viewBtn.title = 'View texture';
viewBtn.style.cssText = 'margin-left: 5px; padding: 2px 8px; background: #2196F3; color: white; border: none; border-radius: 3px; cursor: pointer; font-size: 14px;';
viewBtn.onclick = () => {
enlargeTexture(textureInfo.texture, formatTextureName(textureInfo.mapName || paramName));
};
controller.domElement.parentElement.appendChild(viewBtn);
}
}
} else if (paramDef.type === 'boolean') {
// Checkbox
const boolObj = { [paramName]: !!value };
@@ -3988,7 +4042,10 @@ function updateMaterialFromParams(material, params) {
if (params.base) {
if (params.base.color) {
console.log("[base_color] ", params.base.color);
const [r, g, b] = srgbToDisplayP3(...params.base.color);
// Handle both array values and texture objects
const colorValue = Array.isArray(params.base.color) ? params.base.color :
(params.base.color.value || [1, 1, 1]);
const [r, g, b] = srgbToDisplayP3(...colorValue);
material.color.setRGB(r, g, b);
}
if (params.base.metalness !== undefined) {