#mv-wrapper { max-width: 1200px; margin: 0 auto; }
#mv-ui { display: flex; gap: 16px; margin-top: 12px; flex-wrap: wrap; }
.mat-block { border: 1px solid #e2e8f0; padding: 8px; border-radius: 6px; background: #fff; }
.mat-title { font-size: 13px; font-weight: 600; margin-bottom: 6px; }
.tex-btn { display: inline-block; margin: 4px 4px 0 0; padding: 6px 8px; border-radius: 4px; background: #f1f5f9; border: 1px solid #cbd5e1; cursor: pointer; font-size: 13px; width: 80px; height: 60px; background-size: cover; background-position: center; text-align: center; line-height: 60px; color: #333; }
.tex-btn:hover { background-color: #e2e8f0; }
.option-btn { padding: 6px 12px; margin: 4px; border-radius: 4px; background: #f1f5f9; border: 1px solid #cbd5e1; cursor: pointer; }
.option-btn.selected { background: #cbd5e1; font-weight: bold; }
.tab-buttons { display: flex; gap: 8px; margin-bottom: 8px; }
.tab-btn { padding: 6px 12px; border-radius: 4px 4px 0 0; background: #f1f5f9; border: 1px solid #cbd5e1; cursor: pointer; }
.tab-btn.active { background: #fff; border-bottom: none; }
.tab-content { display: none; }
.tab-content.active { display: block; }
.textures-container { display: flex; flex-wrap: wrap; }
.small-note { font-size: 12px; color: #555; margin-top: 8px; }
در حال لود مدل... لطفاً چند لحظه صبر کنید.
const modelViewer = document.querySelector('#stairsModel');
const controlsContainer = document.getElementById('material-controls');
// تعریف تکسچرها (جایگزین با آدرسهای واقعی)
const texturesPrehani = [
{ name: 'سیاه', url: 'https://pelekar.com/wp-content/uploads/black.jpg' },
{ name: 'سفید', url: 'https://pelekar.com/wp-content/uploads/white.jpg' },
// اضافه کنید
];
const texturesSath = {
marble: [
{ name: 'ماربل 1', url: 'https://pelekar.com/wp-content/uploads/marbles/marble1.jpg' },
{ name: 'ماربل 2', url: 'https://pelekar.com/wp-content/uploads/marbles/marble2.jpg' },
{ name: 'ماربل 3', url: 'https://pelekar.com/wp-content/uploads/marbles/marble3.jpg' },
{ name: 'ماربل 4', url: 'https://pelekar.com/wp-content/uploads/marbles/marble4.jpg' },
{ name: 'ماربل 5', url: 'https://pelekar.com/wp-content/uploads/marbles/marble5.jpg' },
{ name: 'ماربل 6', url: 'https://pelekar.com/wp-content/uploads/marbles/marble6.jpg' },
{ name: 'ماربل 7', url: 'https://pelekar.com/wp-content/uploads/marbles/marble7.jpg' },
{ name: 'ماربل 8', url: 'https://pelekar.com/wp-content/uploads/marbles/marble8.jpg' },
{ name: 'ماربل 9', url: 'https://pelekar.com/wp-content/uploads/marbles/marble9.jpg' },
],
granite: [
{ name: 'گرانیت 1', url: 'https://pelekar.com/wp-content/uploads/granites/granite1.jpg' },
{ name: 'گرانیت 2', url: 'https://pelekar.com/wp-content/uploads/granites/granite2.jpg' },
{ name: 'گرانیت 3', url: 'https://pelekar.com/wp-content/uploads/granites/granite3.jpg' },
{ name: 'گرانیت 4', url: 'https://pelekar.com/wp-content/uploads/granites/granite4.jpg' },
{ name: 'گرانیت 5', url: 'https://pelekar.com/wp-content/uploads/granites/granite5.jpg' },
{ name: 'گرانیت 6', url: 'https://pelekar.com/wp-content/uploads/granites/granite6.jpg' },
{ name: 'گرانیت 7', url: 'https://pelekar.com/wp-content/uploads/granites/granite7.jpg' },
{ name: 'گرانیت 8', url: 'https://pelekar.com/wp-content/uploads/granites/granite8.jpg' },
{ name: 'گرانیت 9', url: 'https://pelekar.com/wp-content/uploads/granites/granite9.jpg' },
{ name: 'گرانیت 10', url: 'https://pelekar.com/wp-content/uploads/granites/granite10.jpg' },
{ name: 'گرانیت 11', url: 'https://pelekar.com/wp-content/uploads/granites/granite11.jpg' },
{ name: 'گرانیت 12', url: 'https://pelekar.com/wp-content/uploads/granites/granite12.jpg' },
],
crystal: [
{ name: 'کریستال 1', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal1.jpg' },
{ name: 'کریستال 2', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal2.jpg' },
{ name: 'کریستال 3', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal3.jpg' },
{ name: 'کریستال 4', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal4.jpg' },
{ name: 'کریستال 5', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal5.jpg' },
{ name: 'کریستال 6', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal6.jpg' },
{ name: 'کریستال 7', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal7.jpg' },
{ name: 'کریستال 8', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal8.jpg' },
{ name: 'کریستال 9', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal9.jpg' },
{ name: 'کریستال 10', url: 'https://pelekar.com/wp-content/uploads/crystals/crystal10.jpg' },
]
};
const optionsHandrail = {
stone: { name: 'هماهنگ با سطح' },
wood: { name: 'چوب', url: 'https://pelekar.com/wp-content/uploads/wood.jpg' },
metal: { name: 'فلز', url: 'https://pelekar.com/wp-content/uploads/metal.jpg' }
};
const optionsBase = { ...optionsHandrail }; // همان گزینهها برای پایه
let currentSathTexture = null; // شیء Texture فعلی سطح
let handrailMode = 'stone'; // حالت اولیه
let baseMode = 'stone'; // حالت اولیه
// وقتی مدل لود شد، UI بساز و currentSathTexture را مقداردهی اولیه کن
modelViewer.addEventListener('load', () => {
controlsContainer.innerHTML = '';
if (!modelViewer.model || !modelViewer.model.materials) {
controlsContainer.innerHTML = '
خطا: دسترسی به مدل یا متریالها امکانپذیر نیست.';
return;
}
const materials = modelViewer.model.materials;
// مقداردهی اولیه currentSathTexture از متریال اولیه مدل
const sathMaterial = materials.find(m => m.name === 'Kimono_5_0b5f0aa5-f8b0-4aea-a027-821144430ccb');
if (sathMaterial && sathMaterial.pbrMetallicRoughness && sathMaterial.pbrMetallicRoughness.baseColorTexture) {
currentSathTexture = sathMaterial.pbrMetallicRoughness.baseColorTexture.texture;
}
const uiWrapper = document.createElement('div');
uiWrapper.id = 'mv-ui';
controlsContainer.appendChild(uiWrapper);
// بلوک پیشانی پلهها
createTextureBlock('Kimono_3_619c5b6b-67f9-4132-ab2f-1bea997320b4', 'پیشانی پلهها', texturesPrehani, uiWrapper);
// بلوک سطح پلهها با تبها
createTabbedTextureBlock('Kimono_5_0b5f0aa5-f8b0-4aea-a027-821144430ccb', 'سطح پلهها', texturesSath, uiWrapper);
// بلوک دستگیره نردهها
createOptionBlock('Golem_3_0ecf031a-08cb-4dc5-b8a8-85ca53bafd6a', 'دستگیره نردهها', optionsHandrail, 'handrail', uiWrapper);
// بلوک پایه نردهها
createOptionBlock('Serenade_f4be43ed-b6f2-4cab-a9a3-cc8a25b11ca3', 'پایه نردهها', optionsBase, 'base', uiWrapper);
});
// تابع ساخت بلوک تکسچر ساده (برای پیشانی)
function createTextureBlock(materialName, title, textures, parent) {
const block = document.createElement('div');
block.className = 'mat-block';
const h = document.createElement('div');
h.className = 'mat-title';
h.textContent = title;
block.appendChild(h);
const container = document.createElement('div');
container.className = 'textures-container';
textures.forEach(tex => {
const b = document.createElement('button');
b.className = 'tex-btn';
b.style.backgroundImage = `url(${tex.url})`;
b.textContent = tex.name;
b.onclick = () => changeTexture(tex.url, materialName);
container.appendChild(b);
});
block.appendChild(container);
parent.appendChild(block);
}
// تابع ساخت بلوک با تبها (برای سطح)
function createTabbedTextureBlock(materialName, title, categories, parent) {
const block = document.createElement('div');
block.className = 'mat-block';
const h = document.createElement('div');
h.className = 'mat-title';
h.textContent = title;
block.appendChild(h);
const tabButtons = document.createElement('div');
tabButtons.className = 'tab-buttons';
const tabContents = {};
Object.keys(categories).forEach((cat, index) => {
const tabBtn = document.createElement('button');
tabBtn.className = 'tab-btn';
tabBtn.textContent = cat.charAt(0).toUpperCase() + cat.slice(1); // Marble, Granite, Crystal
tabBtn.onclick = () => switchTab(tabBtn, cat);
tabButtons.appendChild(tabBtn);
const content = document.createElement('div');
content.className = 'tab-content';
content.id = `tab-${cat}`;
const container = document.createElement('div');
container.className = 'textures-container';
categories[cat].forEach(tex => {
const b = document.createElement('button');
b.className = 'tex-btn';
b.style.backgroundImage = `url(${tex.url})`;
b.textContent = tex.name;
b.onclick = () => changeTexture(tex.url, materialName);
container.appendChild(b);
});
content.appendChild(container);
tabContents[cat] = content;
block.appendChild(content);
if (index === 0) {
tabBtn.classList.add('active');
content.classList.add('active');
}
});
block.appendChild(tabButtons);
parent.appendChild(block);
}
function switchTab(clickedBtn, cat) {
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
clickedBtn.classList.add('active');
document.getElementById(`tab-${cat}`).classList.add('active');
}
// تابع ساخت بلوک گزینهها (برای دستگیره و پایه)
function createOptionBlock(materialName, title, options, modeType, parent) {
const block = document.createElement('div');
block.className = 'mat-block';
const h = document.createElement('div');
h.className = 'mat-title';
h.textContent = title;
block.appendChild(h);
Object.keys(options).forEach(key => {
const b = document.createElement('button');
b.className = 'option-btn';
b.textContent = options[key].name;
if (key === (modeType === 'handrail' ? handrailMode : baseMode)) {
b.classList.add('selected');
}
b.onclick = () => {
if (modeType === 'handrail') handrailMode = key;
else baseMode = key;
document.querySelectorAll(`.mat-block:nth-child(${modeType === 'handrail' ? 3 : 4}) .option-btn`).forEach(btn => btn.classList.remove('selected'));
b.classList.add('selected');
applyOption(materialName, key);
};
block.appendChild(b);
});
parent.appendChild(block);
}
// تابع اعمال گزینه (برای دستگیره/پایه)
async function applyOption(materialName, key) {
let texture = null;
if (key === 'stone') {
if (!currentSathTexture) {
alert('ابتدا یک تکسچر برای سطح پله انتخاب کنید.');
return;
}
texture = currentSathTexture;
} else {
const url = optionsHandrail[key].url; // فرض همان برای هر دو
try {
texture = await modelViewer.createTexture(url);
} catch (err) {
alert('خطا در لود تکسچر: ' + url);
return;
}
}
await changeTexture(texture, materialName, true); // true یعنی texture object است
}
// تابع تغییر تکسچر (پشتیبانی از url یا texture object)
async function changeTexture(source, materialName, isTextureObject = false) {
try {
let texture;
if (isTextureObject) {
texture = source;
} else {
texture = await modelViewer.createTexture(source);
}
const material = modelViewer.model.materials.find(m => m.name === materialName);
if (!material) {
alert('متریال پیدا نشد: ' + materialName);
return;
}
const pbr = material.pbrMetallicRoughness;
if (pbr && pbr.baseColorTexture) {
pbr.baseColorTexture.setTexture(texture);
} else {
alert('این متریال از تغییر تکسچر پشتیبانی نمیکند.');
return;
}
// اگر برای سطح پله باشد، بروزرسانی currentSathTexture و اعمال روی دستگیره/پایه اگر stone
if (materialName === 'Kimono_5_0b5f0aa5-f8b0-4aea-a027-821144430ccb') {
currentSathTexture = pbr.baseColorTexture.texture;
if (handrailMode === 'stone' && currentSathTexture) {
changeTexture(currentSathTexture, 'Golem_3_0ecf031a-08cb-4dc5-b8a8-85ca53bafd6a', true);
}
if (baseMode === 'stone' && currentSathTexture) {
changeTexture(currentSathTexture, 'Serenade_f4be43ed-b6f2-4cab-a9a3-cc8a25b11ca3', true);
}
}
} catch (err) {
alert('خطا در اعمال تکسچر.');
}
}
// اعمال اولیه برای دستگیره و پایه اگر stone و currentSathTexture وجود داشته باشد
modelViewer.addEventListener('load', () => {
// ... (بعد از ساخت UI)
if (handrailMode === 'stone' && currentSathTexture) {
changeTexture(currentSathTexture, 'Golem_3_0ecf031a-08cb-4dc5-b8a8-85ca53bafd6a', true);
}
if (baseMode === 'stone' && currentSathTexture) {
changeTexture(currentSathTexture, 'Serenade_f4be43ed-b6f2-4cab-a9a3-cc8a25b11ca3', true);
}
});