当前位置: 首页 > news >正文

ThreeJS骨骼示例

<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>骨骼动画混合演示</title><style>body {margin: 0;padding: 0;background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);font-family: 'Arial', sans-serif;overflow: hidden;}#container {position: relative;width: 100vw;height: 100vh;}#controls {position: absolute;top: 20px;right: 20px;background: rgba(0, 0, 0, 0.8);padding: 20px;border-radius: 10px;backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.2);z-index: 100;min-width: 200px;}.control-section {margin-bottom: 15px;}.control-section h3 {color: #fff;margin: 0 0 10px 0;font-size: 14px;text-transform: uppercase;letter-spacing: 1px;}button {background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);border: none;padding: 8px 15px;margin: 3px;border-radius: 5px;color: white;cursor: pointer;font-size: 12px;transition: all 0.3s ease;min-width: 80px;}button:hover {transform: translateY(-2px);box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);}button.active {background: linear-gradient(45deg, #f093fb 0%, #f5576c 100%);box-shadow: 0 0 20px rgba(240, 147, 251, 0.5);}.slider-container {margin: 10px 0;}.slider-container label {color: #fff;font-size: 12px;display: block;margin-bottom: 5px;}input[type="range"] {width: 100%;height: 4px;border-radius: 2px;background: rgba(255, 255, 255, 0.3);outline: none;-webkit-appearance: none;}input[type="range"]::-webkit-slider-thumb {appearance: none;width: 16px;height: 16px;border-radius: 50%;background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);cursor: pointer;}#info {position: absolute;bottom: 20px;left: 20px;color: rgba(255, 255, 255, 0.8);font-size: 12px;max-width: 300px;}</style>
<input type="hidden" id="_o_dbjbempljhcmhlfpfacalomonjpalpko" data-inspect-config="7"><script type="text/javascript" src="chrome-extension://odphnbhiddhdpoccbialllejaajemdio/scripts/inspector.js"></script><link id="fl-highlights-css" rel="stylesheet" type="text/css" href="chrome-extension://dppcnmibpgmagiigcnfdjpnghplibbna/fl-highlights.css"><style id="monica-reading-highlight-style">.monica-reading-highlight {animation: fadeInOut 1.5s ease-in-out;}@keyframes fadeInOut {0%, 100% { background-color: transparent; }30%, 70% { background-color: rgba(2, 118, 255, 0.20); }}</style><style data-id="immersive-translate-input-injected-css">.immersive-translate-input {position: absolute;top: 0;right: 0;left: 0;bottom: 0;z-index: 2147483647;display: flex;justify-content: center;align-items: center;
}
.immersive-translate-attach-loading::after {content: " ";--loading-color: #f78fb6;width: 6px;height: 6px;border-radius: 50%;display: block;margin: 12px auto;position: relative;color: white;left: -100px;box-sizing: border-box;animation: immersiveTranslateShadowRolling 1.5s linear infinite;position: absolute;top: 50%;left: 50%;transform: translate(-2000%, -50%);z-index: 100;
}.immersive-translate-loading-spinner {vertical-align: middle !important;width: 10px !important;height: 10px !important;display: inline-block !important;margin: 0 4px !important;border: 2px rgba(221, 244, 255, 0.6) solid !important;border-top: 2px rgba(0, 0, 0, 0.375) solid !important;border-left: 2px rgba(0, 0, 0, 0.375) solid !important;border-radius: 50% !important;padding: 0 !important;-webkit-animation: immersive-translate-loading-animation 0.6s infinite linear !important;animation: immersive-translate-loading-animation 0.6s infinite linear !important;
}@-webkit-keyframes immersive-translate-loading-animation {from {-webkit-transform: rotate(0deg);}to {-webkit-transform: rotate(359deg);}
}@keyframes immersive-translate-loading-animation {from {transform: rotate(0deg);}to {transform: rotate(359deg);}
}.immersive-translate-input-loading {--loading-color: #f78fb6;width: 6px;height: 6px;border-radius: 50%;display: block;margin: 12px auto;position: relative;color: white;left: -100px;box-sizing: border-box;animation: immersiveTranslateShadowRolling 1.5s linear infinite;
}@keyframes immersiveTranslateShadowRolling {0% {box-shadow: 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0),0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0);}12% {box-shadow: 100px 0 var(--loading-color), 0px 0 rgba(255, 255, 255, 0),0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0);}25% {box-shadow: 110px 0 var(--loading-color), 100px 0 var(--loading-color),0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0);}36% {box-shadow: 120px 0 var(--loading-color), 110px 0 var(--loading-color),100px 0 var(--loading-color), 0px 0 rgba(255, 255, 255, 0);}50% {box-shadow: 130px 0 var(--loading-color), 120px 0 var(--loading-color),110px 0 var(--loading-color), 100px 0 var(--loading-color);}62% {box-shadow: 200px 0 rgba(255, 255, 255, 0), 130px 0 var(--loading-color),120px 0 var(--loading-color), 110px 0 var(--loading-color);}75% {box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0),130px 0 var(--loading-color), 120px 0 var(--loading-color);}87% {box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0),200px 0 rgba(255, 255, 255, 0), 130px 0 var(--loading-color);}100% {box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0),200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0);}
}.immersive-translate-toast {display: flex;position: fixed;z-index: 2147483647;left: 0;right: 0;top: 1%;width: fit-content;padding: 12px 20px;margin: auto;overflow: auto;background: #fef6f9;box-shadow: 0px 4px 10px 0px rgba(0, 10, 30, 0.06);font-size: 15px;border-radius: 8px;color: #333;
}.immersive-translate-toast-content {display: flex;flex-direction: row;align-items: center;
}.immersive-translate-toast-hidden {margin: 0 20px 0 72px;text-decoration: underline;cursor: pointer;
}.immersive-translate-toast-close {color: #666666;font-size: 20px;font-weight: bold;padding: 0 10px;cursor: pointer;
}@media screen and (max-width: 768px) {.immersive-translate-toast {top: 0;padding: 12px 0px 0 10px;}.immersive-translate-toast-content {flex-direction: column;text-align: center;}.immersive-translate-toast-hidden {margin: 10px auto;}
}.immersive-translate-dialog {position: fixed;z-index: 2147483647;left: 0;top: 0;display: flex;width: 300px;flex-direction: column;align-items: center;font-size: 15px;left: 0;right: 0;top: 0;bottom: 0;margin: auto;height: fit-content;border-radius: 20px;background-color: #fff;
}.immersive-translate-modal {display: none;position: fixed;z-index: 2147483647;left: 0;top: 0;width: 100%;height: 100%;overflow: auto;background-color: rgb(0, 0, 0);background-color: rgba(0, 0, 0, 0.4);font-size: 15px;
}.immersive-translate-modal-content {background-color: #fefefe;margin: 10% auto;padding: 40px 24px 24px;border-radius: 12px;width: 350px;font-family: system-ui, -apple-system, "Segoe UI", "Roboto", "Ubuntu","Cantarell", "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji","Segoe UI Symbol", "Noto Color Emoji";position: relative;
}@media screen and (max-width: 768px) {.immersive-translate-modal-content {margin: 25% auto !important;}
}@media screen and (max-width: 480px) {.immersive-translate-modal-content {width: 80vw !important;margin: 20vh auto !important;padding: 20px 12px 12px !important;}.immersive-translate-modal-title {font-size: 14px !important;}.immersive-translate-modal-body {font-size: 13px !important;max-height: 60vh !important;}.immersive-translate-btn {font-size: 13px !important;padding: 8px 16px !important;margin: 0 4px !important;}.immersive-translate-modal-footer {gap: 6px !important;margin-top: 16px !important;}
}.immersive-translate-modal .immersive-translate-modal-content-in-input {max-width: 500px;
}
.immersive-translate-modal-content-in-input .immersive-translate-modal-body {text-align: left;max-height: unset;
}.immersive-translate-modal-title {text-align: center;font-size: 16px;font-weight: 700;color: #333333;
}.immersive-translate-modal-body {text-align: center;font-size: 14px;font-weight: 400;color: #333333;margin-top: 24px;
}@media screen and (max-width: 768px) {.immersive-translate-modal-body {max-height: 250px;overflow-y: auto;}
}.immersive-translate-close {color: #666666;position: absolute;right: 16px;top: 16px;font-size: 20px;font-weight: bold;
}.immersive-translate-close:hover,
.immersive-translate-close:focus {text-decoration: none;cursor: pointer;
}.immersive-translate-modal-footer {display: flex;justify-content: center;flex-wrap: wrap;margin-top: 24px;
}.immersive-translate-btn {width: fit-content;color: #fff;background-color: #ea4c89;border: none;font-size: 14px;margin: 0 8px;padding: 9px 30px;border-radius: 5px;display: flex;align-items: center;justify-content: center;cursor: pointer;transition: background-color 0.3s ease;
}.immersive-translate-btn-container {display: flex;flex-direction: column;align-items: center;justify-content: center;gap: 8px;
}.immersive-translate-btn:hover {background-color: #f082ac;
}
.immersive-translate-btn:disabled {opacity: 0.6;cursor: not-allowed;
}
.immersive-translate-btn:disabled:hover {background-color: #ea4c89;
}.immersive-translate-link-btn {background-color: transparent;color: #ea4c89;border: none;cursor: pointer;height: 30px;line-height: 30px;
}.immersive-translate-cancel-btn {/* gray color */background-color: rgb(89, 107, 120);
}.immersive-translate-cancel-btn:hover {background-color: hsl(205, 20%, 32%);
}.immersive-translate-action-btn {background-color: transparent;color: #ea4c89;border: 1px solid #ea4c89;
}.immersive-translate-btn svg {margin-right: 5px;
}.immersive-translate-link {cursor: pointer;user-select: none;-webkit-user-drag: none;text-decoration: none;color: #ea4c89;-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
}.immersive-translate-primary-link {cursor: pointer;user-select: none;-webkit-user-drag: none;text-decoration: none;color: #ea4c89;-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
}.immersive-translate-modal input[type="radio"] {margin: 0 6px;cursor: pointer;
}.immersive-translate-modal label {cursor: pointer;
}.immersive-translate-close-action {position: absolute;top: 2px;right: 0px;cursor: pointer;
}.imt-image-status {background-color: rgba(0, 0, 0, 0.5) !important;display: flex !important;flex-direction: column !important;align-items: center !important;justify-content: center !important;border-radius: 16px !important;
}
.imt-image-status img,
.imt-image-status svg,
.imt-img-loading {width: 28px !important;height: 28px !important;margin: 0 0 8px 0 !important;min-height: 28px !important;min-width: 28px !important;position: relative !important;
}
.imt-img-loading {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAMAAACfWMssAAAAtFBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////oK74hAAAAPHRSTlMABBMIDyQXHwyBfFdDMSw+OjXCb+5RG51IvV/k0rOqlGRM6KKMhdvNyZBz9MaupmxpWyj437iYd/yJVNZeuUC7AAACt0lEQVRIx53T2XKiUBCA4QYOiyCbiAsuuGBcYtxiYtT3f6/pbqoYHVFO5r+iivpo6DpAWYpqeoFfr9f90DsYAuRSWkFnPO50OgR9PwiCUFcl2GEcx+N/YBh6pvKaefHlUgZd1zVe0NbYcQjGBfzrPE8Xz8aF+71D8gG6DHFPpc4a7xFiCDuhaWgKgGIJQ3d5IMGDrpS4S5KgpIm+en9f6PlAhKby4JwEIxlYJV9h5k5nee9GoxHJ2IDSNB0dwdad1NAxDJ/uXDHYmebdk4PdbkS58CIVHdYSUHTYYRWOJblWSyu2lmy3KNFVJNBhxcuGW4YBVCbYGRZwIooipHsNqjM4FbgOQqQqSKQQU9V8xmi1QlgHqQQ6DDBvRUVCDirs+EzGDGOQTCATgtYTnbCVLgsVgRE0T1QE0qHCFAht2z6dLvJQs3Lo2FQoDxWNUiBhaP4eRgwNkI+dAjVOA/kUrIDwf3CG8NfNOE0eiFotSuo+rBiq8tD9oY4Qzc6YJw99hl1wzpQvD7ef2M8QgnOGJfJw+EltQc+oX2yn907QB22WZcvlUpd143dqQu+8pCJZuGE4xCuPXJqqcs5sNpsI93Rmzym1k4Npk+oD1SH3/a3LOK/JpUBpWfqNySxWzCfNCUITuDG5dtuphrUJ1myeIE9bIsPiKrfqTai5WZxbhtNphYx6GEIHihyGFTI69lje/rxajdh0s0msZ0zYxyPLhYCb1CyHm9Qsd2H37Y3lugVwL9kNh8Ot8cha6fUNQ8nuXi5z9/ExsAO4zQrb/ev1yrCB7lGyQzgYDGuxq1toDN/JGvN+HyWNHKB7zEoK+PX11e12G431erGYzwmytAWU56fkMHY5JJnDRR2eZji3AwtIcrEV8Cojat/BdQ7XOwGV1e1hDjGGjXbdArm8uJZtCH5MbcctVX8A1WpqumJHwckAAAAASUVORK5CYII=");background-size: 28px 28px;animation: image-loading-rotate 1s linear infinite !important;
}.imt-image-status span {color: var(--bg-2, #fff) !important;font-size: 14px !important;line-height: 14px !important;font-weight: 500 !important;font-family: "PingFang SC", Arial, sans-serif !important;
}.imt-primary-button {display: flex;padding: 12px 80px;justify-content: center;align-items: center;gap: 8px;border-radius: 8px;background: #ea4c89;color: #fff;font-size: 16px;font-style: normal;font-weight: 700;line-height: 24px;border: none;cursor: pointer;
}.imt-retry-text {color:  #999;text-align: center;font-size: 14px;font-style: normal;font-weight: 400;line-height: 21px;cursor: pointer;
}.imt-action-container {display: flex;flex-direction: column;gap: 12px;
}.imt-modal-content-text {text-align: left;color:  #333;font-size: 16px;font-weight: 400;line-height: 24px;
}@keyframes image-loading-rotate {from {transform: rotate(360deg);}to {transform: rotate(0deg);}
}
</style></head>
<body monica-id="ofpnmcalabcbjgholdjcjblkibolbppb" monica-version="7.9.7"><div id="container"><div id="controls"><div class="control-section"><h3>动作切换</h3><button id="idle" class="active">站立</button><button id="walk">走路</button><button id="run">奔跑</button><button id="jump">跳跃</button></div><div class="control-section"><h3>动画设置</h3><div class="slider-container"><label>混合速度: <span id="blendSpeedValue">2.0</span></label><input type="range" id="blendSpeed" min="0.5" max="5.0" step="0.1" value="2.0"></div><div class="slider-container"><label>动画速度: <span id="animSpeedValue">1.0</span></label><input type="range" id="animSpeed" min="0.1" max="3.0" step="0.1" value="1.0"></div></div><div class="control-section"><button id="autoMode">自动模式</button></div></div><div id="info"><strong>骨骼动画混合演示</strong><br>点击右侧按钮切换动作,观察不同动画之间的平滑过渡。<br>• 蓝色关节:骨骼系统<br>• 绿色线条:骨骼连接<br>• 红色方块:蒙皮网格</div><canvas width="753" height="672" style="display: block; width: 753px; height: 672px;"></canvas></div><script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script><script>// 全局变量let scene, camera, renderer, character;let currentAction = 'idle';let isAutoMode = false;let autoModeTimer = 0;let blendSpeed = 2.0;let animationSpeed = 1.0;// 动画状态const animations = {idle: { weight: 1.0, speed: 1.0 },walk: { weight: 0.0, speed: 1.5 },run: { weight: 0.0, speed: 2.0 },jump: { weight: 0.0, speed: 1.2 }};// 简化的骨骼系统class SimpleSkeleton {constructor() {this.bones = [];this.joints = [];this.meshes = [];this.time = 0;this.createSkeleton();}createSkeleton() {// 创建骨骼结构(简化的人形)const boneStructure = [{ name: 'root', pos: [0, 0, 0], parent: null },{ name: 'spine', pos: [0, 1, 0], parent: 'root' },{ name: 'chest', pos: [0, 2, 0], parent: 'spine' },{ name: 'neck', pos: [0, 2.8, 0], parent: 'chest' },{ name: 'head', pos: [0, 3.5, 0], parent: 'neck' },{ name: 'leftShoulder', pos: [-0.8, 2.5, 0], parent: 'chest' },{ name: 'leftArm', pos: [-1.5, 2.5, 0], parent: 'leftShoulder' },{ name: 'leftForearm', pos: [-2.2, 2.5, 0], parent: 'leftArm' },{ name: 'rightShoulder', pos: [0.8, 2.5, 0], parent: 'chest' },{ name: 'rightArm', pos: [1.5, 2.5, 0], parent: 'rightShoulder' },{ name: 'rightForearm', pos: [2.2, 2.5, 0], parent: 'rightArm' },{ name: 'leftHip', pos: [-0.3, 0, 0], parent: 'root' },{ name: 'leftThigh', pos: [-0.3, -0.8, 0], parent: 'leftHip' },{ name: 'leftCalf', pos: [-0.3, -1.6, 0], parent: 'leftThigh' },{ name: 'leftFoot', pos: [-0.3, -2.2, 0.2], parent: 'leftCalf' },{ name: 'rightHip', pos: [0.3, 0, 0], parent: 'root' },{ name: 'rightThigh', pos: [0.3, -0.8, 0], parent: 'rightHip' },{ name: 'rightCalf', pos: [0.3, -1.6, 0], parent: 'rightThigh' },{ name: 'rightFoot', pos: [0.3, -2.2, 0.2], parent: 'rightCalf' }];// 创建骨骼对象const boneMap = {};boneStructure.forEach(bone => {const boneObject = new THREE.Object3D();boneObject.position.set(bone.pos[0], bone.pos[1], bone.pos[2]);boneObject.name = bone.name;boneMap[bone.name] = boneObject;this.bones.push(boneObject);// 创建关节可视化const jointGeometry = new THREE.SphereGeometry(0.08, 8, 8);const jointMaterial = new THREE.MeshBasicMaterial({ color: 0x4488ff });const joint = new THREE.Mesh(jointGeometry, jointMaterial);boneObject.add(joint);this.joints.push(joint);scene.add(boneObject);});// 建立父子关系boneStructure.forEach(bone => {if (bone.parent) {const parentBone = boneMap[bone.parent];const childBone = boneMap[bone.name];parentBone.add(childBone);// 创建骨骼连接线const lineGeometry = new THREE.BufferGeometry();const lineVertices = new Float32Array([0, 0, 0,childBone.position.x - parentBone.position.x,childBone.position.y - parentBone.position.y,childBone.position.z - parentBone.position.z]);lineGeometry.setAttribute('position', new THREE.BufferAttribute(lineVertices, 3));const lineMaterial = new THREE.LineBasicMaterial({ color: 0x00ff88 });const line = new THREE.Line(lineGeometry, lineMaterial);parentBone.add(line);}});this.boneMap = boneMap;// 创建简单的蒙皮网格this.createSkinMesh();}createSkinMesh() {// 身体部位的简单网格const bodyParts = [{ name: 'torso', bone: 'chest', size: [0.8, 1.2, 0.4], offset: [0, -0.3, 0] },{ name: 'head', bone: 'head', size: [0.4, 0.4, 0.4], offset: [0, 0, 0] },{ name: 'leftArm', bone: 'leftArm', size: [0.6, 0.15, 0.15], offset: [-0.3, 0, 0] },{ name: 'rightArm', bone: 'rightArm', size: [0.6, 0.15, 0.15], offset: [0.3, 0, 0] },{ name: 'leftThigh', bone: 'leftThigh', size: [0.2, 0.7, 0.2], offset: [0, -0.35, 0] },{ name: 'rightThigh', bone: 'rightThigh', size: [0.2, 0.7, 0.2], offset: [0, -0.35, 0] },{ name: 'leftCalf', bone: 'leftCalf', size: [0.15, 0.6, 0.15], offset: [0, -0.3, 0] },{ name: 'rightCalf', bone: 'rightCalf', size: [0.15, 0.6, 0.15], offset: [0, -0.3, 0] }];bodyParts.forEach(part => {const geometry = new THREE.BoxGeometry(part.size[0], part.size[1], part.size[2]);const material = new THREE.MeshPhongMaterial({ color: 0xff4444, transparent: true, opacity: 0.7 });const mesh = new THREE.Mesh(geometry, material);mesh.position.set(part.offset[0], part.offset[1], part.offset[2]);if (this.boneMap[part.bone]) {this.boneMap[part.bone].add(mesh);this.meshes.push(mesh);}});}// 动画函数animate(action, time, weight = 1.0) {const t = time * animationSpeed;switch(action) {case 'idle':this.animateIdle(t, weight);break;case 'walk':this.animateWalk(t, weight);break;case 'run':this.animateRun(t, weight);break;case 'jump':this.animateJump(t, weight);break;}}animateIdle(time, weight) {const breathe = Math.sin(time * 2) * 0.02 * weight;const sway = Math.sin(time * 0.8) * 0.01 * weight;if (this.boneMap['chest']) {this.boneMap['chest'].rotation.z = sway;this.boneMap['chest'].position.y = 2 + breathe;}if (this.boneMap['head']) {this.boneMap['head'].rotation.x = Math.sin(time * 1.5) * 0.05 * weight;}}animateWalk(time, weight) {const walkCycle = time * 3;const armSwing = Math.sin(walkCycle) * 0.3 * weight;const legSwing = Math.sin(walkCycle) * 0.4 * weight;const bodyBob = Math.abs(Math.sin(walkCycle * 2)) * 0.05 * weight;// 手臂摆动if (this.boneMap['leftArm']) {this.boneMap['leftArm'].rotation.x = armSwing;}if (this.boneMap['rightArm']) {this.boneMap['rightArm'].rotation.x = -armSwing;}// 腿部运动if (this.boneMap['leftThigh']) {this.boneMap['leftThigh'].rotation.x = legSwing;}if (this.boneMap['rightThigh']) {this.boneMap['rightThigh'].rotation.x = -legSwing;}// 身体上下摆动if (this.boneMap['root']) {this.boneMap['root'].position.y = bodyBob;}}animateRun(time, weight) {const runCycle = time * 6;const armSwing = Math.sin(runCycle) * 0.6 * weight;const legSwing = Math.sin(runCycle) * 0.8 * weight;const bodyBob = Math.abs(Math.sin(runCycle * 2)) * 0.15 * weight;const bodyLean = Math.sin(runCycle) * 0.1 * weight;// 更大的手臂摆动if (this.boneMap['leftArm']) {this.boneMap['leftArm'].rotation.x = armSwing;}if (this.boneMap['rightArm']) {this.boneMap['rightArm'].rotation.x = -armSwing;}// 更大的腿部运动if (this.boneMap['leftThigh']) {this.boneMap['leftThigh'].rotation.x = legSwing;}if (this.boneMap['rightThigh']) {this.boneMap['rightThigh'].rotation.x = -legSwing;}// 身体前倾和上下摆动if (this.boneMap['root']) {this.boneMap['root'].position.y = bodyBob;}if (this.boneMap['chest']) {this.boneMap['chest'].rotation.x = bodyLean * 0.3;}}animateJump(time, weight) {const jumpPhase = (time % 2) / 2; // 2秒一个循环let jumpY = 0;let armPose = 0;let legBend = 0;if (jumpPhase < 0.3) { // 准备阶段const t = jumpPhase / 0.3;jumpY = -0.2 * t * weight;legBend = 0.5 * t * weight;armPose = -0.5 * t * weight;} else if (jumpPhase < 0.7) { // 跳跃阶段const t = (jumpPhase - 0.3) / 0.4;const arc = Math.sin(t * Math.PI);jumpY = (arc * 1.5 - 0.2) * weight;legBend = (0.5 - arc * 0.3) * weight;armPose = (arc * 1.2 - 0.5) * weight;} else { // 着陆阶段const t = (jumpPhase - 0.7) / 0.3;jumpY = -0.1 * (1 - t) * weight;legBend = 0.2 * (1 - t) * weight;armPose = 0.7 * (1 - t) * weight;}if (this.boneMap['root']) {this.boneMap['root'].position.y = jumpY;}if (this.boneMap['leftArm']) {this.boneMap['leftArm'].rotation.x = armPose;}if (this.boneMap['rightArm']) {this.boneMap['rightArm'].rotation.x = armPose;}if (this.boneMap['leftThigh']) {this.boneMap['leftThigh'].rotation.x = -legBend;}if (this.boneMap['rightThigh']) {this.boneMap['rightThigh'].rotation.x = -legBend;}}update(deltaTime) {this.time += deltaTime;// 更新动画权重(混合)for (let action in animations) {const anim = animations[action];if (action === currentAction) {anim.weight = Math.min(1.0, anim.weight + deltaTime * blendSpeed);} else {anim.weight = Math.max(0.0, anim.weight - deltaTime * blendSpeed);}}// 清除之前的变换this.resetBones();// 应用混合动画for (let action in animations) {const anim = animations[action];if (anim.weight > 0.001) {this.animate(action, this.time * anim.speed, anim.weight);}}}resetBones() {// 重置关键骨骼的变换const resetBones = ['root', 'chest', 'head', 'leftArm', 'rightArm', 'leftThigh', 'rightThigh'];resetBones.forEach(boneName => {if (this.boneMap[boneName]) {this.boneMap[boneName].rotation.set(0, 0, 0);if (boneName === 'root') {this.boneMap[boneName].position.set(0, 0, 0);} else if (boneName === 'chest') {this.boneMap[boneName].position.set(0, 2, 0);}}});}}// 初始化场景function init() {// 创建场景scene = new THREE.Scene();scene.background = new THREE.Color(0x222244);// 创建摄像机camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);camera.position.set(5, 2, 5);camera.lookAt(0, 1, 0);// 创建渲染器renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setSize(window.innerWidth, window.innerHeight);renderer.shadowMap.enabled = true;renderer.shadowMap.type = THREE.PCFSoftShadowMap;document.getElementById('container').appendChild(renderer.domElement);// 添加灯光const ambientLight = new THREE.AmbientLight(0x404040, 0.6);scene.add(ambientLight);const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);directionalLight.position.set(5, 10, 5);directionalLight.castShadow = true;directionalLight.shadow.mapSize.width = 1024;directionalLight.shadow.mapSize.height = 1024;scene.add(directionalLight);// 添加地面const groundGeometry = new THREE.PlaneGeometry(20, 20);const groundMaterial = new THREE.MeshLambertMaterial({ color: 0x336633 });const ground = new THREE.Mesh(groundGeometry, groundMaterial);ground.rotation.x = -Math.PI / 2;ground.position.y = -2.5;ground.receiveShadow = true;scene.add(ground);// 创建角色character = new SimpleSkeleton();// 设置控件setupControls();// 开始动画循环animate();}function setupControls() {// 动作按钮const actionButtons = ['idle', 'walk', 'run', 'jump'];actionButtons.forEach(action => {const button = document.getElementById(action);button.addEventListener('click', () => {if (!isAutoMode) {setAction(action);updateActiveButton(action);}});});// 滑块控制const blendSpeedSlider = document.getElementById('blendSpeed');const blendSpeedValue = document.getElementById('blendSpeedValue');blendSpeedSlider.addEventListener('input', (e) => {blendSpeed = parseFloat(e.target.value);blendSpeedValue.textContent = blendSpeed.toFixed(1);});const animSpeedSlider = document.getElementById('animSpeed');const animSpeedValue = document.getElementById('animSpeedValue');animSpeedSlider.addEventListener('input', (e) => {animationSpeed = parseFloat(e.target.value);animSpeedValue.textContent = animationSpeed.toFixed(1);});// 自动模式const autoButton = document.getElementById('autoMode');autoButton.addEventListener('click', () => {isAutoMode = !isAutoMode;autoButton.textContent = isAutoMode ? '手动模式' : '自动模式';autoButton.classList.toggle('active');if (!isAutoMode) {updateActiveButton(currentAction);}});}function setAction(action) {currentAction = action;}function updateActiveButton(action) {document.querySelectorAll('#controls button').forEach(btn => {btn.classList.remove('active');});document.getElementById(action).classList.add('active');}let lastTime = 0;function animate() {requestAnimationFrame(animate);const currentTime = performance.now() * 0.001;const deltaTime = currentTime - lastTime;lastTime = currentTime;// 自动模式切换动作if (isAutoMode) {autoModeTimer += deltaTime;if (autoModeTimer > 3) { // 每3秒切换一次动作const actions = ['idle', 'walk', 'run', 'jump'];const currentIndex = actions.indexOf(currentAction);const nextAction = actions[(currentIndex + 1) % actions.length];setAction(nextAction);autoModeTimer = 0;}}// 更新角色动画if (character) {character.update(deltaTime);}// 摄像机环绕const time = currentTime * 0.3;camera.position.x = Math.cos(time) * 6;camera.position.z = Math.sin(time) * 6;camera.position.y = 3;camera.lookAt(0, 1, 0);renderer.render(scene, camera);}// 窗口大小调整window.addEventListener('resize', () => {const container = document.getElementById('container');const containerWidth = container.offsetWidth;const containerHeight = container.offsetHeight;camera.aspect = containerWidth / containerHeight;camera.updateProjectionMatrix();renderer.setSize(containerWidth, containerHeight);});// 启动应用init();</script><div id="monica-content-root" class="monica-widget" style="pointer-events: auto;"></div></body><div id="immersive-translate-popup" style="all: initial"></div></html>

在这里插入图片描述
需要全屏演示的同学可以通过**骨骼动画混合演示**查看。


文章转载自:

http://xW4SdLoh.nrydm.cn
http://s8K6J60P.nrydm.cn
http://ZAx7JyMN.nrydm.cn
http://hE2MASh0.nrydm.cn
http://76sVgwu3.nrydm.cn
http://1ApvUxgG.nrydm.cn
http://SxHy9KAv.nrydm.cn
http://LAPmv6AK.nrydm.cn
http://VFzAnqSr.nrydm.cn
http://4qTg085W.nrydm.cn
http://mssZiBIf.nrydm.cn
http://9xpo700X.nrydm.cn
http://eXsouMg2.nrydm.cn
http://KaXevvGv.nrydm.cn
http://IBXH6INx.nrydm.cn
http://mGf1i4zs.nrydm.cn
http://kDKVrtKC.nrydm.cn
http://VKcr6VNN.nrydm.cn
http://rAi7XoX2.nrydm.cn
http://MdDv8WJP.nrydm.cn
http://sXQoYw6q.nrydm.cn
http://kgx1vG1U.nrydm.cn
http://wRPTjZ5Z.nrydm.cn
http://axcWXzmm.nrydm.cn
http://kCqY9NvL.nrydm.cn
http://si9r2nW7.nrydm.cn
http://Kfyh9LkN.nrydm.cn
http://LkWGgek6.nrydm.cn
http://lVNnpMLh.nrydm.cn
http://JvbCdpdq.nrydm.cn
http://www.dtcms.com/a/373583.html

相关文章:

  • 网络工程师软考:网络自动化与可编程网络深度解析
  • 天工开物:耐达讯自动化RS232转ProfiBus网关连接变频器的“重生“术
  • WPF资源字典合并报错
  • DevExpress WPF 中文教程:如何将 WPF 数据网格绑定虚拟数据源?
  • TypeORM 入门教程:@ManyToOne 与 @OneToMany 关系详解
  • 开关电源基础知识
  • C++-RAII
  • nginx反向代理,负载均衡,tomcat的数据流向图篇解析
  • 独立站SEO优化:如何应用移动代理IP提升关键词排名?
  • Linux初始——cgdb
  • 【T2I】Discriminative Probing and Tuning for Text-to-Image Generation
  • Vue: ref、reactive、shallowRef、shallowReactive
  • HarmonyOS 应用开发深度解析:基于 ArkTS 的跨组件状态管理最佳实践
  • 鸿蒙系统下的智能设备故障检测实战:从监控到自愈的全流程实现
  • windows11备份系统盘
  • 小迪web自用笔记31
  • 【前端埋点】纯前端实现 A/B Test
  • Vue3+Cesim ^1.122.0 Home按钮位置自定义;时间轴UTC时间转化为北京时间
  • 第五十五天(SQL注入增删改查HTTP头UAXFFRefererCookie无回显报错复盘)
  • leetcode 1317 将整数转换为两个无零整数的和
  • 高斯数据库(GaussDB)常用命令
  • git 配置本地添加ssh
  • ⸢ 肆 ⸥ ⤳ 默认安全建设方案:c-1.增量风险管控
  • 从零开始学大模型之大模型应用
  • 事务设置和消息分发
  • 人工智能-python-深度学习-神经网络-GoogLeNet
  • 告别进度拖延:19款项目进度管理软件深度测评
  • lesson56:CSS进阶指南:Flex布局、变换渐变与动画实战全解析
  • 【高等数学】第十一章 曲线积分与曲面积分——第四节 对面积的曲面积分
  • 精通Octokit:GitHub API开发全攻略