相机其实在前面已经涉及到了PerspectiveCamera,这里还会简单涉及一个OrthographicCamera:正交相机,但是只是简单涉及,因为我没有听太明白,所以还是看了别人写的文档,加以理解了一下
Camera
Camera是一个抽象类,不能直接实例化Camera类,但是可以使用它的继承类来访问常用的属性和方法
camera有以下几种:
ArrayCamera:通过多个相机进行渲染,每个相机渲染画布上的一个特定区域
StereoCamera:是通过两个摄像机模拟人眼渲染场景,创造视觉差,让这个场景看起来有深度
CubeCamera:他会做6个渲染,每个渲染是不同的方向,即上下左右前后,可以渲染物体的周围
OrthographicCamera:用来渲染没有视角的场景,也就是说,不论相机与物体有多远或多近,物体呈现的都是相同的大小
PerspectiveCamera:透视相机
常用的还是正交相机和透视相机
正交相机
这里引用这个连接:www.cnblogs.com/gaozhiqiang…
new THREE.OrthographicCamera()构造函数用于创建一个正交摄像机,该构造函数中有六个参数,分别是left,right,top,bottom,near,far。
left — 摄像机视锥体左侧面。 right — 摄像机视锥体右侧面。 top — 摄像机视锥体上侧面。 bottom — 摄像机视锥体下侧面。 near — 摄像机视锥体近端面。 far — 摄像机视锥体远端面。
其中,left的值不能够大于right的值,而且left和right设置的值必须位于摄像机position中x坐标的两侧,否则将看不到影像。 对应的top和bottom也一样,bottom值不能大于top值,且位于摄像机position坐标y值两边,否则也会看不到投影影像。 near和far分别用来设置摄像机近端面和远端面,也就是通常说的最近距离和最远距离。near设置越小,投影的影像就越大,反之则越小。 但是near值并不是影响投影物体大小最大的,影响投影物体尺寸最大的还是left,right,top,bottom四个参数,而且也影响投影物体的形状, 所以在设置这四个参数的时候,left与right之间的距离和top与bottom之间的距离的比例一定要和原始的canvas画布比例相等,不然会导致投影的物体形状变形。
透视相机
PerspectiveCamera的参数:这里再写一下参数,包括之前涉及到的fov视场和aspect ratio宽高比,以及两个新的参数near和far
fov
第一个参数:fov,视场,是垂直视角下能看到的场景角度范围,可以想象从人眼散发一个锥形,有一个角度
如果这是一个小角度的视场,则看到的范围就比较小,得到一个长范围的效果;如果是一个大角度的视场,即广角,看到的范围大,会得到一个鱼眼效果,因为最后,相机看到的东西会被拉伸或挤压,以适应画布。
建议设置在45-75度之间
aspect ratio
第二个参数是宽高比,一般也是渲染的宽高比。也就是画布的宽高比
near和far
第三个和第四个参数是能看到的最近和最远的物体的距离,也就是代表着相机能看到的什么距离范围内的物体
比如,有的物体距离相机很近,进到超出了相机能看到的近的范围,那这个物体就不会被渲染出来,同理,超出最远距离范围的物体也一样;如果一个物体介于可见和不可见之间,那么就会看到这个物体的一部分
注:如果设置极限值:如0.00000001和99999999999,那么可能会导致z-fighting的bug,所以,不要设置极限值
z-fighting:渲染中经常会遇到场景中离视点较远但是彼此相近的两个物体会有闪烁的现象
const camera=new THREE.PerspectiveCamera(75,sizes.width/sizes.height,0.1,100)
根据鼠标移动而旋转的物体场景
首先要获取鼠标在页面的位置:这里要涉及到鼠标的坐标点,监测鼠标位置变化,js中event对象的各个属性:
clientX,clientY:以浏览器显示区域的左上角为原点
offsetX,offsetY:以目标元素event,target的左上角为原点
layerX,layerY:以有定位的父元素的左上角为原点
pageX,pageY:相对页面的左上角为远点
screenX,screenY:相对屏幕左上角为原点
监听canvas画布内鼠标移动,获取鼠标对画布左上角原点的距离
//获取鼠标光标对画布的位置
const cursor={
x:0,
y:0
}
canvas.addEventListener("mousemove",e=>{
//获取鼠标光标对画布的位置像素
//cursor.x=e.offsetX;
//cursor.y=e.offsetY;
//为了让数据更好的处理,对鼠标像素距离进行处理,让其的取值范围为-0.5~0.5
cursor.x=e.offsetX/sizes.width-0.5;
//因为我们要根据鼠标移动相机,鼠标的位置就是相机的位置,而相机上移是相机的y轴正方向,而鼠标上移是页面y轴的负方向,所以要让鼠标和相机方向上一致就要取负
cursor.y=-(e.offsetY/sizes.height-0.5);
},false)
在获取到鼠标的光标坐标后,就要进行相机随着鼠标移动
......
camera.position.z=2
......
const clock=new THREE.Clock();
const tick=()=>{
const elapsedTime=clock.getElapsedTime();
//相机随鼠标左右旋转
camera.position.x=cursor.x*10;
camera.position.y=cursor.y*10;
//相机随鼠标上下
//相机看向物体的中心
//这里注意,相机应该先定好位置,再看向物体,如果先看向物体在定位会出现问题
camera.lookAt(mesh.position)
renderer.render(scene,camera)
window.requsetAnimationFrame(tick)
}
tick()
这里相机的z轴已经设置好是2,无论是沿x轴移动还是y轴移动,相机都不会跑到物体后面去,所以永远看不到物体的后面那一个面(注意,此时相机已经设为看向物体,所以如果相机到物体后方,摄像机的方向也是看向物体的方向)
为了能看到物体的后背,就需要在动画中也加上相机z轴的变化,那么,这里就设计一个数学的三角函数了:Math.sin(x); Math.cos(x)
sin和cos都是随着一个变量x的变化而变化的,那么,就可以通过这两个函数完成坐标轴上的物体在x-y这个平面上按圆旋转,可以先做一个简单的案例
//物体随着时间的增加左右摇摆
camera.position.x=Math.sin(elapsedTime)
//物体随着时间的增加上下摇摆
camera.position.y=Math.cos(elapsedTime)
结合起来,物体随着xy对应的坐标点处移动,因为函数的参数是一个相同的数,所以sin²(elapsedTime)+cos²(elapsedTime)=1,即这个坐标点在距离原点为1的位置上移动,也就是移动的路径是半径为1的圆
因此,如果要让相机可以看到物体背面,就要让相机绕到物体背面,即相机在x-z平面画圆
//注,这里cursor.x取值为-0.5~0.5,cursor.x*Math.PI*2取值-PI~PI,sin取值-1~1,这里是画半径为3的圆
camera.position.x=Math.sin(cursor.x*Math.PI*2)*3;
camera.position.z=Math.cos(cursor.x*Math.PI*2)*3;
camera.position.y=cursor.y*5
控件OrbitControls
可以完成用鼠标旋转物体,但是,如果有一些操作是控件没有的时,还是需要自己手写
这是three.js的控件,但是不能通过THREE.OrbitControls获得,这个类位于node_modules/three/example/jsm/controls/PointerLockControls.js
import {OrbitControls} from "three/example/jsm/controls/PointerLockControls.js"
//参数:1,要更新的相机;2,dom元素:将作为在其上防止鼠标事件的引用
const controls=new OrbitControls(camera,canvas)
//damping:通过添加某种加速度和摩擦力,是动画更平滑
controls.enableDamping=true;
//更改相机看向的目标
constrols.target.y=1
//更改相机后要更新
controls.update()
......
//tick()内,不断更新控件
controls.update()
//渲染......
......