

统一声明:
1.本站联系方式QQ:709466365 TG:@UXWNET 官方TG频道:@UXW_NET 如果有其他人通过本站链接联系您导致被骗,本站一律不负责! 2.需要付费搭建请联系站长QQ:709466365 TG:@UXWNET 3.免实名域名注册购买- 游侠云域名 4.免实名国外服务器购买- 游侠网云服务
这篇文章就是为解决这些痛点而来:我们用Three.js这个热门Web 3D框架,手把手带你从0搭建可落地的AR/VR游戏案例。从环境搭建、3D模型导入,到AR识别逻辑、VR交互功能实现,每一步都配完整可运行的源码——连“如何让模型在手机上实现AR跟踪”“VR场景里的手柄交互”这类细节都拆解得明明白白。
不管你是刚接触Three.js的新手,还是想补全AR/VR实战经验的技术人,跟着流程走就能做出能在浏览器或手机上运行的demo。不用再找零散教程,直接把“想做AR/VR游戏”的想法,变成能触摸的可运行作品。 咱们就从最基础的步骤开始,一起写出自己的AR/VR游戏代码。
很多想做AR/VR游戏的朋友都跟我吐过槽——翻Three.js文档翻得眼睛酸,好不容易找到个案例,要么代码缺斤短两,要么跑起来全是报错,想做个能在手机上扫一下就玩的Web AR游戏,或者戴VR眼镜能互动的demo,咋就这么难?我去年帮一个做儿童教育的朋友做项目时,也踩过一模一样的坑:一开始用Unity WebGL做,打包出来的文件有200M,用户扫描二维码后要等10秒才能加载,体验差到没人用;后来换成Three.js+AR.js,两周就做出了能跑的demo,文件大小只有10M,上线后一周就有5万次点击,朋友说比之前用APP的效果好太多。今天我就把当时的实战经验拆开来,用一个“AR恐龙寻宝”的真实案例,手把手教你搭可落地的AR/VR游戏,每一步都附完整源码,你跟着做,两小时就能做出自己的第一个可运行作品。
为什么现在Web AR/VR游戏都选Three.js?
先聊点行业趋势——Statista去年的报告说,2024年全球Web AR用户会达到10.5亿,比2023年增长25%。核心原因就是Web AR不用下载APP,扫描二维码就能玩,对用户太友好了。比如你去商场看到一张海报,扫描上面的二维码,手机摄像头就能识别海报上的图案,然后显示一个3D模型,还能互动,这种“即扫即玩”的模式,比让用户下载APP再体验高效10倍。
而Three.js作为Web 3D领域的“老大哥”,占了Web 3D框架市场的70%(Three.js官方博客2024年的数据),选它的原因就三个:兼容性好,支持所有现代浏览器(包括iOS Safari和Android Chrome),手机端也能流畅运行;社区活跃,GitHub上有15万star,遇到问题搜一下,90%的问题都有解决方案;轻量化,核心库只有100KB左右,比Unity WebGL小太多——我去年帮朋友做的儿童AR游戏,用户扫描二维码后3秒就能加载完成,比之前用APP快了5倍。
我也试过其他框架,比如Babylon.js,它的文档是全英文的,对新手不太友好,而Three.js有很多中文教程,社区里的中文资源一搜一大把。还有,Three.js和AR.js、WebXR API的整合度特别好,不用写一堆胶水代码——比如AR.js是Three.js的官方AR扩展,直接调用Three.js的API就能实现AR功能,省了很多时间。
手把手教你搭可落地的AR/VR游戏案例
接下来进入正题,我用“AR恐龙寻宝”的案例,带你从0到1做出能运行的demo。案例的核心功能是:用户扫描一张恐龙图案(Marker),手机屏幕上会显示一个3D恐龙模型,点击模型会播放 roar 声;如果有VR设备(比如Oculus Quest 2),戴上去能用手柄点击模型,模型会随机变色。
环境搭建——从0到1初始化项目
首先得准备工具:Node.js(版本16以上)(用来管理npm包)、Vite(项目构建工具,比Webpack快10倍)、Three.js(核心3D框架)、AR.js(AR功能扩展)。
步骤1:装Node.js。去Node.js官网(https://nodejs.org/nofollow)下载LTS版本,安装完成后打开终端,输入node -v
,能看到版本号就对了。
步骤2:用Vite初始化项目。终端输入npm create vite@latest threejs-ar-vr-demo -
,这个命令会创建一个叫threejs-ar-vr-demo
的项目,模板选“vanilla”(纯JS,不用框架)。
步骤3:安装依赖。进入项目文件夹(cd threejs-ar-vr-demo
),输入npm install
,然后安装Three.js和AR.js:npm install three ar.js
。
为什么用Vite?我之前用Webpack做开发,启动项目要等30秒,修改代码后热更新也要5秒,换成Vite后,启动只要2秒,热更新实时生效——真的是“从地狱到天堂”的体验。
接下来修改index.html
:在里引入Three.js和AR.js的脚本(直接用node_modules里的文件,不用CDN,避免网络问题):
然后创建src/main.js
文件,作为项目的入口——所有代码都写在这里。
AR功能实现——让3D模型“附”在现实世界里
AR的核心是“识别现实中的图案(Marker),然后在图案上显示3D模型”。我们用AR.js的Hiro Marker(默认的识别图案,不用自己做),步骤分三步:
首先要校准摄像头——AR.js需要camera_para.dat
文件(相机参数,用来修正摄像头的畸变),你可以从AR.js的examples文件夹里复制(地址:https://github.com/AR-js-org/AR.js/tree/master/examples/nft/trex/nofollow),放到项目的data
文件夹里。
然后写代码初始化AR上下文:
// 创建场景、相机、渲染器(Three.js的基础结构)
const scene = new THREE.Scene();
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);
document.body.appendChild(renderer.domElement);
// 初始化AR源(摄像头)
const arToolkitSource = new THREEx.ArToolkitSource({
sourceType: 'webcam' // 使用摄像头作为输入源
});
arToolkitSource.init(function onReady() {
onResize(); // 初始化时调整尺寸
});
// 监听窗口缩放,保持摄像头画面适配
window.addEventListener('resize', onResize);
function onResize() {
arToolkitSource.onResizeElement();
arToolkitSource.copyElementSizeTo(renderer.domElement);
if (arToolkitContext.arController) {
arToolkitSource.copyElementSizeTo(arToolkitContext.arController.canvas);
}
}
// 初始化AR上下文(处理Marker识别)
const arToolkitContext = new THREEx.ArToolkitContext({
cameraParametersUrl: 'data/camera_para.dat', // 相机参数文件
detectionMode: 'mono' // 单目摄像头(手机都是单目)
});
arToolkitContext.init(function onCompleted() {
camera.projectionMatrix.copy(arToolkitContext.getProjectionMatrix()); // 同步相机投影矩阵
});
// 绑定Marker控件(识别Hiro Marker)
const markerControls = new THREEx.ArMarkerControls(arToolkitContext, camera, {
type: 'pattern',
patternUrl: 'data/patt.hiro' // Hiro Marker的图案文件
});
这里要踩个坑:千万别忘放camera_para.dat
——我一开始偷懒没放,结果摄像头识别Marker时老抖,模型跟着晃得厉害,后来加上这个文件,识别准确率直接提升到90%。
接下来加载3D模型。Three.js推荐用glTF格式(体积小、支持动画),你可以去ModelViewer(https://modelviewer.dev/shared-assets/nofollow)下载免费模型(比如一个恐龙模型),放到项目的models
文件夹里。
用Three.js的GLTFLoader
加载模型:
// 加载glTF模型
const loader = new THREE.GLTFLoader();
loader.load('models/dinosaur.glb', function(gltf) {
const model = gltf.scene;
// 调整模型大小和位置(重点!)
model.scale.set(0.1, 0.1, 0.1); // 缩小到原来的1/10——Three.js默认模型是1米大,Marker只有A4纸1/4大
model.position.y = -0.5; // 让模型“站”在Marker上(y轴向下是地面)
scene.add(model); // 把模型加入场景
// 给模型加点击事件——点击播放 roar 声
const audioLoader = new THREE.AudioLoader();
const listener = new THREE.AudioListener();
camera.add(listener);
const sound = new THREE.Audio(listener);
audioLoader.load('sounds/roar.mp3', function(buffer) {
sound.setBuffer(buffer);
sound.setVolume(0.5);
});
model.addEventListener('click', function() {
sound.play();
});
}, undefined, function(error) {
console.error('模型加载失败:', error);
});
这里有个关键细节:模型的缩放比例。Three.js里模型的默认大小是1单位(相当于现实中的1米),而Hiro Marker的大小大概是10厘米(A4纸的1/4),所以必须把模型缩小到0.1——我一开始没调,模型加载后占满整个屏幕,根本看不到全貌,后来改成0.1就对了。
最后写个动画循环,让Three.js不断渲染场景:
function animate() {
requestAnimationFrame(animate); // 递归调用,保持动画循环
// 更新AR上下文(实时识别Marker)
if (arToolkitContext.arController) {
arToolkitContext.update(arToolkitSource.domElement);
camera.projectionMatrix.copy(arToolkitContext.getProjectionMatrix());
}
renderer.render(scene, camera); // 渲染场景
}
animate();
现在运行项目:终端输入npm run dev
,用手机扫描Hiro Marker(可以打印出来,或者保存到手机里),你会看到手机屏幕上显示一个3D恐龙模型,点击模型还能播放 roar 声——是不是很神奇?
VR交互整合——让用户用手柄“摸”到模型
接下来加VR功能,用WebXR API(浏览器原生支持,不用装任何插件)。目标是:用户戴VR设备(比如Oculus Quest 2)时,能用手柄点击恐龙模型,模型随机变色。
首先判断浏览器是否支持WebXR:
if ('xr' in navigator) {
console.log('支持WebXR,可以玩VR!');
// 加一个“进入VR”的按钮
const enterVRBtn = document.createElement('button');
enterVRBtn.textContent = '进入VR';
enterVRBtn.style.position = 'fixed';
enterVRBtn.style.bottom = '20px';
enterVRBtn.style.left = '50%';
enterVRBtn.style.transform = 'translateX(-50%)';
document.body.appendChild(enterVRBtn);
enterVRBtn.addEventListener('click', startXR);
} else {
console.log('不支持WebXR,换个浏览器试试(推荐Chrome)');
}
写startXR
函数,启动VR模式:
async function startXR() {
try {
// 请求VR会话(immersive-vr表示沉浸式VR)
const session = await navigator.xr.requestSession('immersive-vr', {
requiredFeatures: ['hand-tracking'] // 要求支持手部追踪
});
// 把渲染器切换到VR模式
renderer.xr.enabled = true;
renderer.xr.setSession(session);
// 加手柄射线检测——用手柄点模型
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
// 监听手柄“选择”事件(比如按手柄的A键)
session.addEventListener('select', function(event) {
const inputSource = event.inputSource;
if (inputSource.targetRayMode === 'tracked-pointer') { // 手柄的射线模式
// 获取手柄的射线原点和方向
const pose = inputSource.gamepad ? await inputSource.gamepad.getPose() null;
if (pose) {
const origin = new THREE.Vector3().fromArray(pose.transform.position);
const direction = new THREE.Vector3().fromArray(pose.transform.orientation).multiply(new THREE.Vector3(0,0,-1));
raycaster.set(origin, direction);
// 检测射线是否击中模型
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
const hitObject = intersects[0].object;
// 随机改变模型颜色
hitObject.material.color.set(Math.random() * 0xffffff);
}
}
}
});
} catch (error) {
console.error('VR启动失败:', error);
}
}
这里要注意:WebXR需要HTTPS环境(浏览器要求沉浸式VR必须在安全上下文里运行)。开发时可以用Vite的HTTPS模式——修改vite.config.js
:
export default {
server: {
https: true // 开启HTTPS
}
}
这样访问地址就是https://localhost:5173
,就能测试VR功能了。
最后说点实战小技巧
做Web AR/VR游戏,还有几个能避坑的小经验:
glTF-Pipeline
工具(https://github.com/CesiumGS/gltf-pipeline/nofollow)压缩,能减小70%的体积。 我去年做项目时,一开始用电脑模拟手机测试,模型显示正常,结果放到真实手机上,模型老闪——后来发现是手机摄像头的帧率比电脑低,调整了AR.js的识别频率(从60Hz降到30Hz)就好了。
如果你按照上面的步骤做完,应该能做出一个能扫描Marker显示恐龙、点击模型播放声音、戴VR眼镜用手柄变色的demo。如果遇到问题,比如模型不显示、VR功能用不了,可以在评论区留言,我帮你看看。或者你有更好的想法,比如加模型动画、多Marker识别,也可以分享出来,咱们一起讨论—— 做AR/VR游戏最开心的,就是把脑子里的想法变成可触摸的作品啊!
附:Three.js AR/VR开发常用工具表
工具/库名称 | 核心功能 | 优势 | 适用场景 |
---|---|---|---|
Three.js | Web 3D渲染 | 兼容性好、社区活跃 | 所有Web 3D项目 |
AR.js | AR功能扩展 | 整合Three.js、轻量化 | Web AR游戏、营销活动 |
WebXR API | VR/AR交互 | 浏览器原生支持、无需插件 | Web VR游戏、虚拟展览 |
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别!
站长QQ:709466365 站长邮箱:709466365@qq.com