three实现三维山坡上的寺庙场景代码

代码语言:html

所属分类:其他

代码由minimax-m3.1-flash ai生成,可能有错误,仅供参考:点击查看提示词

代码描述:three实现三维山坡上的寺庙场景代码

代码标签: three 三维 山坡 寺庙 场景 代码

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>云隐禅寺 · 山坡寺庙三维场景</title>
<style>
  :root{
    --ink:#e8e3d8; --ink-dim:#a7a094; --gold:#d8b26a; --line:rgba(216,178,106,.28);
    --glass:rgba(18,20,24,.58);
  }
  *{box-sizing:border-box}
  html,body{margin:0;height:100%;overflow:hidden;background:#0a0d12;color:var(--ink);
    font-family:"PingFang SC","Microsoft YaHei","Noto Sans SC",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;}
  canvas{display:block}
  #app{position:fixed;inset:0}

  /* ---------- 加载 ---------- */
  #loader{position:fixed;inset:0;z-index:50;display:flex;flex-direction:column;align-items:center;justify-content:center;
    gap:18px;background:radial-gradient(120% 90% at 50% 30%,#1d2733 0%,#0a0d12 70%);transition:opacity .9s ease}
  #loader.hide{opacity:0;pointer-events:none}
  .lbrand{font-size:26px;letter-spacing:.42em;color:var(--gold);text-indent:.42em;font-weight:300}
  .lsub{font-size:12px;letter-spacing:.32em;color:var(--ink-dim);text-indent:.32em}
  .lbar{width:min(320px,64vw);height:2px;background:rgba(255,255,255,.12);border-radius:2px;overflow:hidden}
  .lbar i{display:block;height:100%;width:0%;background:linear-gradient(90deg,#8a6a32,var(--gold));transition:width .3s}
  .ltip{font-size:11px;color:#6f6a60;letter-spacing:.16em;min-height:14px}

  /* ---------- 标题 ---------- */
  #title{position:fixed;left:26px;top:24px;z-index:20;pointer-events:none;transition:opacity .6s}
  #title h1{margin:0;font-size:22px;font-weight:300;letter-spacing:.34em;text-indent:.34em;
    color:#f2ece0;text-shadow:0 2px 18px rgba(0,0,0,.75)}
  #title p{margin:6px 0 0;font-size:11px;letter-spacing:.24em;color:#cbc2b0;text-shadow:0 1px 10px rgba(0,0,0,.8)}

  /* ---------- 控制面板 ---------- */
  #panel{position:fixed;right:18px;top:18px;z-index:20;width:246px;padding:16px 16px 14px;border-radius:14px;
    background:var(--glass);backdrop-filter:blur(16px) saturate(140%);-webkit-backdrop-filter:blur(16px);
    border:1px solid var(--line);box-shadow:0 18px 50px rgba(0,0,0,.5);font-size:12px;
    transition:transform .35s cubic-bezier(.2,.8,.2,1),opacity .35s}
  #panel.hidden{transform:translateX(280px);opacity:0;pointer-events:none}
  #panel .row{display:flex;align-items:center;justify-content:space-between;margin:9px 0 4px;color:var(--ink-dim)}
  #panel .row b{color:var(--ink);font-weight:500;font-variant-numeric:tabular-nums}
  .grp{border-top:1px solid rgba(255,255,255,.08);margin-top:12px;padding-top:4px}
  .grp:first-of-type{border-top:none;margin-top:0;padding-top:0}
  .seclabel{font-size:10px;letter-spacing:.26em;color:#8d8577;margin:10px 0 6px}
  input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:16px;background:transparent;cursor:pointer}
  input[type=range]::-webkit-slider-runnable-track{height:2px;background:rgba(255,255,255,.16);border-radius:2px}
  input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;border-radius:50%;
    background:var(--gold);margin-top:-5px;box-shadow:0 0 8px rgba(216,178,106,.6)}
  input[type=range]::-moz-range-track{height:2px;background:rgba(255,255,255,.16);border-radius:2px}
  input[type=range]::-moz-range-thumb{width:12px;height:12px;border:none;border-radius:50%;background:var(--gold)}
  .btns{display:flex;flex-wrap:wrap;gap:5px}
  button{flex:1 1 auto;min-width:0;padding:6px 4px;font-size:11px;letter-spacing:.06em;color:var(--ink);
    background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);border-radius:8px;cursor:pointer;
    transition:.18s;white-space:nowrap;font-family:inherit}
  button:hover{background:rgba(216,178,106,.18);border-color:rgba(216,178,106,.45);color:#fff}
  button.on{background:linear-gradient(180deg,rgba(216,178,106,.34),rgba(216,178,106,.16));
    border-color:rgba(216,178,106,.6);color:#fff6e2}
  .toggles{display:grid;grid-template-columns:1fr 1fr;gap:5px}
  #stats{position:fixed;left:26px;bottom:20px;z-index:20;font-size:11px;letter-spacing:.1em;color:#b9b2a4;
    text-shadow:0 1px 8px rgba(0,0,0,.8);font-variant-numeric:tabular-nums}
  #hint{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:20;font-size:11px;letter-spacing:.2em;
    color:#b9b2a4;text-shadow:0 1px 8px rgba(0,0,0,.8);pointer-events:none;transition:opacity .8s}
  #toast{position:fixed;left:50%;top:26px;transform:translateX(-50%);z-index:40;padding:8px 16px;border-radius:20px;
    background:rgba(18,20,24,.8);border:1px solid var(--line);font-size:12px;letter-spacing:.14em;opacity:0;
    transition:opacity .35s;pointer-events:none;backdrop-filter:blur(10px)}
  #toast.show{opacity:1}
  #toggle{position:fixed;right:18px;top:18px;z-index:21;width:34px;height:34px;padding:0;flex:none;border-radius:10px;
    display:none;align-items:center;justify-content:center;font-size:15px}
  #toggle.show{display:flex}
  @media (max-width:720px){
    #panel{width:210px;right:10px;top:10px;padding:12px}
    #title{left:14px;top:14px}#title h1{font-size:17px}
    #stats{left:14px;bottom:12px}
  }
</style>
</head>
<body>
<div id="app"></div>

<div id="loader">
  <div class="lbrand">云隐禅寺</div>
  <div class="lbar"><i id="lbar-fill"></i></div>
  <div class="ltip" id="ltip">正在开山辟地…</div>
</div>

<div id="title">
  <h1>云隐禅寺</h1>
  <p id="subtitle">AIKOU MOUNTAIN · TEMPLE IN THE CLOUDS</p>
</div>

<button id="toggle">☰</button>
<div id="panel">
  <div class="grp">
    <div class="seclabel">时 刻</div>
    <div class="row"><span>时间</span><b id="v-time">16:21</b></div>
    <input type="range" id="s-time" min="4" max="23" step="0.02" value="16.35" />
    <div class="btns" style="margin-top:6px">
      <button data-time="5.6">晨</button><button data-time="8.4">上午</button>
      <button data-time="12">正午</button><button data-time="16.35" class="on">黄昏</button><button data-time="21.2">夜</button>
    </div>
  </div>
  <div class="grp">
    <div class="seclabel">机 位</div>
    <div class="btns">
      <button data-cam="0">远眺</button><button data-cam="1">山门</button>
      <button data-cam="2">庭院</button><button data-cam="3">檐角</button><button data-cam="4">俯瞰</button>
    </div>
  </div>
  <div class="grp">
    <div class="seclabel">气 象</div>
    <div class="toggles">
      <button data-tog="rain">细雨</button><button data-tog="snow">飞雪</button>
      <button data-tog="cloud">云海</button><button data-tog="fog">浓雾</button>
    </div>
    <div class="row" style="margin-top:10px"><span>雾气</span><b id="v-fog">0.20</b></div>
    <input type="range" id="s-fog" min="0" max="1" step="0.01" value="0.2" />
  </div>
  <div class="grp">
    <div class="seclabel">画 质</div>
    <div class="btns">
      <button data-q="low">流畅</button><button data-q="mid" class="on">均衡</button><button data-q="high">极致</button>
    </div>
    <div class="btns" style="margin-top:5px">
      <button id="b-auto">自动漫游</button><button id="b-shot">保存截图</button>
    </div>
  </div>
  <div class="grp">
    <div class="seclabel">状 态</div>
    <div class="row"><span>帧率</span><b id="v-fps">--</b></div>
    <div class="row"><span>绘制调用</span><b id="v-calls">--</b></div>
  </div>
</div>

<div id="stats">拖拽旋转 · 滚轮缩放 · 右键平移 · H 隐藏面板 · 空格 漫游</div>
<div id="hint">点击「均衡」画质体验最佳</div>
<div id="toast"></div>

<script type="importmap">
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@0.186.0/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.0/examples/jsm/"
  }
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { Sky } from 'three/addons/objects/Sky.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 { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
/* =====================================================================
 *  云隐禅寺 — 基础层:随机数 / 噪声 / 纹理工厂 / 材质库
 * ===================================================================*/
const QS = new URLSearchParams(location.search);
const num = (k, d) => (QS.has(k) ? parseFloat(QS.get(k)) : d);

/* 固定随机种子:保证每次打开场景布局一致(可复现) */
const SEED = 20240711;
let _rnd = mulberry32(SEED);
const R = () => _rnd();
function reseed(s){ _rnd = mulberry32(s); }

/* 画质档:决定草量、树量、阴影贴图与后期 */
const QUALITY = {
  low:  { grass: 0,     treeMul: 0.3,  shadow: 1024, bloom: false, particles: 0.3, rocks: 0.3, aa: false },
  mid:  { grass: 40000,treeMul: 0.75, shadow: 2048, bloom: true,  particles: 1.0,  rocks: 0.7, aa: true  },
  high: { grass: 95000,treeMul: 1.0,  shadow: 4096, bloom: true,  particles: 1.6,  rocks: 1.0,  aa: true  },
};
/* 自动挑画质:移动端 / 软件渲染 / 低端 GPU 自动降档 */
function autoQuality(){
  if (QS.get('q') && QUALITY[QS.get('q')]) return QS.get('q');
  const mobile = /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);
  if (mobile) return 'low';
  try{
    const c = document.createElement('canvas');
    const gl = c.getContext('webgl2') || c.getContext('webgl');
    const dbg = gl && gl.getExtension('WEBGL_debug_renderer_info');
    const r = dbg ? String(gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL)) : '';
    if (/swiftshader|llvmpipe|software|basic render/i.test(r)) return 'low';
    if (/(intel).*(hd graphics (2|3|4|5)|uhd graphics 6)/i.test(r)) return 'mid';
  }catch(e){}
  return (navigator.hardwareConcurrency || 4) <= 4 ? 'mid' : 'mid';
}
let QKEY = autoQuality();
let Q = QUALITY[QKEY];
if (num('grass', -1) >= 0) Q = { ...Q, grass: num('grass', 0) };
if (num('trees', -1) >= 0) Q = { ...Q, treeMul: num('trees', 1) };

/* 世界尺度(米) */
const W = {
  field: 420,        // 地形边长
  seg: 300,          // 地形分段
  plateauH: 17.5,    // 台地高度
  plateauR: 34,      // 台地半径
  gateZ: 30,         // 山门位置
  bottomZ: 132,      // 山脚
};

/* ---------------- 随机 / 噪声 ---------------- */
function mulberry32(a){ return function(){ a|=0; a = a + 0x6D2B79F5 | 0;
  let t = Math.imul(a ^ a>>>15, 1 | a); t = t + Math.imul(t ^ t>>>7, 61 | t) ^ t;
  return ((t ^ t>>>14) >>> 0) / 4294967296; }; }

function hash2(x, y, seed = 0){
  let h = Math.imul(x, 374761393) ^ Math.imul(y, 668265263) ^ Math.imul(seed, 1274126177);
  h = Math.imul(h ^ (h >>> 13), 1274126177);
  h ^= h >>> 16;
  return (h >>> 0) / 4294967296;
}
const sstep = t => t * t * (3 - 2 * t);
function vnoise(x, y, seed = 0){
  const ix = Math.floor(x), iy = Math.floor(y);
  const fx = sstep(x - ix), fy = sstep(y - iy);
  const a = hash2(ix, iy, seed),     b = hash2(ix + 1, iy, seed);
  const c = hash2(ix, iy + 1, seed), d = hash2(ix + 1, iy + 1, seed);
  return (a + (b - a) * fx) * (1 - fy) + (c + (d - c) * fx) * fy;
}
function fbm(x, y, oct = 4, seed =.........完整代码请登录后点击上方下载按钮下载查看

网友评论0