大家好, 在上一篇中说到了Three.js 系列的目标以及宝可梦游戏,那么今天就来通过Three.js 来谈谈关于游戏中的视角跟随问题。
相信我的读者都或多或少玩一些游戏,例如王者荣耀、绝地求生、宝可梦、塞尔达、原神之类的游戏。那么你知道他们分别是什么视角的游戏么?你知道第一人称视角和第三人称视角的差异么?通过代码我们怎么能实现这样的效果呢?
如果你对以上问题好奇,并且不能完全回答。那么请跟随着我一起往下看吧。
首先我们先来看看第一人称视角、第三人称视角的概念。其实对于我们而言 第一人称 和 第三人称,是非常熟悉的,第一人称就是以自己的口吻讲述一件事,例如自传都是以这种形式抒写,第三人称则是以旁观者,例如很多小说,都是以他(xxx)来展开式将的,观众则是以上帝视角看着这整个故事。对应的第一人称视角、第三人称视角也是相同的概念,只不过是视觉上面。
那么他们各自有上面区别呢?
第一人称视角的有点是可以给玩家带来最大限度的沉浸感,从第一人称视角“我”去观察场景和画面,可以让玩家更加细致地感受到其中的细节,最常见的就是类似绝地求生、极品飞车之类的。
而第一人称视角也有他的局限性。玩家的视野受限,无法看到更广阔的的视野。另一个就是第一人称视角会给玩家带来“3D眩晕感”。当反应速度更不上镜头速度的时候会造成眩晕感。
那么第三人称视角呢?他的优势就是自由,视野开阔,人物移动和视角是分开的,一个用来操作人物前进方向,另一个则是用来操控视野方向。
它的劣势就是无法很好的聚焦局部,容易错过细节。
但是总的来说,目前大多数游戏都提供了两种视角的切换来满足不同的情形。例如绝对求生中平时走路用第三人称视角跟随移动,开枪的时候一般用第一人称视角。
好了,到目前为主我们已经知道了第一人称视角、第三人称视角各自概念、区别。那么我们接下来以第三人称视角为例,展开分析我们该如何实现这样的一个效果呢?(第三人称的编写好后,稍加修改就可以变成第一人称,因此以更加复杂的第三人称为例)
把大象放入冰箱需要几步?三步!打开冰箱,把大象放进冰箱,关上冰箱。显然如果真的要把大象放进冰箱是很难的事情,但是从宏观角度来看,就是三个步骤。
因此我们也将实现第三人称视角这个功能分成三步:
以下的步骤拆分不会包含任何代码,请放心使用:
1.人物如何运动
我们都知道在物理真实的世界中,我们运动起来是靠我们双腿,迈开就动起来了。那这个过程从更宏观的角度来看是怎么样的呢?其实如果从地球外,从一个更远的角度来看,我们做运动更像是一个个平移变化。
相同地,我们在计算机中来表示运动也就是运用了平移变化。平移变化详细大家以前都比较熟悉,如果现在不熟悉了呢,也没有什么关系,先看下面的坐标轴。(小方块的边长是1)
小方块从A1位置移动到位置A2就是平移变化,如果用数学表达式来表示的话就是
上面是什么意思呢?就是说我们让小方块中所有的小点的 x 值都加2,而 y 的值不变。我们随意取一些值来验证一下。
例如A1位置小方块,左下角是 (0,0), 通过以上变化,就变成了 (2, 0),我们来A2中看小方块新的位置就是 (2, 0);再用右上角的 (1,1) 代入,发现就变成了(3,1),和我们真实移动到的位置也是一样的。所以上面的式子没有什么问题。
但是后来呢,大家觉得像上面那样的式子用来表示稍微有点不够通用。至于这里为什么说不够通用,在后面的系列文章中会详细讲解,因为还涉及到了其他变化,例如旋转、缩放,他们都可以用一个矩阵来进行描述,因此如果平移也能够用矩阵的方式来表达,那么整个问题就变得简单了,也就是说:
运动变化 = 矩阵变化
我们来看看把最开始的式子变成矩阵是什么样子的:
可以简单讲解一下右边这个矩阵是怎么来的
左上角的这个部分称为单位矩阵,后面的 2 0 则就是我们需要的平移变化,至于为什么从2维变成了3维,则是因为引入了一个齐次矩阵的概念。同样的原理,类比到 3维,我们就需要用到4维矩阵。
所以说,我们通过一系列的例子,最终想要得到的一个结论就是,所有的运动都是矩阵变化。
2.镜头朝向人物
我们都知道,在现实世界中我们眼睛看出去的视野是有限的,在电脑中也是一样的。
假设在电脑中我们的视野是 3 * 3 的方格,我们还是以之前坐标轴举例子,黄色区域是我们的视野可见区域:
现在我们让小块往右移动3个单位,再网上移动1个单位。
这个时候我们会发现,我们的视野内已经看不到这个小块了。试想一下,我们正在玩一个射击游戏,敌人在眼前移动,我们为了找到它会在怎么办?没错,我们会旋转我们的脑袋,从而使得敌人暴露在我们的视野内。就像这样:
这下就把敌人锁定住了,能够始终让人物出现在我们的视野内并且保持相对静止。
3.镜头与人物同距
光有镜头朝向人物还不够,我们还得让我们的镜头和人物同距。为什么这么说呢,首先还是我们坐标轴的例子,但是这次我们将扩充一个z轴:然后我们看看正常下的平面截图
截图:
现在我们将我们的小块往-Z 移动1个单位:
截图:
这个时候我们发现这个小方块变小了,并且随着小方块往 -z方向移动的越多,我们看到的小块会越来越小。这个时候我们明明没有改变我们的视角,但是还是无法很好的跟踪小块。因此我们需要移动为我们视角的位置,当我们看不清一个远处的路标的时候,我们会怎么办?没错,凑近点!
截图:
完美!现在我们通过三个方向的讲解,将如果实现一个第三人称视角的功能从理论上面实现了!
接下来我们只需要按照我们的以上的理论,来实现代码就好了,代码无法就是我们用另一种语言的实现方式,知道了原理都是非常简单的。
1.初始化画布场景
<canvas class="webgl"></canvas>
...
<script>
// 创建场景
const scene = new THREE.Scene()
// 加入相机
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height);
camera.position.y = 6;
camera.position.z = 18;
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true; // 设置阻尼,需要在 update 调用
scene.add(camera);
// 渲染
const renderer = new THREE.WebGLRenderer({
canvas
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.render(scene, camera);
</script>
场景、相机、渲染器是一些比较固定的东西,这一节不主要进行讲解,可以理解为我们项目初始化的时候一些必备的语句。
这个时候我们打开页面,是黑乎乎的一片,为了美观,我给整个场景加上一个地板。
// 设置地板
const geometry = new THREE.PlaneGeometry(1000, 1000, 1, 1);
// 地板贴图
const floorTexture = new THREE.ImageUtils.loadTexture( '12.jpeg' );
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set( 10, 10 );
// 地板材质
const floorMaterial = new THREE.MeshBasicMaterial({
map: floorTexture,
side: THREE.DoubleSide
});
const floor = new THREE.Mesh(geometry, floorMaterial);
// 设置地板位置
floor.position.y = -1.5;
floor.rotation.x = - Math.PI / 2;
scene.add(floor);
这个时候画面还不错~
2.人物运动
根据理论,我们需要加入一个人物,这里为了方便,也还是加入一个小方块为主:
// 小滑块
const boxgeometry = new THREE.BoxGeometry(1, 1, 1);
const boxMaterials = [];
for (let i = 0; i < 6; i++) {
const boxMaterial = new THREE.MeshBasicMaterial({
color: Math.random() * 0xffffff,
});
boxMaterials.push(boxMaterial);
}
// 小块
const box = new THREE.Mesh(boxgeometry, boxMaterials);
box.position.y = 1;
box.position.z = 8;
scene.add(box);
为了好看,我给小块加了六面不同的颜色。
虽然看起来还是有点简陋,但是俗话说高端的食材往往只需要最朴素的烹饪方式。小块虽小,但是五脏俱全。
现在我们渲染出了小块后,要做的事情就是绑定快捷键。
对应的代码:
// 控制代码
const keyboard = new THREEx.KeyboardState();
const clock = new THREE.Clock();
const tick = () => {
const delta = clock.getDelta();
const moveDistance = 5 * delta;
const rotateAngle = Math.PI / 2 * delta;
if (keyboard.pressed("down"))
box.translateZ(moveDistance);
if (keyboard.pressed("up"))
box.translateZ(-moveDistance);
if (keyboard.pressed("left"))
box.translateX(-moveDistance);
if (keyboard.pressed("right"))
box.translateX(moveDistance);
if (keyboard.pressed("w"))
box.rotateOnAxis( new THREE.Vector3(1,0,0), rotateAngle);
if (keyboard.pressed("s"))
box.rotateOnAxis( new THREE.Vector3(1,0,0), -rotateAngle);
if (keyboard.pressed("a"))
box.rotateOnAxis( new THREE.Vector3(0,1,0), rotateAngle);
if (keyboard.pressed("d"))
box.rotateOnAxis( new THREE.Vector3(0,1,0), -rotateAngle);
renderer.render(scene, camera)
window.requestAnimationFrame(tick)
}
tick();
这里解释一下 translateZ、translateX,这俩函数就是字面意思,往 z 轴 和 x 轴移动,如果想要往前,就往 -z 轴移动,如果是往 左就是往 -x 轴移动。
clock.getDelta ()
是什么意思呢?简单说.getDelta ()
方法的功能就是获得前后两次执行该方法的时间间隔。例如我们想要在1秒内往前移动5个单位,但是直接移动肯定比较生硬,因此我们想加入动画。我们知道为了实现流畅的动画,一般通过浏览器的APIrequestAnimationFrame
实现,浏览器会控制渲染频率,一般性能理想的情况下,每秒s
渲染60次左右,在实际的项目中,如果需要渲染的场景比较复杂,一般都会低于60,也就是渲染的两帧时间间隔大于16.67ms。因此为了移动这5个单位,我们将每一帧该移动的距离,拆分到了这 60次渲染中。
最后来说说 rotateOnAxios
,这个主要就是用来控制 小盒子的旋转。
.rotateOnWorldAxis ( axis : Vector3, angle : Float ) : this axis -- 一个在世界空间中的标准化向量。 angle -- 角度,以弧度来表示。
3.相机与人物同步
回顾理论部分,我们最后一个步骤就是想要让相机(人眼)和物体保持相对静止的,也就是距离不变。
const tick = () => {
...
const relativeCameraOffset = new THREE.Vector3(0, 5, 10);
const cameraOffset = relativeCameraOffset.applyMatrix4( box.matrixWorld );
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
// 始终让相机看向物体
controls.target = box.position;
...
}
这里有个比较核心的点就是 relativeCameraOffset.applyMatrix4( box.matrixWorld );
其实这个我们在理论部分说过了,因为我们的物体移动的底层原理就是做矩阵变化,那么想要让相机(人眼)和物体的距离不变,我们只需要让相机(人眼)和物体做相同的变化。而在 Three.js 中物体所有的自身变化都记录在 .matrix
里面,只要外部的场景不发生变化,那么.matrixWorld
就等于 .matrix
。而applyMatrix4
的意思就是相乘的意思。
这样我就最终实现了整个功能!我们下期见!
源码地址:https://github.com/hua1995116/Fly-Three.js
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/Nol_cKRp9-VO4RS5VUaMvA
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。