Files
a2f-service/examples/3d/index.html
yinsx c10cfa7c33 1
2026-02-03 14:16:42 +08:00

187 lines
9.3 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Digital Human - BlendShapes Demo</title>
<link rel="stylesheet" href="./styles.css">
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
<script src="./blendshapeAnimator.js"></script>
<script src="./babylonAdapter.js"></script>
<script src="./babylonScene.js"></script>
<script src="./expressionLibrary.js"></script>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<div class="controls collapsible-panel" id="mainControls">
<div class="panel-header">
<h2>数字人形态键控制</h2>
<button type="button" class="panel-toggle" onclick="togglePanel('mainControls')">收起</button>
</div>
<div class="panel-body">
<div class="input-group">
<label>文字输入</label>
<textarea id="textInput" placeholder="输入文字生成动画...">君不见,黄河之水天上来,奔流到海不复回,君不见,高堂明镜悲白发,朝如青丝暮成雪。</textarea>
</div>
<div class="input-group">
<label>API 地址</label>
<input type="text" id="apiUrl" value="http://localhost:5001/text-to-blendshapes">
</div>
<div class="input-group toggle-group">
<label>
<input type="checkbox" id="streamEnabled" checked>
启用流式传输
</label>
</div>
<div class="input-group">
<label>形态键强度: <span id="scaleValue">1.0</span></label>
<input type="range" id="scaleSlider" min="0" max="2" step="0.1" value="1.0"
oninput="updateScale(this.value)"
style="width: 100%; cursor: pointer;">
</div>
<div class="input-group">
<label>动画速度 (FPS): <span id="fpsValue">30</span></label>
<input type="range" id="fpsSlider" min="10" max="60" step="1" value="30"
oninput="updateFps(this.value)"
style="width: 100%; cursor: pointer;">
</div>
<button id="generateBtn" onclick="generateAnimation()">生成动画</button>
<button onclick="playAnimation()">播放动画</button>
<button onclick="stopAnimation()">停止动画</button>
<button onclick="testBlendShape()">测试形态键</button>
<button onclick="resetBlendShapes()">重置形态键</button>
<div class="input-group">
<label>CSV动画文件</label>
<select id="csvSelect">
<option value="">-- 选择CSV文件 --</option>
</select>
<button onclick="loadAndPlayCsv()">播放单个</button>
<button id="playAllCsvBtn" onclick="playAllCsv()">播放全部CSV</button>
<div id="currentCsvName" style="margin-top: 8px; font-weight: bold; color: #4CAF50;"></div>
</div>
<div class="status" id="status"></div>
</div>
</div>
<!-- 当前播放句子显示(屏幕中央) -->
<div class="current-sentence" id="currentSentence" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 20px 40px; background: rgba(0,0,0,0.7); border-radius: 10px; color: white; font-size: 24px; text-align: center; display: none; z-index: 1000; max-width: 80%; pointer-events: none;">
<div id="sentenceText"></div>
</div>
<div class="idle-controls collapsible-panel" id="idleControls">
<div class="panel-header">
<h2>空闲动画控制</h2>
<button type="button" class="panel-toggle" onclick="togglePanel('idleControls')">收起</button>
</div>
<div class="panel-body">
<!-- 随机眨眼 -->
<div class="checkbox-group">
<label>
<button class="collapse-btn" onclick="toggleCollapse(event, 'blinkParams')"></button>
<input type="checkbox" id="blinkEnabled" onchange="toggleBlink()">
<span>随机眨眼</span>
</label>
<div class="param-group" id="blinkParams">
<div class="param-item">
<label>频率间隔 (秒): <span class="param-value" id="blinkIntervalValue">1-2</span></label>
<input type="range" id="blinkIntervalMin" min="1" max="5" step="0.5" value="1"
oninput="updateBlinkInterval()">
<input type="range" id="blinkIntervalMax" min="2" max="10" step="0.5" value="2"
oninput="updateBlinkInterval()">
</div>
<div class="param-item">
<label>闭眼时长 (ms): <span class="param-value" id="blinkDurationValue">150</span></label>
<input type="range" id="blinkDuration" min="100" max="300" step="10" value="150"
oninput="updateBlinkDuration(this.value)">
</div>
<div class="param-item">
<label>动画速度 (ms): <span class="param-value" id="blinkSpeedValue">100</span></label>
<input type="range" id="blinkSpeed" min="50" max="200" step="10" value="100"
oninput="updateBlinkSpeed(this.value)">
</div>
</div>
</div>
<!-- 眼球移动 -->
<div class="checkbox-group">
<label>
<button class="collapse-btn" onclick="toggleCollapse(event, 'eyeLookParams')"></button>
<input type="checkbox" id="eyeLookEnabled" onchange="toggleEyeLook()">
<span>眼球移动</span>
</label>
<div class="param-group" id="eyeLookParams">
<div class="param-item">
<label>频率间隔 (秒): <span class="param-value" id="eyeLookIntervalValue">1-2</span></label>
<input type="range" id="eyeLookIntervalMin" min="1" max="5" step="0.5" value="1"
oninput="updateEyeLookInterval()">
<input type="range" id="eyeLookIntervalMax" min="2" max="10" step="0.5" value="2"
oninput="updateEyeLookInterval()">
</div>
<div class="param-item">
<label>停留时长 (ms): <span class="param-value" id="eyeLookDurationValue">1000-2500</span></label>
<input type="range" id="eyeLookDurationMin" min="500" max="2000" step="100" value="1000"
oninput="updateEyeLookDuration()">
<input type="range" id="eyeLookDurationMax" min="1000" max="4000" step="100" value="2500"
oninput="updateEyeLookDuration()">
</div>
<div class="param-item">
<label>移动速度 (ms): <span class="param-value" id="eyeLookSpeedValue">250</span></label>
<input type="range" id="eyeLookSpeed" min="100" max="500" step="25" value="250"
oninput="updateEyeLookSpeed(this.value)">
</div>
</div>
</div>
<!-- 随机表情 -->
<div class="checkbox-group">
<label>
<button class="collapse-btn" onclick="toggleCollapse(event, 'expressionParams')"></button>
<input type="checkbox" id="expressionEnabled" onchange="toggleRandomExpression()">
<span>随机表情</span>
</label>
<div class="param-group" id="expressionParams">
<div class="param-item">
<label>选择表情:</label>
<div class="expression-list" id="expressionList">
<!-- 动态生成 -->
</div>
</div>
<div class="param-item">
<label>频率间隔 (秒): <span class="param-value" id="expressionIntervalValue">1-1</span></label>
<input type="range" id="expressionIntervalMin" min="0" max="8" step="0.5" value="1"
oninput="updateExpressionInterval()">
<input type="range" id="expressionIntervalMax" min="0.5" max="15" step="0.5" value="1"
oninput="updateExpressionInterval()">
</div>
<div class="param-item">
<label>表情幅度: <span class="param-value" id="expressionStrengthValue">1.3</span></label>
<input type="range" id="expressionStrength" min="0" max="2" step="0.1" value="1.0"
oninput="updateExpressionStrength(this.value)">
</div>
<div class="param-item">
<label>动画速度 (ms): <span class="param-value" id="expressionSpeedValue">400</span></label>
<input type="range" id="expressionSpeed" min="200" max="800" step="50" value="400"
oninput="updateExpressionSpeed(this.value)">
</div>
</div>
</div>
</div>
<script src="./main.js"></script>
</body>
</html>