D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
var
/
www
/
html
/
crsys_ant
/
Filename :
catalogo3D_lateral v32 Oficial.html
back
Copy
<!DOCTYPE html> <html lang="pt-BR"> <head> <meta charset="utf-8" /> <title>Gerador de Imagens 3D</title> <style> html,body { height:100%; margin:0; background:#222; color:#ddd; font-family:system-ui, Segoe UI, Roboto } header { padding:10px 14px; border-bottom:1px solid #444; } .wrap { display:grid; grid-template-columns: 380px 1fr; /* largura da barra lateral ajustada */ height:calc(100vh - 48px); } aside { border-right:1px solid #444; padding:12px; overflow:auto; } main { position:relative; } #viewport { position:absolute; inset:0; overscroll-behavior: contain; } fieldset { border:1px solid #444; border-radius:10px; padding:10px; margin:0 0 12px; } legend { padding:0 6px; color:#a6c1ff; font-size:16px; } :root{--w-input: 95px; --gap: 8px; --w-bloco: calc(var(--w-input)*3 + var(--gap)*2);} .row{display:grid;grid-template-columns: var(--w-input) var(--w-input) var(--w-input); gap:var(--gap); width:var(--w-bloco); justify-content:start;} .row2x{display:grid;grid-template-columns: var(--w-input) var(--w-input); gap:var(--gap); width: calc(var(--w-input)*2 + var(--gap)); justify-content:start;} .row2{display:grid;grid-template-columns: 1fr 1fr; gap:var(--gap); width:100%; justify-content:start;} .row2 button{ width:100%;} .grid4{display:grid; grid-template-columns: 1fr 1fr; gap:6px; margin-top:8px;} .grid4 label{gap:6px} input,button{ background:#ffffff; color:#0c0c0c; border:1px solid #555; border-radius:0px; padding:8px 8px } input[type="number"]{ width:100%; min-width:0; } button{ cursor:pointer; font-weight:600 } label{ display:flex; gap:8px; align-items:center } .hint{ font-size:12px; opacity:.8; margin-top:6px } /* Ocultar os controles de Ângulo, mantendo o HTML/JS intactos (V19) */ fieldset div:has(> #latDR_ang), fieldset div:has(> #latESQ_ang), fieldset div:has(> #top_ang) { display: none !important; } </style> </head> <body> <header>Gerador de Imagens 3D</header> <div class="wrap"> <aside> <!-- Tampo base --> <fieldset> <legend>Tampo base</legend> <div class="row"> <input id="dimX" type="number" step="0.1" value="40" title="X (largura)"> <input id="dimY" type="number" step="0.1" value="2" title="Y (espessura)"> <input id="dimZ" type="number" step="0.1" value="20" title="Z (profundidade)"> </div> <div class="row2" style="margin-top:8px"> <!-- <button id="aplicarDim">Aplicar</button> --> <button id="resetCamera">Recentrar câmera</button> </div> <!-- Acabamento por borda --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <div style="font-weight:600; margin-bottom:6px;">Acabamento</div> <div class="grid4"> <label><input type="checkbox" id="baseFin_front"> Frente <!--(Z−)--> </label> <label><input type="checkbox" id="baseFin_back"> Trás <!--(Z+)--> </label> <label><input type="checkbox" id="baseFin_right"> Direita <!--(X+)--> </label> <label><input type="checkbox" id="baseFin_left"> Esquerda <!--(X−)--> </label> </div> </fieldset> <!-- Saia (apenas no tampo inferior) --> <fieldset> <legend>Saia do tampo inferior</legend> <!-- Saia frontal --> <label><input type="checkbox" id="sf_on"> Saia frontal</label> <div class="row2x" style="margin-top:8px;"> <input id="sf_h" type="number" step="0.1" value="5" title="Altura (Y)"> <input id="sf_t" type="number" step="0.1" value="2.0" title="Espessura (Z)"> </div> <!-- <button id="sf_apply" style="margin-top:8px">Aplicar saia frontal</button> --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- Saia lateral direita --> <label><input type="checkbox" id="sr_on"> Saia lateral direita</label> <div class="row2x" style="margin-top:8px;"> <input id="sr_h" type="number" step="0.1" value="5" title="Altura (Y)"> <input id="sr_t" type="number" step="0.1" value="2.0" title="Espessura (X)"> </div> <!-- <button id="sr_apply" style="margin-top:8px">Aplicar saia direita</button> --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- Saia lateral esquerda --> <label><input type="checkbox" id="sl_on"> Saia lateral esquerda</label> <div class="row2x" style="margin-top:8px;"> <input id="sl_h" type="number" step="0.1" value="5" title="Altura (Y)"> <input id="sl_t" type="number" step="0.1" value="2.0" title="Espessura (X)"> </div> <!-- <button id="sl_apply" style="margin-top:8px">Aplicar saia esquerda</button> --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- Saia traseira --> <label><input type="checkbox" id="sb_on"> Saia traseira</label> <div class="row2x" style="margin-top:8px;"> <input id="sb_h" type="number" step="0.1" value="5" title="Altura (Y)"> <input id="sb_t" type="number" step="0.1" value="2.0" title="Espessura (Z)"> </div> <!-- <button id="sb_apply" style="margin-top:8px">Aplicar saia traseira</button> --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- NOVO: acabamento de fundo para todas as saias --> <label><input type="checkbox" id="skirtBottom_all"> Acabamento Fundo (todas as saias)</label> </fieldset> <!-- Frontões --> <fieldset> <legend>Frontões</legend> <!-- Frontão frontal --> <label><input type="checkbox" id="ff_on"> Frontão frontal</label> <div class="row2x" style="margin-top:8px;"> <input id="ff_h" type="number" step="0.1" value="10" title="Altura (Y)"> <input id="ff_t" type="number" step="0.1" value="2.0" title="Espessura (Z)"> </div> <!-- <button id="ff_apply" style="margin-top:8px">Aplicar frontão frontal</button> --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- Frontão traseiro --> <label><input type="checkbox" id="ft_on"> Frontão traseiro</label> <div class="row2x" style="margin-top:8px;"> <input id="ft_h" type="number" step="0.1" value="10" title="Altura (Y)"> <input id="ft_t" type="number" step="0.1" value="2.0" title="Espessura (Z)"> </div> <!-- <button id="ft_apply" style="margin-top:8px">Aplicar frontão traseiro</button> --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- Frontão lateral direito --> <label><input type="checkbox" id="ftR_on"> Frontão lateral direito</label> <div class="row2x" style="margin-top:8px;"> <input id="ftR_h" type="number" step="0.1" value="10" title="Altura (Y)"> <input id="ftR_t" type="number" step="0.1" value="2.0" title="Espessura (X)"> </div> <!-- <button id="ftR_apply" style="margin-top:8px">Aplicar frontão direito</button> --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- Frontão lateral esquerdo --> <label><input type="checkbox" id="ftL_on"> Frontão lateral esquerdo</label> <div class="row2x" style="margin-top:8px;"> <input id="ftL_h" type="number" step="0.1" value="10" title="Altura (Y)"> <input id="ftL_t" type="number" step="0.1" value="2.0" title="Espessura (X)"> </div> <!-- <button id="ftL_apply" style="margin-top:8px">Aplicar frontão esquerdo</button> --> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- Acabamento topo para TODOS os frontões --> <label><input type="checkbox" id="ftop_all"> Acabamento Topo (todos os frontões)</label> </fieldset> <!-- Lateral direita --> <fieldset> <legend>Lateral direita </legend> <label><input type="checkbox" id="latDR_on"> Incluir direita</label> <div class="row" style="margin-top:8px;"> <input id="latDR_x" type="number" step="0.1" value="1.5" title="Espessura X"> <input id="latDR_y" type="number" step="0.1" value="30" title="Altura Y"> <input id="latDR_z" type="number" step="0.1" value="20" title="Profundidade Z"> </div> <div style="display:flex;align-items:center;gap:8px;margin-top:8px;"> <label>Ângulo (0–180°)</label> <input id="latDR_ang" type="number" min="0" max="180" step="1" value="90" style="width:100px"> </div> <!-- <button id="latDR_apply" style="margin-top:8px">Aplicar direita</button> --> </fieldset> <!-- Lateral esquerda --> <fieldset> <legend>Lateral esquerda </legend> <label><input type="checkbox" id="latESQ_on"> Incluir esquerda</label> <div class="row" style="margin-top:8px;"> <input id="latESQ_x" type="number" step="0.1" value="1.5" title="Espessura X"> <input id="latESQ_y" type="number" step="0.1" value="30" title="Altura Y"> <input id="latESQ_z" type="number" step="0.1" value="20" title="Profundidade Z"> </div> <div style="display:flex;align-items:center;gap:8px;margin-top:8px;"> <label>Ângulo (0–180°)</label> <input id="latESQ_ang" type="number" min="0" max="180" step="1" value="90" style="width:100px"> </div> <!-- <button id="latESQ_apply" style="margin-top:8px">Aplicar esquerda</button> --> </fieldset> <!-- Tampo superior --> <fieldset> <legend>Tampo superior </legend> <label><input type="checkbox" id="top_on"> Incluir tampo superior</label> <div class="row" style="margin-top:8px;"> <input id="top_x" type="number" step="0.1" value="40" title="Largura X (ignorada; usamos X do tampo)"> <input id="top_y" type="number" step="0.1" value="1.5" title="Espessura Y"> <input id="top_z" type="number" step="0.1" value="20" title="Profundidade Z"> </div> <div style="display:flex;align-items:center;gap:8px;margin-top:8px;"> <label>Abertura (0–120°)</label> <input id="top_ang" type="number" min="0" max="120" step="1" value="0" style="width:100px"> </div> <!-- <button id="top_apply" style="margin-top:8px">Aplicar tampo</button> --> </fieldset> </aside> <main><div id="viewport"></div></main> </div> <script src="https://unpkg.com/three@0.160.0/build/three.min.js"></script> <script> /* ====== helpers ====== */ function debounce(fn, ms=120){ let t; return (...args)=>{ clearTimeout(t); t=setTimeout(()=>fn(...args), ms); }; } /* ====== CENA ====== */ const vpEl = document.getElementById('viewport'); const renderer = new THREE.WebGLRenderer({ antialias:true, preserveDrawingBuffer:true }); vpEl.appendChild(renderer.domElement); // Zoom isolado no viewport vpEl.addEventListener('wheel', (e) => { e.preventDefault(); e.stopPropagation(); radius *= (e.deltaY < 0 ? 0.9 : 1.1); updateCamera(); render(); }, { passive: false }); const scene = new THREE.Scene(); scene.background = new THREE.Color(0x222222); const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 5000); scene.add(new THREE.HemisphereLight(0xffffff, 0xffffff, 1.2)); const dir = new THREE.DirectionalLight(0xffffff, 0.85); dir.position.set(30,50,30); scene.add(dir); const root = new THREE.Group(); scene.add(root); let baseMesh, rightPivot, rightMesh, leftPivot, leftMesh, topPivot, topMesh; /* Saia */ let skirtFront, skirtRight, skirtLeft, skirtBack; /* Frontões */ let backsplashFront, backsplash, backsplashRight, backsplashLeft; /* ====== BASE ====== */ function makeBase(x=40,y=2,z=20){ if (baseMesh) { root.remove(baseMesh); baseMesh.geometry.dispose(); Array.isArray(baseMesh.material) ? baseMesh.material.forEach(m=>m.dispose&&m.dispose()) : baseMesh.material.dispose&&baseMesh.material.dispose(); baseMesh=null; } const g = new THREE.BoxGeometry(x,y,z); // Materiais: topo/fundo polidos brancos; acabamento (borda) ROSA-bebê const matTop = new THREE.MeshStandardMaterial({ color:0xffffff, roughness:0.30 }); const matSide = new THREE.MeshStandardMaterial({ color:new THREE.Color('#FFC0CB'), roughness:0.60 }); // BORDAS LIGADAS? (sem master switch) const finFront = !!document.getElementById('baseFin_front')?.checked; // Z− (índice 5) const finBack = !!document.getElementById('baseFin_back') ?.checked; // Z+ (índice 4) const finRight = !!document.getElementById('baseFin_right')?.checked; // X+ (índice 0) const finLeft = !!document.getElementById('baseFin_left') ?.checked; // X− (índice 1) // Ordem em BoxGeometry: [ +X, -X, +Y, -Y, +Z, -Z ] const materials = [ finRight ? matSide : matTop, // +X finLeft ? matSide : matTop, // -X matTop, // +Y matTop, // -Y finBack ? matSide : matTop, // +Z finFront ? matSide : matTop, // -Z ]; baseMesh = new THREE.Mesh(g, materials); root.add(baseMesh); render(); } makeBase(); /* ====== CÂMERA / ORBIT ====== */ const target = new THREE.Vector3(0,0,0); let radius=120, theta=THREE.MathUtils.degToRad(45), phi=THREE.MathUtils.degToRad(35); function updateCamera(){ const x = target.x + radius * Math.sin(phi) * Math.cos(theta); const y = target.y + radius * Math.cos(phi); const z = target.z + radius * Math.sin(phi) * Math.sin(theta); camera.position.set(x,y,z); camera.lookAt(target); } /* === ENQUADRAMENTO AUTOMÁTICO (FOV horizontal) === */ function fitCameraToScene(margin = 2.0) { root.updateWorldMatrix(true, true); const box = new THREE.Box3().setFromObject(root); if (box.isEmpty()) { updateCamera(); render(); return; } const size = box.getSize(new THREE.Vector3()); const center = box.getCenter(new THREE.Vector3()); target.copy(center); const vFov = camera.fov * Math.PI / 180; const hFov = 2 * Math.atan(Math.tan(vFov / 2) * camera.aspect); const distH = (size.y * 0.5) / Math.tan(vFov / 2); const distW = (size.x * 0.5) / Math.tan(hFov / 2); const distZ = (size.z * 0.5) / Math.tan(vFov / 2); radius = Math.max(distH, distW, distZ) * margin; updateCamera(); render(); } function focusCamera(){ fitCameraToScene(1.8); } updateCamera(); /* ====== CONTROLE DO MOUSE ====== */ let dragging=false, lx=0, ly=0; addEventListener('pointerdown',e=>{dragging=true; lx=e.clientX; ly=e.clientY;}); addEventListener('pointermove',e=>{ if(!dragging) return; const dx=e.clientX-lx, dy=e.clientY-ly; lx=e.clientX; ly=e.clientY; theta -= dx*0.005; phi -= dy*0.005; phi = Math.max(THREE.MathUtils.degToRad(5), Math.min(THREE.MathUtils.degToRad(175), phi)); updateCamera(); render(); }); addEventListener('pointerup',()=>dragging=false); /* ====== RESIZE ====== */ function onResize(){ const w = document.getElementById('viewport').clientWidth || (innerWidth-460); const h = document.getElementById('viewport').clientHeight || (innerHeight-48); renderer.setSize(w,h,false); camera.aspect = w/h; camera.updateProjectionMatrix(); fitCameraToScene(1.8); } addEventListener('resize', onResize); onResize(); function render(){ renderer.render(scene,camera); } /* ====== REAPLICAÇÃO GERAL ====== */ function reapplyAll(){ const x=+dimX.value||40, y=+dimY.value||2, z=+dimZ.value||20; makeBase(x,y,z); if (sf_on.checked) applySkirtFront(); else if (skirtFront){ root.remove(skirtFront); skirtFront=null; } if (sr_on.checked) applySkirtRight(); else if (skirtRight){ root.remove(skirtRight); skirtRight=null; } if (sl_on.checked) applySkirtLeft(); else if (skirtLeft){ root.remove(skirtLeft); skirtLeft=null; } if (sb_on.checked) applySkirtBack(); else if (skirtBack){ root.remove(skirtBack); skirtBack=null; } if (ff_on.checked) applyBacksplashFront(); else if (backsplashFront){ root.remove(backsplashFront); backsplashFront=null; } if (ft_on.checked) applyBacksplash(); else if (backsplash){ root.remove(backsplash); backsplash=null; } if (ftR_on.checked) applyBacksplashRight(); else if (backsplashRight){ root.remove(backsplashRight); backsplashRight=null; } if (ftL_on.checked) applyBacksplashLeft(); else if (backsplashLeft){ root.remove(backsplashLeft); backsplashLeft=null; } if (latDR_on.checked) applyRight(); else if (rightPivot){ root.remove(rightPivot); rightPivot=null; rightMesh=null; } if (latESQ_on.checked) applyLeft(); else if (leftPivot){ root.remove(leftPivot); leftPivot=null; leftMesh=null; } if (top_on.checked) applyTop(); else if (topPivot){ root.remove(topPivot); topPivot=null; topMesh=null; } fitCameraToScene(1.8); } const reapplyAllDebounced = debounce(reapplyAll, 120); /* ====== UI ====== */ document.getElementById('aplicarDim')?.addEventListener('click', reapplyAll); document.getElementById('resetCamera')?.addEventListener('click', ()=>fitCameraToScene(1.8)); /* ====== AUTO-APPLY: base e acabamento ====== */ ['dimX','dimY','dimZ'].forEach(id=>{ document.getElementById(id).addEventListener('input', reapplyAllDebounced); }); ['baseFin_front','baseFin_back','baseFin_right','baseFin_left'].forEach(id=>{ document.getElementById(id)?.addEventListener('change', reapplyAllDebounced); }); /* ====== NOVO: listener para acabamento de fundo das saias ====== */ document.getElementById('skirtBottom_all').addEventListener('change', reapplyAllDebounced); /* ====== SAIA — FRONTAL ====== */ document.getElementById('sf_on').addEventListener('change', reapplyAllDebounced); ['sf_h','sf_t'].forEach(id=>document.getElementById(id).addEventListener('input', ()=>{ if(sf_on.checked) applySkirtFront(); })); function applySkirtFront(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const h = Math.max(0.1, +sf_h.value || 5); const t = Math.max(0.1, +sf_t.value || 2.0); if(!sf_on.checked){ if(skirtFront){ root.remove(skirtFront); skirtFront=null; render(); fitCameraToScene(1.8); } return; } const geo = new THREE.BoxGeometry(bx, h, t); const pink = new THREE.Color('#FFC0CB'); const white = 0xffffff; const finFront = document.getElementById('baseFin_front')?.checked; const finRight = document.getElementById('baseFin_right')?.checked; const finLeft = document.getElementById('baseFin_left') ?.checked; const finBottom= document.getElementById('skirtBottom_all')?.checked; // −Y // Ordem: [ +X, -X, +Y, -Y, +Z, -Z ] const materials = [ new THREE.MeshStandardMaterial({color: finRight ? pink : white, roughness: finRight?0.6:0.85}), // +X new THREE.MeshStandardMaterial({color: finLeft ? pink : white, roughness: finLeft ?0.6:0.85}), // -X new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +Y new THREE.MeshStandardMaterial({color: finBottom? pink : white, roughness: finBottom?0.6:0.85}), // -Y (Fundo) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +Z new THREE.MeshStandardMaterial({color: finFront ? pink : white, roughness: finFront?0.6:0.85}) // -Z (frontal) ]; if(!skirtFront){ skirtFront = new THREE.Mesh(geo, materials); root.add(skirtFront); } else { skirtFront.geometry.dispose(); skirtFront.geometry = geo; skirtFront.material = materials; } skirtFront.position.set(0, -by/2 - h/2, -bz/2 + t/2); render(); fitCameraToScene(1.8); } /* ====== SAIA — DIREITA ====== */ document.getElementById('sr_on').addEventListener('change', reapplyAllDebounced); ['sr_h','sr_t'].forEach(id=>document.getElementById(id).addEventListener('input', ()=>{ if(sr_on.checked) applySkirtRight(); })); function applySkirtRight(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const h = Math.max(0.1, +sr_h.value || 5); const t = Math.max(0.1, +sr_t.value || 2.0); if(!sr_on.checked){ if(skirtRight){ root.remove(skirtRight); skirtRight=null; render(); fitCameraToScene(1.8); } return; } const geo = new THREE.BoxGeometry(t, h, bz); const pink = new THREE.Color('#FFC0CB'); const white = 0xffffff; const finRight = document.getElementById('baseFin_right')?.checked; const finBottom= document.getElementById('skirtBottom_all')?.checked; // −Y const materials = [ new THREE.MeshStandardMaterial({color: finRight ? pink : white, roughness: finRight?0.6:0.85}), // +X (borda) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -X new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +Y new THREE.MeshStandardMaterial({color: finBottom? pink : white, roughness: finBottom?0.6:0.85}), // -Y (Fundo) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +Z new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -Z ]; if(!skirtRight){ skirtRight = new THREE.Mesh(geo, materials); root.add(skirtRight); } else { skirtRight.geometry.dispose(); skirtRight.geometry = geo; skirtRight.material = materials; } skirtRight.position.set(+bx/2 - t/2, -by/2 - h/2, 0); render(); fitCameraToScene(1.8); } /* ====== SAIA — ESQUERDA ====== */ document.getElementById('sl_on').addEventListener('change', reapplyAllDebounced); ['sl_h','sl_t'].forEach(id=>document.getElementById(id).addEventListener('input', ()=>{ if(sl_on.checked) applySkirtLeft(); })); function applySkirtLeft(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const h = Math.max(0.1, +sl_h.value || 5); const t = Math.max(0.1, +sl_t.value || 2.0); if(!sl_on.checked){ if(skirtLeft){ root.remove(skirtLeft); skirtLeft=null; render(); fitCameraToScene(1.8); } return; } const geo = new THREE.BoxGeometry(t, h, bz); const pink = new THREE.Color('#FFC0CB'); const white = 0xffffff; const finLeft = document.getElementById('baseFin_left')?.checked; const finBottom= document.getElementById('skirtBottom_all')?.checked; // −Y const materials = [ new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +X new THREE.MeshStandardMaterial({color: finLeft ? pink : white, roughness: finLeft?0.6:0.85}), // -X (borda) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +Y new THREE.MeshStandardMaterial({color: finBottom? pink : white, roughness: finBottom?0.6:0.85}), // -Y (Fundo) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +Z new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -Z ]; if(!skirtLeft){ skirtLeft = new THREE.Mesh(geo, materials); root.add(skirtLeft); } else { skirtLeft.geometry.dispose(); skirtLeft.geometry = geo; skirtLeft.material = materials; } skirtLeft.position.set(-bx/2 + t/2, -by/2 - h/2, 0); render(); fitCameraToScene(1.8); } /* ====== SAIA — TRASEIRA ====== */ document.getElementById('sb_on').addEventListener('change', reapplyAllDebounced); ['sb_h','sb_t'].forEach(id=>document.getElementById(id).addEventListener('input', ()=>{ if(sb_on.checked) applySkirtBack(); })); function applySkirtBack(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const h = Math.max(0.1, +sb_h.value || 5); const t = Math.max(0.1, +sb_t.value || 2.0); if(!sb_on.checked){ if(skirtBack){ root.remove(skirtBack); skirtBack=null; render(); fitCameraToScene(1.8); } return; } const geo = new THREE.BoxGeometry(bx, h, t); const pink = new THREE.Color('#FFC0CB'); const white = 0xffffff; const finBack = document.getElementById('baseFin_back') ?.checked; // +Z const finRight = document.getElementById('baseFin_right')?.checked; // +X const finLeft = document.getElementById('baseFin_left') ?.checked; // -X const finBottom= document.getElementById('skirtBottom_all')?.checked; // −Y // Ordem: [ +X, -X, +Y, -Y, +Z, -Z ] const materials = [ new THREE.MeshStandardMaterial({color: finRight ? pink : white, roughness: finRight?0.6:0.85}), // +X (direita) new THREE.MeshStandardMaterial({color: finLeft ? pink : white, roughness: finLeft ?0.6:0.85}), // -X (esquerda) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +Y (topo) new THREE.MeshStandardMaterial({color: finBottom? pink : white, roughness: finBottom?0.6:0.85}), // -Y (Fundo) new THREE.MeshStandardMaterial({color: finBack ? pink : white, roughness: finBack?0.6:0.85}), // +Z (traseira) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -Z ]; if(!skirtBack){ skirtBack = new THREE.Mesh(geo, materials); root.add(skirtBack); } else { skirtBack.geometry.dispose(); skirtBack.geometry = geo; skirtBack.material = materials; } skirtBack.position.set(0, -by/2 - h/2, +bz/2 - t/2); render(); fitCameraToScene(1.8); } /* ====== FRONTÕES — LISTENERS ====== */ document.getElementById('ff_on').addEventListener('change', reapplyAllDebounced); ['ff_h','ff_t'].forEach(id=>{ document.getElementById(id).addEventListener('input', ()=>{ if(ff_on.checked) applyBacksplashFront(); }); }); document.getElementById('ft_on').addEventListener('change', reapplyAllDebounced); ['ft_h','ft_t'].forEach(id=>{ document.getElementById(id).addEventListener('input', ()=>{ if(ft_on.checked) applyBacksplash(); }); }); document.getElementById('ftR_on').addEventListener('change', reapplyAllDebounced); ['ftR_h','ftR_t'].forEach(id=>{ document.getElementById(id).addEventListener('input', ()=>{ if(ftR_on.checked) applyBacksplashRight(); }); }); document.getElementById('ftL_on').addEventListener('change', reapplyAllDebounced); ['ftL_h','ftL_t'].forEach(id=>{ document.getElementById(id).addEventListener('input', ()=>{ if(ftL_on.checked) applyBacksplashLeft(); }); }); /* Checkbox único para acabamento de topo (todos os frontões) */ document.getElementById('ftop_all').addEventListener('change', reapplyAllDebounced); /* ====== FRONTÕES ====== */ function applyBacksplashFront(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const fh = Math.max(0.1, +ff_h.value || 10); const ft = Math.max(0.1, +ff_t.value || by); if(!ff_on.checked){ if(backsplashFront){ root.remove(backsplashFront); backsplashFront=null; render(); fitCameraToScene(1.8); } return; } const pink = new THREE.Color('#FFC0CB'); const white = 0xffffff; const finFront = document.getElementById('baseFin_front')?.checked; // -Z const finRight = document.getElementById('baseFin_right')?.checked; // +X const finLeft = document.getElementById('baseFin_left') ?.checked; // -X const finTop = document.getElementById('ftop_all')?.checked; // +Y (topo) const mat = [ new THREE.MeshStandardMaterial({color: finRight? pink:white, roughness: finRight?0.6:0.85}), // +X new THREE.MeshStandardMaterial({color: finLeft ? pink:white, roughness: finLeft ?0.6:0.85}), // -X new THREE.MeshStandardMaterial({color: finTop ? pink:white, roughness: finTop ?0.6:0.85}), // +Y (topo) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -Y new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +Z (verso) new THREE.MeshStandardMaterial({color: finFront? pink:white, roughness: finFront?0.6:0.85}), // -Z (frente) ]; const geo = new THREE.BoxGeometry(bx, fh, ft); if(!backsplashFront){ backsplashFront = new THREE.Mesh(geo, mat); root.add(backsplashFront); } else { backsplashFront.geometry.dispose(); backsplashFront.geometry = geo; backsplashFront.material = mat; } backsplashFront.position.set(0, +by/2 + fh/2, -bz/2 + ft/2); render(); fitCameraToScene(1.8); } function applyBacksplash(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const fh = Math.max(0.1, +ft_h.value || 10); const ft = Math.max(0.1, +ft_t.value || by); if(!ft_on.checked){ if(backsplash){ root.remove(backsplash); backsplash=null; render(); fitCameraToScene(1.8); } return; } const pink = new THREE.Color('#FFC0CB'); const white = 0xffffff; const finBack = document.getElementById('baseFin_back') ?.checked; // +Z const finRight = document.getElementById('baseFin_right')?.checked; // +X const finLeft = document.getElementById('baseFin_left') ?.checked; // -X const finTop = document.getElementById('ftop_all')?.checked; // +Y (topo) const mat = [ new THREE.MeshStandardMaterial({color: finRight? pink:white, roughness: finRight?0.6:0.85}), // +X new THREE.MeshStandardMaterial({color: finLeft ? pink:white, roughness: finLeft ?0.6:0.85}), // -X new THREE.MeshStandardMaterial({color: finTop ? pink:white, roughness: finTop ?0.6:0.85}), // +Y (topo) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -Y new THREE.MeshStandardMaterial({color: finBack? pink:white, roughness: finBack?0.6:0.85}), // +Z (trás) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -Z ]; const geo = new THREE.BoxGeometry(bx, fh, ft); if(!backsplash){ backsplash = new THREE.Mesh(geo, mat); root.add(backsplash); } else { backsplash.geometry.dispose(); backsplash.geometry = geo; backsplash.material = mat; } backsplash.position.set(0, +by/2 + fh/2, +bz/2 - ft/2); render(); fitCameraToScene(1.8); } function applyBacksplashRight(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const fh = Math.max(0.1, +ftR_h.value || 10); const ft = Math.max(0.1, +ftR_t.value || by); if(!ftR_on.checked){ if(backsplashRight){ root.remove(backsplashRight); backsplashRight=null; render(); fitCameraToScene(1.8); } return; } const pink = new THREE.Color('#FFC0CB'); const white = 0xffffff; const finRight = document.getElementById('baseFin_right')?.checked; // +X const finFront = document.getElementById('baseFin_front')?.checked; // -Z const finBack = document.getElementById('baseFin_back') ?.checked; // +Z const finTop = document.getElementById('ftop_all')?.checked; // +Y (topo) const mat = [ new THREE.MeshStandardMaterial({color: finRight? pink:white, roughness: finRight?0.6:0.85}), // +X (externa) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -X new THREE.MeshStandardMaterial({color: finTop ? pink:white, roughness: finTop ?0.6:0.85}), // +Y (topo) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -Y new THREE.MeshStandardMaterial({color: finBack ? pink:white, roughness: finBack ?0.6:0.85}), // +Z (trás) new THREE.MeshStandardMaterial({color: finFront? pink:white, roughness: finFront?0.6:0.85}), // -Z (frente) ]; const geo = new THREE.BoxGeometry(ft, fh, bz); if(!backsplashRight){ backsplashRight = new THREE.Mesh(geo, mat); root.add(backsplashRight); } else { backsplashRight.geometry.dispose(); backsplashRight.geometry = geo; backsplashRight.material = mat; } backsplashRight.position.set(+bx/2 - ft/2, +by/2 + fh/2, 0); render(); fitCameraToScene(1.8); } function applyBacksplashLeft(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const fh = Math.max(0.1, +ftL_h.value || 10); const ft = Math.max(0.1, +ftL_t.value || by); if(!ftL_on.checked){ if(backsplashLeft){ root.remove(backsplashLeft); backsplashLeft=null; render(); fitCameraToScene(1.8); } return; } const pink = new THREE.Color('#FFC0CB'); const white = 0xffffff; const finLeft = document.getElementById('baseFin_left') ?.checked; // -X const finFront = document.getElementById('baseFin_front')?.checked; // -Z const finBack = document.getElementById('baseFin_back') ?.checked; // +Z const finTop = document.getElementById('ftop_all')?.checked; // +Y (topo) const mat = [ new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // +X new THREE.MeshStandardMaterial({color: finLeft? pink:white, roughness: finLeft?0.6:0.85}), // -X (externa) new THREE.MeshStandardMaterial({color: finTop ? pink:white, roughness: finTop ?0.6:0.85}), // +Y (topo) new THREE.MeshStandardMaterial({color:white, roughness:0.85}), // -Y new THREE.MeshStandardMaterial({color: finBack ? pink:white, roughness: finBack ?0.6:0.85}), // +Z (trás) new THREE.MeshStandardMaterial({color: finFront? pink:white, roughness: finFront?0.6:0.85}), // -Z (frente) ]; const geo = new THREE.BoxGeometry(ft, fh, bz); if(!backsplashLeft){ backsplashLeft = new THREE.Mesh(geo, mat); root.add(backsplashLeft); } else { backsplashLeft.geometry.dispose(); backsplashLeft.geometry = geo; backsplashLeft.material = mat; } backsplashLeft.position.set(-bx/2 + ft/2, +by/2 + fh/2, 0); render(); fitCameraToScene(1.8); } /* ====== LATERAIS E TAMPO SUPERIOR (inalterados) ====== */ document.getElementById('latDR_on').addEventListener('change', reapplyAllDebounced); ['latDR_x','latDR_y','latDR_z','latDR_ang'].forEach(id=>{ document.getElementById(id).addEventListener('input', ()=>{ if(latDR_on.checked) applyRight(); }); }); function applyRight(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const sx=Math.max(0.1,+latDR_x.value||1.5); const sy=Math.max(0.1,+latDR_y.value||30); const sz=Math.max(0.1,+latDR_z.value||bz); const ang=Math.max(0,Math.min(180,+latDR_ang.value||90)); if(!rightPivot){ rightPivot=new THREE.Object3D(); root.add(rightPivot); } rightPivot.position.set(+bx/2, -by/2, 0); const m=new THREE.MeshStandardMaterial({ color:0xffffff, roughness:0.85 }); if(!rightMesh){ rightMesh=new THREE.Mesh(new THREE.BoxGeometry(sx,sy,sz),m); rightPivot.add(rightMesh); } else { rightMesh.material=m; rightMesh.geometry.dispose(); rightMesh.geometry=new THREE.BoxGeometry(sx,sy,sz); } rightMesh.position.set(-sx/2, +sy/2, 0); rightPivot.rotation.set(0,0,THREE.MathUtils.degToRad(90-ang)); if(!latDR_on.checked){ root.remove(rightPivot); rightPivot=null; rightMesh=null; } render(); fitCameraToScene(1.8); } document.getElementById('latESQ_on').addEventListener('change', reapplyAllDebounced); ['latESQ_x','latESQ_y','latESQ_z','latESQ_ang'].forEach(id=>{ document.getElementById(id).addEventListener('input', ()=>{ if(latESQ_on.checked) applyLeft(); }); }); function applyLeft(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; const sx=Math.max(0.1,+latESQ_x.value||1.5); const sy=Math.max(0.1,+latESQ_y.value||30); const sz=Math.max(0.1,+latESQ_z.value||bz); const ang=Math.max(0,Math.min(180,+latESQ_ang.value||90)); if(!leftPivot){ leftPivot=new THREE.Object3D(); root.add(leftPivot); } leftPivot.position.set(-bx/2, -by/2, 0); const m=new THREE.MeshStandardMaterial({ color:0xffffff, roughness:0.85 }); if(!leftMesh){ leftMesh=new THREE.Mesh(new THREE.BoxGeometry(sx,sy,sz),m); leftPivot.add(leftMesh); } else { leftMesh.material=m; leftMesh.geometry.dispose(); leftMesh.geometry=new THREE.BoxGeometry(sx,sy,sz); } leftMesh.position.set(+sx/2, +sy/2, 0); leftPivot.rotation.set(0,0,THREE.MathUtils.degToRad(-(90-ang))); if(!latESQ_on.checked){ root.remove(leftPivot); leftPivot=null; leftMesh=null; } render(); fitCameraToScene(1.8); } document.getElementById('top_on').addEventListener('change', reapplyAllDebounced); ['top_x','top_y','top_z','top_ang'].forEach(id=>{ document.getElementById(id).addEventListener('input', ()=>{ if(top_on.checked) applyTop(); }); }); function applyTop(){ const bx=+dimX.value||40, by=+dimY.value||2, bz=+dimZ.value||20; let tX = Math.max(0.1, +top_x.value || bx); const tY = Math.max(0.1, +top_y.value || 1.5); const tZ = Math.max(0.1, +top_z.value || bz); const ang= Math.max(0, Math.min(120, +top_ang.value || 0)); const R_on = latDR_on.checked, L_on = latESQ_on.checked; const R_sy = R_on ? (+latDR_y.value || 0) : 0; const L_sy = L_on ? (+latESQ_y.value || 0) : 0; if(!topPivot){ topPivot=new THREE.Object3D(); root.add(topPivot); } let alturaLaterais = 0; if (R_on && L_on) alturaLaterais = Math.min(R_sy, L_sy); else if (R_on) alturaLaterais = R_sy; else if (L_on) alturaLaterais = L_sy; const yTopoVao = -by/2 + alturaLaterais; topPivot.position.set(0, yTopoVao, +bz/2); tX = bx; // encaixe sem folga const m = new THREE.MeshStandardMaterial({ color:0xffffff, roughness:0.85 }); if(!topMesh){ topMesh=new THREE.Mesh(new THREE.BoxGeometry(tX,tY,tZ), m); topPivot.add(topMesh); } else { topMesh.material=m; topMesh.geometry.dispose(); topMesh.geometry=new THREE.BoxGeometry(tX,tY,tZ); } topMesh.position.set(0, -tY/2, -tZ/2); topPivot.rotation.set(THREE.MathUtils.degToRad(-ang), 0, 0); if(!top_on.checked){ root.remove(topPivot); topPivot=null; topMesh=null; } render(); fitCameraToScene(1.8); } /* ====== INICIAL ====== */ fitCameraToScene(1.8); </script> </body> </html>