使用 Three.js 创建一个 3D 人形机器人仿真系统

news2024/12/26 19:37:01

引言

在这篇文章中,我们将探讨如何使用 Three.js 创建一个简单但有趣的 3D 人形机器人仿真系统。这个机器人可以通过键盘控制进行行走和转向,并具有基本的动画效果。

在这里插入图片描述

技术栈

  • HTML5
  • Three.js
  • JavaScript

实现步骤

1. 基础设置

首先,我们需要创建基本的 HTML 结构并引入 Three.js 库:

<!DOCTYPE html>
<html>
<head>
    <title>3D Robot Simulation</title>
    <style>
        body { 
            margin: 0; 
            overflow: hidden;
        }
        canvas { 
            display: block; 
        }
        #info {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            font-family: Arial;
            font-size: 14px;
            background: rgba(0,0,0,0.5);
            padding: 10px;
        }
    </style>
</head>
<body>
    <div id="info">
        使用方向键控制机器人:<br>
        ↑ - 向前移动<br>
        ← → - 左右转向
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
</body>
</html>

2. 场景初始化

接下来,我们需要初始化 Three.js 的基本组件:

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB); // 天空蓝色背景

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

3. 创建机器人类

创建一个 Robot 类来管理机器人的所有组件和动作:

class Robot {
    constructor() {
        this.body = new THREE.Group();
        
        // 创建躯干
        const torsoGeometry = new THREE.BoxGeometry(2, 3, 1);
        const torsoMaterial = new THREE.MeshPhongMaterial({color: 0x999999});
        this.torso = new THREE.Mesh(torsoGeometry, torsoMaterial);
        this.torso.castShadow = true;
        
        // 创建头部
        const headGeometry = new THREE.SphereGeometry(0.5);
        const headMaterial = new THREE.MeshPhongMaterial({color: 0xcccccc});
        this.head = new THREE.Mesh(headGeometry, headMaterial);
        this.head.position.y = 2;
        this.head.castShadow = true;
        
        // ... 其他部件的创建代码 ...
    }
    
    // 创建四肢
    createLimb(width, height) {
        const geometry = new THREE.BoxGeometry(width, height, width);
        const material = new THREE.MeshPhongMaterial({color: 0x999999});
        const limb = new THREE.Mesh(geometry, material);
        limb.castShadow = true;
        return limb;
    }
    
    // 行走动画
    walk() {
        const legRotation = Math.sin(Date.now() * 0.005) * 0.5;
        this.leftLeg.rotation.x = legRotation;
        this.rightLeg.rotation.x = -legRotation;
        
        const armRotation = Math.sin(Date.now() * 0.005) * 0.25;
        this.leftArm.rotation.x = -armRotation;
        this.rightArm.rotation.x = armRotation;
    }
    
    // 转向和移动方法
    turn(angle) {
        this.body.rotation.y += angle;
    }
    
    moveForward(speed) {
        this.body.position.x += Math.sin(this.body.rotation.y) * speed;
        this.body.position.z += Math.cos(this.body.rotation.y) * speed;
    }
}

4. 添加环境元素

创建地面和光照系统:

// 创建地面
const groundGeometry = new THREE.PlaneGeometry(100, 100);
const groundMaterial = new THREE.MeshPhongMaterial({ 
    color: 0x808080,
    side: THREE.DoubleSide
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.position.y = -2.5;
ground.receiveShadow = true;
scene.add(ground);

// 添加光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);
directionalLight.castShadow = true;
scene.add(directionalLight);

const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);

5. 实现控制系统

添加键盘控制和动画循环:

const keyStates = {};

document.addEventListener('keydown', (e) => {
    keyStates[e.key] = true;
});

document.addEventListener('keyup', (e) => {
    keyStates[e.key] = false;
});

function animate() {
    requestAnimationFrame(animate);
    
    if(keyStates['ArrowUp']) {
        robot.walk();
        robot.moveForward(0.1);
    }
    if(keyStates['ArrowLeft']) {
        robot.turn(0.05);
    }
    if(keyStates['ArrowRight']) {
        robot.turn(-0.05);
    }
    
    camera.position.x = robot.body.position.x;
    camera.position.z = robot.body.position.z + 10;
    camera.lookAt(robot.body.position);
    
    renderer.render(scene, camera);
}

animate();

主要特性

  1. 3D 人形机器人模型
  2. 基本的行走动画
  3. 键盘控制系统
  4. 相机跟随
  5. 阴影效果
  6. 响应式设计

控制方法

  • ↑ 向前移动
  • ← 向左转
  • → 向右转

可能的改进方向

  1. 添加更多动作(如后退、跳跃)
  2. 改进机器人模型细节
  3. 添加碰撞检测
  4. 添加物理引擎
  5. 实现更复杂的动画效果
  6. 添加声音效果
  7. 增加更多交互控制选项
  8. 优化性能

结论

通过这个项目,我们展示了如何使用 Three.js 创建一个基本的 3D 人形机器人仿真系统。虽然这是一个相对简单的实现,但它为更复杂的 3D 网页应用提供了良好的起点。

完整代码

<!DOCTYPE html>
<html>
<head>
    <title>3D Robot Simulation</title>
    <style>
        body { 
            margin: 0; 
            overflow: hidden;
        }
        canvas { 
            display: block; 
        }
        #info {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            font-family: Arial;
            font-size: 14px;
            background: rgba(0,0,0,0.5);
            padding: 10px;
        }
    </style>
</head>
<body>
    <div id="info">
        使用方向键控制机器人:<br>- 向前移动<br>
        ← → - 左右转向
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
        // 初始化场景、相机和渲染器
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x87CEEB); // 天空蓝色背景

        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true;
        document.body.appendChild(renderer.domElement);

        // 创建机器人类
        class Robot {
            constructor() {
                // 机器人主体
                this.body = new THREE.Group();
                
                // 躯干
                const torsoGeometry = new THREE.BoxGeometry(2, 3, 1);
                const torsoMaterial = new THREE.MeshPhongMaterial({color: 0x999999});
                this.torso = new THREE.Mesh(torsoGeometry, torsoMaterial);
                this.torso.castShadow = true;
                
                // 头部
                const headGeometry = new THREE.SphereGeometry(0.5);
                const headMaterial = new THREE.MeshPhongMaterial({color: 0xcccccc});
                this.head = new THREE.Mesh(headGeometry, headMaterial);
                this.head.position.y = 2;
                this.head.castShadow = true;
                
                // 眼睛
                const eyeGeometry = new THREE.SphereGeometry(0.1);
                const eyeMaterial = new THREE.MeshPhongMaterial({color: 0x000000});
                this.leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
                this.rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
                this.leftEye.position.set(-0.2, 2, 0.4);
                this.rightEye.position.set(0.2, 2, 0.4);
                
                // 手臂
                this.leftArm = this.createLimb(0.3, 2);
                this.leftArm.position.set(-1.2, 1, 0);
                this.rightArm = this.createLimb(0.3, 2);
                this.rightArm.position.set(1.2, 1, 0);
                
                // 腿部
                this.leftLeg = this.createLimb(0.4, 2);
                this.leftLeg.position.set(-0.6, -1.5, 0);
                this.rightLeg = this.createLimb(0.4, 2);
                this.rightLeg.position.set(0.6, -1.5, 0);
                
                // 组装机器人
                this.body.add(this.torso);
                this.body.add(this.head);
                this.body.add(this.leftEye);
                this.body.add(this.rightEye);
                this.body.add(this.leftArm);
                this.body.add(this.rightArm);
                this.body.add(this.leftLeg);
                this.body.add(this.rightLeg);
            }
            
            createLimb(width, height) {
                const geometry = new THREE.BoxGeometry(width, height, width);
                const material = new THREE.MeshPhongMaterial({color: 0x999999});
                const limb = new THREE.Mesh(geometry, material);
                limb.castShadow = true;
                return limb;
            }
            
            walk() {
                // 腿部摆动
                const legRotation = Math.sin(Date.now() * 0.005) * 0.5;
                this.leftLeg.rotation.x = legRotation;
                this.rightLeg.rotation.x = -legRotation;
                
                // 手臂摆动
                const armRotation = Math.sin(Date.now() * 0.005) * 0.25;
                this.leftArm.rotation.x = -armRotation;
                this.rightArm.rotation.x = armRotation;
            }
            
            turn(angle) {
                this.body.rotation.y += angle;
            }
            
            moveForward(speed) {
                this.body.position.x += Math.sin(this.body.rotation.y) * speed;
                this.body.position.z += Math.cos(this.body.rotation.y) * speed;
            }
        }

        // 创建地面
        const groundGeometry = new THREE.PlaneGeometry(100, 100);
        const groundMaterial = new THREE.MeshPhongMaterial({ 
            color: 0x808080,
            side: THREE.DoubleSide
        });
        const ground = new THREE.Mesh(groundGeometry, groundMaterial);
        ground.rotation.x = -Math.PI / 2;
        ground.position.y = -2.5;
        ground.receiveShadow = true;
        scene.add(ground);

        // 创建机器人实例
        const robot = new Robot();
        scene.add(robot.body);

        // 添加光源
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(5, 10, 5);
        directionalLight.castShadow = true;
        directionalLight.shadow.camera.near = 0.1;
        directionalLight.shadow.camera.far = 100;
        directionalLight.shadow.camera.left = -50;
        directionalLight.shadow.camera.right = 50;
        directionalLight.shadow.camera.top = 50;
        directionalLight.shadow.camera.bottom = -50;
        scene.add(directionalLight);

        const ambientLight = new THREE.AmbientLight(0x404040);
        scene.add(ambientLight);

        // 设置相机位置
        camera.position.set(0, 5, 10);
        camera.lookAt(robot.body.position);

        // 键盘状态
        const keyStates = {};

        // 键盘事件监听
        document.addEventListener('keydown', (e) => {
            keyStates[e.key] = true;
        });

        document.addEventListener('keyup', (e) => {
            keyStates[e.key] = false;
        });

        // 窗口大小调整
        window.addEventListener('resize', onWindowResize, false);

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            
            // 更新机器人动作
            if(keyStates['ArrowUp']) {
                robot.walk();
                robot.moveForward(0.1);
            }
            if(keyStates['ArrowLeft']) {
                robot.turn(0.05);
            }
            if(keyStates['ArrowRight']) {
                robot.turn(-0.05);
            }
            
            // 相机跟随
            camera.position.x = robot.body.position.x;
            camera.position.z = robot.body.position.z + 10;
            camera.lookAt(robot.body.position);
            
            renderer.render(scene, camera);
        }

        animate();
    </script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2265988.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android unitTest 单元测试用例编写(初始)

文章目录 了解测试相关库导入依赖库新建测试文件示例执行查看结果网页结果其他 本片讲解的重点是unitTest&#xff0c;而不是androidTest哦 了解测试相关库 androidx.compose.ui:ui-test-junit4: 用于Compose UI的JUnit 4测试库。 它提供了测试Compose UI组件的工具和API。 and…

【蓝桥杯——物联网设计与开发】拓展模块3 - 温度传感器模块

目录 一、温度传感器模块 &#xff08;1&#xff09;资源介绍 &#x1f505;原理图 &#x1f505;STS30-DIS-B &#x1f319;引脚分配 &#x1f319;通信 &#x1f319;时钟拉伸&#xff08;Clock Stretching&#xff09; &#x1f319;单次触发模式 &#x1f319;温度数据转…

如何在任何地方随时使用本地Jupyter Notebook无需公网IP

文章目录 1.前言2.Jupyter Notebook的安装2.1 Jupyter Notebook下载安装2.2 Jupyter Notebook的配置2.3 Cpolar下载安装 3.Cpolar端口设置3.1 Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 今天就来给大家安利一套神器组合&#xff1a;通过Windows系统本地部…

长沙景区数据分析项目实现

一、设计题目 长沙景区数据分析项目 二、设计目的 通过本项目让学生独立完成数据统计、数据可视化、数据分析的过程&#xff0c;并提高学生解决问题的能力。 三、设计要求 读取‘长沙景区信息.xlsx’文件&#xff08;读取Excel文件的方法为pandas.read_excel()&#xff0c…

Kafka可视化工具 Offset Explorer (以前叫Kafka Tool)

数据的存储是基于 主题&#xff08;Topic&#xff09; 和 分区&#xff08;Partition&#xff09; 的 Kafka是一个高可靠性的分布式消息系统&#xff0c;广泛应用于大规模数据处理和实时, 为了更方便地管理和监控Kafka集群&#xff0c;开发人员和运维人员经常需要使用可视化工具…

PHP后执行php.exe -v命令报错并给出解决方案

文章目录 一、执行php.exe -v命令报错解决方案 一、执行php.exe -v命令报错 -PHP Warning: ‘C:\windows\SYSTEM32\VCRUNTIME140.dll’ 14.38 is not compatible with this PHP build linked with 14.41 in Unknown on line 0 解决方案 当使用PHP8.4.1时遇到VCRUNTIME140.dll…

详解MySQL在Windows上的安装

目录 查看电脑上是否安装了MySQL 下载安装MySQL 打开MySQL官网&#xff0c;找到DOWNLOADS 然后往下翻&#xff0c;找到MySQL Community(GPL) Downloads>> 然后找到MySQL Community Server 然后下载&#xff0c;选择No thanks,just start my download. 然后双击进行…

Excel粘贴复制不完整的原因以及解决方法

在数据处理和分析的过程中&#xff0c;Excel无疑是不可或缺的工具。然而&#xff0c;在使用Excel进行复制粘贴操作时&#xff0c;有时会遇到粘贴不完整的情况&#xff0c;这可能会让人感到困惑和烦恼。本文将深入探讨Excel粘贴复制不完整的原因、提供解决方案&#xff0c;并给出…

嵌入式轻量级开源操作系统:HeliOS的使用

嵌入式轻量级开源操作系统:HeliOS的使用 &#x1f4cd;项目地址&#xff1a;https://github.com/heliosproj/HeliOS HeliOS项目是一个社区交付的开源项目&#xff0c;用于构建和维护HeliOS嵌入式操作系统&#xff08;OS&#xff09;。HeliOS是一个功能齐全的操作系统&#xff0…

Linux复习3——管理文件系统2

修改文件权限命令 chmod 功能&#xff1a; chmod 命令主要用于修改文件或者目录的权限 只有文件所有者和超级用户可以修改文件或目录的权限 (1)使用数字表示法修改权限 所谓数字表示法是指将读取(r)、写入(w)和执行(x)分别以4、2、1来表示&#xff0c;没有授予的部分就表示…

ECharts散点图-气泡图,附视频讲解与代码下载

引言&#xff1a; ECharts散点图是一种常见的数据可视化图表类型&#xff0c;它通过在二维坐标系或其它坐标系中绘制散乱的点来展示数据之间的关系。本文将详细介绍如何使用ECharts库实现一个散点图&#xff0c;包括图表效果预览、视频讲解及代码下载&#xff0c;让你轻松掌握…

嵌入式驱动开发详解21(网络驱动开发)

文章目录 前言以太网框架ENET 接口简介MAC接口MII \ RMII 接口MDIO 接口RJ45 接口 PHY芯片以太网驱动驱动挂载wifi模块挂载后续 前言 linux驱动主要是字符设备驱动、块设备驱动还有网络设备驱动、字符设备驱动在本专栏前面已经详细将解了&#xff0c;网络设备驱动本文会做简要…

论文解读 | EMNLP2024 一种用于大语言模型版本更新的学习率路径切换训练范式

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 作者简介 王志豪&#xff0c;厦门大学博士生 刘诗雨&#xff0c;厦门大学硕士生 内容简介 新数据的不断涌现使版本更新成为大型语言模型&#xff08;LLMs&#xff…

FFmpeg 的常用API

FFmpeg 的常用API 附录&#xff1a;FFmpeg库介绍 库介绍libavcodec音视频编解码核心库编码 (avcodec_send_frame, avcodec_receive_packet)。解码 (avcodec_send_packet, avcodec_receive_frame)。libavformat提供了音视频流的解析和封装功能&#xff0c;多种多媒体封装格式&…

trap命令

信号 linux信号是由一个整数构成的异步消息&#xff0c;可以由某个进程发给其他的进程&#xff0c;也可以在用户按下特定键发生某种异常事件时&#xff0c;由系统发给某个进程 信号列表 kill -l trap -l 在使用信号名时&#xff0c;需要省略SIG前缀 trap trap命令用于指定…

Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码 【AI辅助开发系列】

&#x1f380;&#x1f380;&#x1f380;【AI辅助编程系列】&#x1f380;&#x1f380;&#x1f380; Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码Visual Studio 安装和管理 GitHub CopilotVisual Studio 使用 GitHub Copilot 扩展Visual Studio 使用 GitHu…

Llama 3 模型系列解析(一)

目录 1. 引言 1.1 Llama 3 的简介 1.2 性能评估 1.3 开源计划 1.4 多模态扩展 ps 1. 缩放法则 2. 超额训练&#xff08;Over-training&#xff09; 3. 计算训练预算 4. 如何逐步估算和确定最优模型&#xff1f; 2. 概述 2.1 Llama 3 语言模型开发两个主要阶段 2.2…

【多时段】含sop的配电网重构【含分布式电源】【已更新视频讲解】

1 主要内容 之前分享了很多配电网重构的程序&#xff0c;每个程序针对场景限定性比较大&#xff0c;程序初学者修改起来难度较大&#xff0c;本次分享一个基础程序&#xff0c;针对含sop的配电网重构模型&#xff0c;含风电和光伏&#xff0c;优化了33节点网络电压合理性&…

使用 Elastic AI Assistant 简化威胁情报报告

作者&#xff1a;来自 Tommy Bumford 了解 SRE 不断扩展的角色以及所需的新技能&#xff1a;成本管理和 AI。 通过 AI 驱动的报告为分析师提供支持 在不断发展的网络安全领域&#xff0c;威胁分析师不断被新的威胁情报 (threat intelligence - TI) 数据淹没。挑战不仅在于理解…

64.基于SpringBoot + Vue实现的前后端分离-新闻资讯系统(项目 + 论文)

项目介绍 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;文章信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广…