D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
var
/
www
/
html
/
crsys
/
Filename :
catalogo3D_lateral v25 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:335px 1fr; height:calc(100vh - 48px); } aside { border-right:1px solid #444; padding:12px; overflow:auto; } main { position:relative; } #viewport-container { position: relative; width: 50%; height: 50%; display: flex; justify-content: center; align-items: center; background: #111; border: 1px solid #555; border-radius: 6px; overflow: hidden; } #viewport { position: relative; width: 40%; height: 40%; } 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: 85px; --gap: 8px; --w-bloco: calc(var(--w-input)*3 + var(--gap)*2);} /* V19: 3 campos lado a lado */ .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;} /* 2 campos lado a lado mantendo a mesma estética */ .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%;} 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> <!--<div class="hint">Eixos: Direita = X+, Esquerda = X−, Frente = Z−, Trás = Z+, Cima = Y+.</div> --> </fieldset> <!-- Saia (apenas no tampo inferior) --> <fieldset> <legend>Saia do tampo inferior</legend> <!-- Saia frontal --> <label><input type="checkbox" id="sf_on"> Incluir 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"> Incluir 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"> Incluir 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> <!--<div class="hint"> Saia frontal: painel vertical sob a face Z− (frente).<br> Saia laterais: painéis verticais sob X+ e X−. Altura Y para baixo; espessura “entra” sob o tampo. </div>--> </fieldset> <!-- Frontões --> <fieldset> <legend>Frontão traseiro</legend> <label><input type="checkbox" id="ft_on"> Incluir 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</button> <!--<div class="hint"> O frontão nasce sobre o tampo, encostado na face traseira (Z+). Altura acima, espessura entra no tampo. </div>--> <hr style="border:none;border-top:1px solid #444; margin:10px 0"> <!-- Frontão lateral direito --> <label><input type="checkbox" id="ftR_on"> Incluir 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"> Incluir 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> </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> <!--<div class="hint">Pivô: (+X/2, −Y/2, 0). Offset: (−sx/2, +sy/2, 0). Face externa em +X/2.</div> --> </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> <!--<div class="hint">Pivô: (−X/2, −Y/2, 0). Offset: (+sx/2, +sy/2, 0). Face externa em −X/2.</div> --> </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> <!--<div class="hint"> Largura do tampo superior = X do tampo base (sem folga).<br> Centro em Y = (altura das laterais) − (espessura do tampo superior)/2. Abre para trás. </div> --> </fieldset> </aside> <main> <div id="viewport-container"> <div id="viewport"></div> </div> </main> </div> <script src="https://unpkg.com/three@0.160.0/build/three.min.js"></script> <script> /* ====== CENA ====== */ const container = document.getElementById('viewport-container'); // ✅ canvas dentro do container const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true }); container.appendChild(renderer.domElement); // ✅ canvas é filho direto do container // 🎯 Listener de zoom isolado container.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(0xffffff); // ✅ fundo branco da imagem const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 5000); scene.add(new THREE.HemisphereLight(0xffffff, 0xffffff, 0.9)); // luz mais branca 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; /* Frontões */ let backsplash, backsplashRight, backsplashLeft; /* ====== BASE ====== */ function makeBase(x = 40, y = 2, z = 20) { if (baseMesh) root.remove(baseMesh); const g = new THREE.BoxGeometry(x, y, z); const m = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.85 }); baseMesh = new THREE.Mesh(g, m); root.add(baseMesh); render(); } makeBase(); /* ====== CÂMERA ====== */ 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 ====== */ 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; container.addEventListener('pointerdown', e => { dragging = true; lx = e.clientX; ly = e.clientY; }); container.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(); }); container.addEventListener('pointerup', () => dragging = false); /* ====== RESIZE ====== */ function onResize() { const w = container.clientWidth; const h = container.clientHeight; renderer.setSize(w, h); camera.aspect = w / h; camera.updateProjectionMatrix(); updateCamera(); render(); } window.addEventListener('resize', onResize); onResize(); function render() { renderer.render(scene, camera); } updateCamera(); render(); /* ====== UI: APLICAR / RECENTRAR ====== */ aplicarDim.onclick = () => { const x = +dimX.value || 40, y = +dimY.value || 2, z = +dimZ.value || 20; makeBase(x, y, z); if (sf_on.checked) applySkirtFront(); if (sr_on.checked) applySkirtRight(); if (sl_on.checked) applySkirtLeft(); if (ft_on.checked) applyBacksplash(); if (ftR_on.checked) applyBacksplashRight(); if (ftL_on.checked) applyBacksplashLeft(); if (latDR_on.checked) applyRight(); if (latESQ_on.checked) applyLeft(); if (top_on.checked) applyTop(); fitCameraToScene(1.8); }; resetCamera.onclick = () => fitCameraToScene(1.8); /* ====== SAIA — FRONTAL ====== */ sf_apply.onclick = applySkirtFront; sf_on.onchange = 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 mat = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.85 }); const geo = new THREE.BoxGeometry(bx, h, t); if (!skirtFront) { skirtFront = new THREE.Mesh(geo, mat); root.add(skirtFront); } else { skirtFront.material = mat; skirtFront.geometry.dispose(); skirtFront.geometry = geo; } skirtFront.position.set(0, -by / 2 - h / 2, -bz / 2 + t / 2); render(); fitCameraToScene(1.8); } /* ====== OUTRAS PARTES (mantidas iguais) ====== */ /* ... todas as funções applySkirtRight, applySkirtLeft, applyBacksplash, etc ... */ /* ====== INICIAL ====== */ fitCameraToScene(1.8); </script> </body> </html>