Three.js笔记(八)相机(2)

自定义控件

回到PerspectiveCamera透视相机上来。注释OrthographicCamera正交相机,取消注释PerspectiveCamera透视相机,移动相机,使其面向立方体,删掉tick中的对网格体旋转的部分。

// 相机

const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 1, 1000)

// const aspectRatio = sizes.width / sizes.height

// const camera = new THREE.OrthographicCamera(- 1 * aspectRatio, 1 * aspectRatio, 1, - 1, 0.1, 100)

// camera.position.x = 2

// camera.position.y = 2

camera.position.z = 3

camera.lookAt(mesh.position)

scene.add(camera)

以用鼠标控制相机为例,首先需要知道鼠标坐标。可以使用原生JavaScript的侦听事件addEventListener,来侦听mousemove事件。

坐标将通过回调函数返回,比如event.clientX和event.clientY

// 鼠标

window.addEventListener('mousemove', (event) =>

{

    console.log(event.clientX, event.clientY)

})

此处的返回值可以直接使用,但是调整下值的范围会更好,比如调整为区间为1的值。

比如,对于x:

    当光标位于画布左侧,输出-0.5

    当光标位于画布中间,输出0

    当光标位于画布右侧,输出0.5

当然也可以采用其它值。

仿照size变量,这里创建个cursor变量,变量默认属性包含x和y,当触发mousemove回调时,更新属性的值

// 鼠标

const cursor = {

    x: 0,

    y: 0

}

window.addEventListener('mousemove', (event) =>

{

    cursor.x = event.clientX / sizes.width - 0.5

    cursor.y = event.clientY / sizes.height - 0.5

    console.log(cursor.x, cursor.y)

})

event.clientX除以sizes.width会返回一个介于0~1之间的值,通过减去一个0.5,让值分布在0.5~-0.5

这样,就完成了鼠标位置的存储,并且可以通过tick更新位置。

const tick = () =>

{

    // ...

    // 更新相机

    camera.position.x = cursor.x

    camera.position.y = cursor.y

    // ...

}

运行后,会发现沿y轴运动方向不对,这是因为Three.js中positon.y向上运动时为正,在网页中clientY向下运动时为正。

通过在cursor.y上添加负号,来纠正。

window.addEventListener('mousemove', (event) =>

{

    cursor.x = event.clientX / sizes.width - 0.5

    cursor.y = - (event.clientY / sizes.height - 0.5)

})

可以通过cursor.x和cursor.y乘上一个数字,来调整幅度大小。此时仍可通过lookAt()方法调整相机朝向。

const tick = () =>

{

    // ...

    // 更新相机

    camera.position.x = cursor.x * 5

    camera.position.y = cursor.y * 5

    camera.lookAt(mesh.position)

    // ...

}

更进一步,还可以通过使用Math.sin()和Math.cos()实现相机绕网格体旋转。

同时使用cos和sin时,可以让运动变成圆周运动。要运动成完成的圆,角度的大小必须是Π的2倍。可以通过使用Math.PI,使用Π的值。

要增加圆的半径,可以简单的将Math.sin()和Math.cos()结果乘上一个数。

const tick = () =>

{

    // ...

    // 更新相机

    camera.position.x = Math.sin(cursor.x * Math.PI * 2) * 2

    camera.position.z = Math.cos(cursor.x * Math.PI * 2) * 2

    camera.position.y = cursor.y * 3

    camera.lookAt(mesh.position)

    // ...

}

tick()

这只是一个自定义控制的例子,Three.js内置了许多控件类,用来进行许多的相似操作。

内建控件

如果在Three.js文档中搜索控件,会看到很多现成的控件。

DeviceOrientationControls设备陀螺仪控件

DeviceOrientationControls设备陀螺仪控件,就是根据权限许可,依照设备方向相应的旋转相机。如果设备合适,可以用来创建全景图或者VR效果。

FlyControls飞行控件

FlyControls飞行控件允许像飞船一样控制相机,此时可在三个轴上任意旋转、并可前后移动。

FirstPersonControls第一人称控件

FirstPersonControls第一人称控件类似上一个,但具有一个固定向上的轴,即不能向前后左右翻转,虽然名字里有第一人称,但是相机本身不含人。

PointerLockControls指针锁定控件

PointerLockControls指针锁定控件使用了JavaScript的pointer lock API。通过这个,隐藏了鼠标指针,并使其居中,但仍在事件回调中继续发送移动。使用这个API,可以创建FPS游戏,但是,这个API只提供了相机的旋转,相机的移动和游戏中的物理效果仍旧需要自行处理。

OrbitControls环绕控件

OrbitControls环绕控件类似于上面的自定义控件的例子。可以通过左键绕某个点旋转,使用鼠标右键横向平移,使用滚轮放大缩小。

TrackballControls轨迹球控件

TrackballControls轨迹球控件类似OrbitControls环绕控件,但是可以在竖直方向上翻转。

TransformControls变换控件

TransformControls变换控件和相机无关。可以用它给对象添加一个控件,用来移动对象。

这里只讲OrbitControls环绕控件

OrbitControls环绕控件

注释掉tick中更新相机的部分。

实例化

首先,使用OrbitControls类实例化变量。

由于使用了Webpack,将会以以下形式引入

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

之后就可以直接实例化OrbitControls 类,但要在创建相机后执行。

要使其正常工作,需要向其传入相机和画布,然后实例会自己处理鼠标事件。

// 控件

const controls = new OrbitControls(camera, canvas)

这样就可以使用鼠标左键或者右键来移动相机,使用滚轮进行缩放。

比自定义控件方便得多,且带有许多控件。然后再往更深层次研究。

target目标

默认情况下,相机看向场景中心。可以通过target目标属性修改它。

这个属性是个Vector3,意思就是通过x、y、z三个属性定义的。

如果希望OrbitControls环绕控件默认查看立方体上方,只需要增加y值。

controls.target.y = 2

这个用处不是很大,先注释掉它。

Damping阻尼

Damping阻尼通过加速度和摩擦力公式来平滑动画。

要启用阻尼,请将controls的enableDamping属性设置为true。

为了正常运行,还需要通过在每帧调用controls.update()。可以通过tick()实现。

// 控件

const controls = new OrbitControls(camera, canvas)

controls.enableDamping = true

// ...

const tick = () =>

{

    // ...

    // Update controls

    controls.update()

    // ...

}

这样控件看起来更加流畅。

阻尼可以用在各种旋转、移动、缩放、角度控制上,甚至按键绑定上。

何时使用内建控件

虽然这些控件很方便,但是都有局限性。如果过于依赖它们,可能需要以意想不到的方式改变类的工作方式。

首先请确保所需的功能,然后检查内建控件的功能是否完全覆盖所需的。

否则,需要自己建立控件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容