Discusión

Escena Web Interactiva 3D de Valle de Cerezos en Voxel

De Wikiprompt, la enciclopedia libre de prompts

宝玉
Contribuido por宝玉XFuente

23 sept 2026

Escena Web Interactiva 3D de Valle de Cerezos en Voxel Un prompt excepcionalmente detallado en chino que dirige a un asistente de codificación de IA para construir un valle de cerezos japonés en arte voxel 3D totalmente interactivo como una página web HTML/JS autocontenida, completo con vistas de cámara, cambio de ambiente y una lista de verificación de autoevaluación antes de la entrega.

Medios relacionados

Contenido del PromptGuardar

🌐
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>日式樱花山谷 · 蓝调时刻</title> <style> body { margin: 0; overflow: hidden; font-family: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif; background-color: #0a0f1a; } #info { position: absolute; top: 16px; left: 16px; color: rgba(255, 255, 255, 0.8); background: rgba(10, 15, 30, 0.5); backdrop-filter: blur(6px); padding: 8px 16px; border-radius: 40px; font-size: 14px; letter-spacing: 1px; border: 1px solid rgba(255, 255, 255, 0.15); pointer-events: none; z-index: 10; text-shadow: 0 1px 4px rgba(0,0,0,0.3); } #controls { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); display: flex; gap: 10px; background: rgba(10, 15, 30, 0.6); backdrop-filter: blur(8px); padding: 10px 18px; border-radius: 60px; border: 1px solid rgba(255, 255, 255, 0.15); z-index: 20; flex-wrap: wrap; justify-content: center; box-shadow: 0 8px 24px rgba(0,0,0,0.4); pointer-events: auto; } .btn { background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); color: #f0e6d8; padding: 6px 14px; border-radius: 40px; font-size: 13px; cursor: pointer; transition: all 0.2s ease; white-space: nowrap; backdrop-filter: blur(4px); letter-spacing: 0.5px; font-weight: 400; box-shadow: 0 2px 8px rgba(0,0,0,0.2); } .btn:hover { background: rgba(255, 255, 255, 0.25); border-color: rgba(255, 200, 150, 0.5); color: #fff; } .btn.active { background: rgba(220, 180, 140, 0.3); border-color: #ffb98a; color: #fff; } #ui-toggle { position: absolute; bottom: 20px; right: 20px; z-index: 30; background: rgba(10, 15, 30, 0.5); backdrop-filter: blur(6px); border: 1px solid rgba(255,255,255,0.2); border-radius: 40px; padding: 6px 12px; color: #ddd; font-size: 12px; cursor: pointer; } #loading { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #ccc; font-size: 18px; background: rgba(0,0,0,0.5); padding: 12px 24px; border-radius: 40px; z-index: 100; letter-spacing: 2px; backdrop-filter: blur(4px); border: 1px solid rgba(255,255,255,0.2); transition: opacity 0.5s; } #error { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); color: #ffaa88; background: rgba(30, 10, 10, 0.7); padding: 8px 20px; border-radius: 30px; font-size: 14px; z-index: 200; display: none; border: 1px solid #ff9966; backdrop-filter: blur(4px); } @media (max-width: 600px) { #controls { bottom: 12px; padding: 8px 12px; gap: 6px; width: 95%; overflow-x: auto; justify-content: flex-start; flex-wrap: nowrap; scrollbar-width: none; } #controls::-webkit-scrollbar { display: none; } .btn { font-size: 12px; padding: 5px 10px; flex-shrink: 0; } #info { font-size: 12px; top: 10px; left: 10px; padding: 4px 12px; } } canvas { display: block; } </style> </head> <body> <div id="info">🌸 日式樱花山谷 · 蓝调时刻</div> <div id="controls"> <button class="btn" id="view1">🏔️ 山谷全景</button> <button class="btn" id="view2">🌊 河边低机位</button> <button class="btn" id="view3">⛩️ 寺庙小径</button> <button class="btn" id="view4">⛰️ 山坡俯瞰</button> <button class="btn" id="reset">↺ 重置视角</button> <button class="btn" id="toggleUI">🙈 隐藏界面</button> <button class="btn" id="save">📸 保存画面</button> <button class="btn" id="mood1">🌙 蓝调</button> <button class="btn" id="mood2">🌅 清晨</button> <button class="btn" id="mood3">🌧️ 雨中</button> </div> <div id="ui-toggle">🙈</div> <div id="loading">🌸 加载山谷中...</div> <div id="error"></div> <!-- 引入 Three.js 核心库和扩展 --> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three@0.128.0/build/three.module.js", "three/addons/": "https://unpkg.com/three@0.128.0/examples/jsm/" } } </script> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; import { FXAAShader } from 'three/addons/shaders/FXAAShader.js'; // --- 初始化场景 --- const scene = new THREE.Scene(); scene.background = new THREE.Color(0x0a1220); scene.fog = new THREE.FogExp2(0x0a1220, 0.006); // --- 相机 (透视) --- const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(18, 8, 22); camera.lookAt(0, 2, 0); // --- 渲染器 --- const renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: "high-performance" }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1.2; document.body.appendChild(renderer.domElement); // --- 后期特效: 泛光 + FXAA --- const composer = new EffectComposer(renderer); const renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.3, 0.4, 0.85); bloomPass.threshold = 0.6; bloomPass.strength = 0.5; bloomPass.radius = 0.2; composer.addPass(bloomPass); // FXAA 抗锯齿 const fxaaPass = new ShaderPass(FXAAShader); fxaaPass.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight); composer.addPass(fxaaPass); // --- 控制器 --- const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; controls.maxPolarAngle = Math.PI / 2.2; controls.minDistance = 5; controls.maxDistance = 40; controls.target.set(0, 3, 0); // --- 光照 --- // 环境光 (蓝调) const ambientLight = new THREE.AmbientLight(0x404060, 0.6); scene.add(ambientLight); // 主光 (冷月光) const dirLight = new THREE.DirectionalLight(0xc8d0ff, 0.8); dirLight.position.set(-10, 20, 10); dirLight.castShadow = true; dirLight.shadow.mapSize.width = 1024; dirLight.shadow.mapSize.height = 1024; dirLight.shadow.camera.near = 0.5; dirLight.shadow.camera.far = 50; dirLight.shadow.camera.left = -20; dirLight.shadow.camera.right = 20; dirLight.shadow.camera.top = 20; dirLight.shadow.camera.bottom = -20; scene.add(dirLight); // 暖色补光 (灯笼/窗光) const warmLight = new THREE.PointLight(0xffaa66, 0.5, 20); warmLight.position.set(5, 2, 3); scene.add(warmLight); // 辅助背光 const backLight = new THREE.PointLight(0x8899ff, 0.3, 30); backLight.position.set(-5, 5, -10); scene.add(backLight); // --- 地面 / 地形 (程序化起伏) --- const groundGeo = new THREE.PlaneGeometry(60, 60, 64, 64); groundGeo.rotateX(-Math.PI / 2); const posAttr = groundGeo.attributes.position; for (let i = 0; i < posAttr.count; i++) { const x = posAttr.getX(i); const z = posAttr.getZ(i); // 山谷起伏 let y = 0; y += Math.sin(x * 0.2) * 0.8; y += Math.cos(z * 0.25) * 0.8; y += Math.sin(x * 0.5 + z * 0.3) * 0.4; // 河流区域凹陷 const distToRiver = Math.abs(z - 2 * Math.sin(x * 0.15) - 1); if (distToRiver < 2.5) { y -= 1.2 * (1 - distToRiver / 2.5); } // 山坡 if (x > 8) y += (x - 8) * 0.3; if (x < -10) y += (-10 - x) * 0.2; posAttr.setY(i, y); } groundGeo.computeVertexNormals(); const groundMat = new THREE.MeshStandardMaterial({ color: 0x3a4a3a, roughness: 0.8, metalness: 0.1, emissive: new THREE.Color(0x111122) }); const ground = new THREE.Mesh(groundGeo, groundMat); ground.receiveShadow = true; scene.add(ground); // --- 河流 (半透明平面) --- const riverGeo = new THREE.PlaneGeometry(4, 30); riverGeo.rotateX(-Math.PI / 2); const riverMat = new THREE.MeshStandardMaterial({ color: 0x2a4a5a, transparent: true, opacity: 0.7, roughness: 0.2, metalness: 0.1, emissive: new THREE.Color(0x112233) }); const river = new THREE.Mesh(riverGeo, riverMat); river.position.set(0, 0.1, 2); river.rotation.z = 0.2; river.receiveShadow = true; scene.add(river); // --- 红色木桥 --- const bridgeGroup = new THREE.Group(); const bridgeMat = new THREE.MeshStandardMaterial({ color: 0xaa4444, roughness: 0.7 }); const bridgePlank = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.1, 1.2), bridgeMat); bridgePlank.position.set(0, 0.2, 0); bridgePlank.castShadow = true; bridgeGroup.add(bridgePlank); for (let i = -2; i <= 2; i++) { const plank = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.05, 0.8), bridgeMat); plank.position.set(i * 0.4, 0.35, 0); plank.castShadow = true; bridgeGroup.add(plank); } // 桥柱 const pillarMat = new THREE.MeshStandardMaterial({ color: 0x8a5a3a }); for (let i = -1; i <= 1; i+=2) { const pillar = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.8, 0.2), pillarMat); pillar.position.set(i * 1.2, 0.4, 0.6); pillar.castShadow = true; bridgeGroup.add(pillar); const pillar2 = pillar.clone(); pillar2.position.z = -0.6; bridgeGroup.add(pillar2); } bridgeGroup.position.set(0.5, 0.2, 1.5); bridgeGroup.rotation.y = 0.3; scene.add(bridgeGroup); // --- 樱花树 (程序化) --- function createSakuraTree(pos, scale = 1) { const treeGroup = new THREE.Group(); // 树干 const trunkMat = new THREE.MeshStandardMaterial({ color: 0x5a3a2a, roughness: 0.9 }); const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.3 * scale, 0.5 * scale, 2.5 * scale, 6), trunkMat); trunk.position.y = 1.2 * scale; trunk.castShadow = true; treeGroup.add(trunk); // 分支 const branchMat = new THREE.MeshStandardMaterial({ color: 0x4a2a1a }); for (let i = 0; i < 5; i++) { const branch = new THREE.Mesh(new THREE.CylinderGeometry(0.1 * scale, 0.2 * scale, 1.2 * scale, 4), branchMat); branch.position.y = 2.0 * scale + i * 0.2; branch.rotation.z = (i - 2) * 0.3; branch.rotation.x = (i % 2 === 0 ? 0.2 : -0.2); branch.castShadow = true; treeGroup.add(branch); } // 花簇 (多个小球) const flowerMat = new THREE.MeshStandardMaterial({ color: 0xffaacc, emissive: new THREE.Color(0x552233), roughness: 0.4, emissiveIntensity: 0.2 }); for (let i = 0; i < 30; i++) { const flower = new THREE.Mesh(new THREE.SphereGeometry(0.2 * scale + Math.random()*0.1, 5), flowerMat); const angle = Math.random() * Math.PI * 2; const radius = 0.8 * scale + Math.random() * 0.5; const height = 2.0 * scale + Math.random() * 1.5; flower.position.set(Math.cos(angle) * radius, height, Math.sin(angle) * radius); flower.castShadow = true; treeGroup.add(flower); } treeGroup.position.set(pos.x, pos.y, pos.z); return treeGroup; } // 前景大樱花树 const bigTree = createSakuraTree(new THREE.Vector3(-4, 0.2, -2), 1.5); scene.add(bigTree); // 中景几棵 scene.add(createSakuraTree(new THREE.Vector3(3, 0.1, 4), 1.0)); scene.add(createSakuraTree(new THREE.Vector3(-2, 0.2, 6), 1.2)); scene.add(createSakuraTree(new THREE.Vector3(6, 0.3, -1), 0.9)); // --- 石灯笼 --- const stoneMat = new THREE.MeshStandardMaterial({ color: 0x6a6a6a, roughness: 0.8 }); const lanternBase = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.4, 0.5, 6), stoneMat); lanternBase.position.set(-3, 0.25, 1); lanternBase.castShadow = true; scene.add(lanternBase); const lanternTop = new THREE.Mesh(new THREE.SphereGeometry(0.25, 6), stoneMat); lanternTop.position.set(-3, 0.7, 1); lanternTop.castShadow = true; scene.add(lanternTop); // 暖光 const lanternLight = new THREE.PointLight(0xffaa66, 0.8, 4); lanternLight.position.set(-3, 0.8, 1); scene.add(lanternLight); // --- 建筑 (茶屋/神社) --- function createHouse(pos, scale = 1, color = 0x8a6a4a) { const house = new THREE.Group(); const baseMat = new THREE.MeshStandardMaterial({ color: color, roughness: 0.7 }); const roofMat = new THREE.MeshStandardMaterial({ color: 0x4a3a3a, roughness: 0.6 }); // 主体 const base = new THREE.Mesh(new THREE.BoxGeometry(1.2 * scale, 0.8 * scale, 1.2 * scale), baseMat); base.position.y = 0.4 * scale; base.castShadow = true; house.add(base); // 屋顶 const roof = new THREE.Mesh(new THREE.ConeGeometry(1.0 * scale, 0.5 * scale, 4), roofMat); roof.position.y = 1.0 * scale; roof.rotation.y = Math.PI/4; roof.castShadow = true; house.add(roof); // 窗光 const windowLight = new THREE.PointLight(0xffaa66, 0.4, 3); windowLight.position.set(0.3 * scale, 0.5 * scale, 0.5 * scale); house.add(windowLight); house.position.set(pos.x, pos.y, pos.z); return house; } scene.add(createHouse(new THREE.Vector3(2, 0.2, 3), 1.0)); scene.add(createHouse(new THREE.Vector3(-1.5, 0.3, 5), 0.8, 0x7a5a3a)); scene.add(createHouse(new THREE.Vector3(4, 0.4, -2), 1.2, 0x9a7a5a)); // --- 多层塔 (远景) --- function createPagoda(pos, scale = 1) { const pagoda = new THREE.Group(); const mat = new THREE.MeshStandardMaterial({ color: 0x6a4a3a, roughness: 0.7 }); const roofMat = new THREE.MeshStandardMaterial({ color: 0x3a2a2a }); for (let i = 0; i < 3; i++) { const base = new THREE.Mesh(new THREE.BoxGeometry(0.8 * scale, 0.4 * scale, 0.8 * scale), mat); base.position.y = i * 0.6 * scale + 0.2 * scale; base.castShadow = true; pagoda.add(base); const roof = new THREE.Mesh(new THREE.ConeGeometry(0.7 * scale, 0.3 * scale, 4), roofMat); roof.position.y = i * 0.6 * scale + 0.5 * scale; roof.rotation.y = Math.PI/4; roof.castShadow = true; pagoda.add(roof); } pagoda.position.set(pos.x, pos.y, pos.z); return pagoda; } scene.add(createPagoda(new THREE.Vector3(8, 0.8, -5), 1.5)); scene.add(createPagoda(new THREE.Vector3(-7, 0.6, -3), 1.2)); // --- 远山/雪山 --- const mountainMat = new THREE.MeshStandardMaterial({ color: 0x8a9aaa, roughness: 0.9, emissive: new THREE.Color(0x223344) }); const m1 = new THREE.Mesh(new THREE.ConeGeometry(4, 3, 5), mountainMat); m1.position.set(-12, 1.5, -15); m1.castShadow = true; scene.add(m1); const m2 = new THREE.Mesh(new THREE.ConeGeometry(5, 4, 5), mountainMat); m2.position.set(10, 2, -18); m2.castShadow = true; scene.add(m2); const m3 = new THREE.Mesh(new THREE.ConeGeometry(3, 2.5, 5), mountainMat); m3.position.set(0, 1.2, -20); m3.castShadow = true; scene.add(m3); // --- 岩石/草丛 (点缀) --- const rockMat = new THREE.MeshStandardMaterial({ color: 0x5a5a5a, roughness: 0.9 }); for (let i = 0; i < 20; i++) { const rock = new THREE.Mesh(new THREE.DodecahedronGeometry(0.2 + Math.random()*0.3), rockMat); rock.position.set(Math.random() * 20 - 10, 0.1, Math.random() * 20 - 10); rock.castShadow = true; scene.add(rock); } // --- 落花粒子 --- const petalCount = 80; const petalGeo = new THREE.SphereGeometry(0.05, 3); const petalMat = new THREE.MeshStandardMaterial({ color: 0xffaacc, emissive: new THREE.Color(0x552233), emissiveIntensity: 0.3 }); const petals = new THREE.InstancedMesh(petalGeo, petalMat, petalCount); const dummy = new THREE.Object3D(); for (let i = 0; i < petalCount; i++) { dummy.position.set(Math.random() * 20 - 10, Math.random() * 5 + 1, Math.random() * 20 - 10); dummy.scale.set(1, 1, 1); dummy.updateMatrix(); petals.setMatrixAt(i, dummy.matrix); } scene.add(petals); // --- 萤火虫 (远处) --- const fireflyMat = new THREE.MeshStandardMaterial({ color: 0xffdd88, emissive: new THREE.Color(0xffaa44), emissiveIntensity: 0.8 }); const fireflies = new THREE.InstancedMesh(new THREE.SphereGeometry(0.06, 4), fireflyMat, 30); for (let i = 0; i < 30; i++) { dummy.position.set(Math.random() * 20 - 10, Math.random() * 4 + 0.5, Math.random() * 20 - 10); dummy.updateMatrix(); fireflies.setMatrixAt(i, dummy.matrix); } scene.add(fireflies); // --- 氛围切换 --- function setMood(mood) { if (mood === 'blue') { scene.background = new THREE.Color(0x0a1220); scene.fog.color.set(0x0a1220); dirLight.color.set(0xc8d0ff); dirLight.intensity = 0.8; ambientLight.color.set(0x404060); ambientLight.intensity = 0.6; bloomPass.strength = 0.5; } else if (mood === 'morning') { scene.background = new THREE.Color(0x8a9aaa); scene.fog.color.set(0x8a9aaa); dirLight.color.set(0xffccaa); dirLight.intensity = 1.2; ambientLight.color.set(0x8899aa); ambientLight.intensity = 0.8; bloomPass.strength = 0.3; } else if (mood === 'rain') { scene.background = new THREE.Color(0x2a3a4a); scene.fog.color.set(0x2a3a4a); dirLight.color.set(0x8899aa); dirLight.intensity = 0.4; ambientLight.color.set(0x556677); ambientLight.intensity = 0.5; bloomPass.strength = 0.2; } } // --- 镜头预设 --- const views = { view1: { pos: new THREE.Vector3(18, 8, 22), target: new THREE.Vector3(0, 2, 0) }, view2: { pos: new THREE.Vector3(2, 1.5, 5), target: new THREE.Vector3(0, 0.5, 2) }, view3: { pos: new THREE.Vector3(-3, 2, 6), target: new THREE.Vector3(0, 1, 3) }, view4: { pos: new THREE.Vector3(10, 12, -5), target: new THREE.Vector3(0, 2, 0) } }; // --- UI 事件绑定 --- document.getElementById('view1').addEventListener('click', () => { camera.position.copy(views.view1.pos); controls.target.copy(views.view1.target); }); document.getElementById('view2').addEventListener('click', () => { camera.position.copy(views.view2.pos); controls.target.copy(views.view2.target); }); document.getElementById('view3').addEventListener('click', () => { camera.position.copy(views.view3.pos); controls.target.copy(views.view3.target); }); document.getElementById('view4').addEventListener('click', () => { camera.position.copy(views.view4.pos); controls.target.copy(views.view4.target); }); document.getElementById('reset').addEventListener('click', () => { camera.position.set(18, 8, 22); controls.target.set(0, 2, 0); }); document.getElementById('toggleUI').addEventListener('click', () => { const controlsEl = document.getElementById('controls'); controlsEl.style.display = controlsEl.style.display === 'none' ? 'flex' : 'none'; }); document.getElementById('save').addEventListener('click', () => { renderer.render(scene, camera); const link = document.createElement('a'); link.download = 'sakura_valley.png'; link.href = renderer.domElement.toDataURL('image/png'); link.click(); }); document.getElementById('mood1').addEventListener('click', () => setMood('blue')); document.getElementById('mood2').addEventListener('click', () => setMood('morning')); document.getElementById('mood3').addEventListener('click', () => setMood('rain')); // 隐藏加载 setTimeout(() => { document.getElementById('loading').style.opacity = '0'; setTimeout(() => document.getElementById('loading').style.display = 'none', 500); }, 1000); // --- 动画循环 --- let time = 0; function animate() { requestAnimationFrame(animate); time += 0.01; // 落花飘动 petals.rotation.y += 0.0005; // 萤火虫闪烁 fireflies.rotation.y += 0.001; controls.update(); composer.render(); } animate(); // --- 窗口大小自适应 --- window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); composer.setSize(window.innerWidth, window.innerHeight); fxaaPass.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight); }); // 错误处理 window.addEventListener('error', (e) => { document.getElementById('error').textContent = '渲染错误: ' + e.message; document.getElementById('error').style.display = 'block'; }); // 移动端提示 if (/Mobi|Android/i.test(navigator.userAgent)) { document.getElementById('info').textContent = '🌸 樱花山谷 · 拖动/双指缩放'; } </script> </body> </html>

Iniciá sesión para ver el prompt completo

Continuar con:

Al iniciar sesión, aceptás nuestros Términos de uso y Política de privacidad

Uso

Este prompt está diseñado para usarse con coding. Copiá el contenido de arriba y pegalo en tu herramienta de IA preferida.

Para mejores resultados, personalizá los marcadores (indicados con corchetes o mayúsculas) con tus requisitos específicos.

Referencias

Categorías:coding| twitter| 3d-voxel-art| interactive-webpage

Discusión