【ThreeJS基础教程-初识Threejs】1.5 选择合适的相机与相机切换
选择合适的相机
- 学习ThreeJS的捷径
- 两种常用相机
- 案例分析
- 创建两种相机
- 透视相机 PerspectiveCamera
- 正交相机OrthographicCamera
- 切换相机
- 掌控相机
学习ThreeJS的捷径
本段内容会写在0篇以外所有的,本人所编写的Threejs教程中
对,学习ThreeJS有捷径
当你有哪个函数不懂的时候,第一时间去翻一翻文档
当你有哪个效果不会做的时候,第一时间去翻一翻所有的案例,也许就能找到你想要的效果
最重要的一点,就是,绝对不要怕问问题,越怕找找别人问题,你的问题就会被拖的越久
如果你确定要走WebGL/ThreeJS的开发者路线的话,以下行为可以让你更快的学习ThreeJS
- 没事就把所有的文档翻一遍,哪怕看不懂,也要留个印象,至少要知道Threejs有什么
- 没事多看看案例效果,当你记忆的案例效果足够多时,下次再遇到相似问题时,你就有可能第一时间来找对应的案例,能更快解决你自己的问题
- 上述案例不只是官网的案例,郭隆邦技术博客,跃焱邵隼,暮志未晚等站点均有不少优质案例,记得一并收藏
http://www.yanhuangxueyuan.com/ 郭隆邦技术博客
https://www.wellyyss.cn/ 跃焱邵隼
http://www.wjceo.com/ 暮志未晚
这三个站点是我最常逛的站点,推荐各位有事没事逛一下,看看他们的案例和写法思路,绝对没坏处
两种常用相机
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>canvas{display: block;}body {margin: 0;overscroll-behavior: none;}#btns{position: absolute;top:10%;width: 500px;height: 100px;left: 50%;transform:translateX(-50%);}</style>
</head>
<body>
<div id="btns"><input type="button" value="切换正交相机" id="changeO"><input type="button" value="切换透视相机" id="changeP">
</div><!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script><script type="importmap">{"imports": {"three": "../three.js-master/build/three.module.js"}}</script>
<script type="module">import * as THREE from '../three.js-master/build/three.module.js';import {OrbitControls} from "../three.js-master/examples/jsm/controls/OrbitControls.js";import {GUI} from "../three.js-master/examples/jsm/libs/lil-gui.module.min.js"import Stats from "../three.js-master/examples/jsm/libs/stats.module.js"let scene,renderer,orbitControls;let cameraP,cameraO;let useCameraP = true;let stats,gui;let light,ambientLight;function init(){scene = new THREE.Scene();renderer = new THREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(renderer.domElement);cameraP = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);cameraP.position.set(15,10,15);orbitControls = new OrbitControls(cameraP,renderer.domElement);let width = window.innerWidth / 64;let height = window.innerHeight / 64;cameraO = new THREE.OrthographicCamera(-width,width,height,-height,1,1000);cameraO.position.set(15,10,15);let helper = new THREE.AxesHelper(5);scene.add(helper);ambientLight = new THREE.AmbientLight( 0xffffff,0.3);scene.add(ambientLight)light = new THREE.PointLight(0xffffff,0.7);light.position.y += 5;scene.add(light);stats = new Stats();document.body.appendChild(stats.dom);gui = new GUI();}function addMesh(){let geometry = new THREE.BoxGeometry(1,1,1);for(let i = 0;i< 100;i++){let material = new THREE.MeshStandardMaterial({color:Math.random() * 0xffffff});let mesh = new THREE.Mesh(geometry,material);mesh.position.x = Number.parseInt(i /10) * 1.1;mesh.position.z = ( i % 10) * 1.1;scene.add(mesh);}}function addGUI(){}function addEvent(){document.getElementById("changeO").onclick = function () {orbitControls.object = cameraO;orbitControls.update();useCameraP = false;console.log(cameraO);}document.getElementById("changeP").onclick = function () {orbitControls.object = cameraP;orbitControls.update();useCameraP = true;}}function render(){if(useCameraP){renderer.render(scene,cameraP);}else{renderer.render(scene,cameraO);}requestAnimationFrame(render);stats.update();}init();addMesh();addGUI();addEvent();render();
</script>
</body>
</html>
案例效果
透视相机下的效果
正交相机下的效果
案例分析
大多数代码已在前面的文章中做了分析,本文仅针对新出现的代码进行分析
创建两种相机
let cameraP,cameraO;let useCameraP = true;function init(){......cameraP = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);cameraP.position.set(15,10,15);orbitControls = new OrbitControls(cameraP,renderer.domElement);let width = window.innerWidth / 64;let height = window.innerHeight / 64;cameraO = new THREE.OrthographicCamera(-width,width,height,-height,1,1000);cameraO.position.set(15,10,15);......}
前面的案例中,我们都只使用了一个相机,但是这次我们要使用两个,主要是针对两种常见相机的对比和介绍
cameraP = PerspectiveCamera 透视相机
cameraO = OrthographicCamera 正交相机
透视相机 PerspectiveCamera
透视相机是一种模拟人眼的相机,这种相机看到的东西会产生近大远小的效果,如上方案例截图所示
构造器:new PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number)
fov — 摄像机视锥体垂直视野角度
aspect — 摄像机视锥体长宽比
near — 摄像机视锥体近端面
far — 摄像机视锥体远端面
官方解释比较专业,所以我们换一种方式来解释
官方对透视相机和正交相机专门做了一个案例相机案例
如上图,左侧是相机实际看到的画面,右侧是相机的可视区域的cameraHelper
这里建议同学们打开这个案例来观看会达到最好的学习效果
属性名 | 值类型 | 默认值 | 参数说明 |
---|---|---|---|
fov | Number | 50 | 相当于案例中,四棱锥的开合程度,fov越小,我们透视相机看到的内容就会越多越丰富,在案例中,右侧四棱锥越细越尖时,左侧看到的东西就会越少,四棱锥约扁越宽时,左侧看到的东西就会越多 |
aspedt | Number | 1 | 这个值为画布的比例,我们可以看到,四棱锥的底面是一个矩形,这个矩形的长宽比,就是我们的< canvas>的长宽比,这个值与画布长宽比不同时,画布上显示的画面会被压缩或拉伸 |
near | Number | 0.1 | 上图中,四棱锥的顶部有一个小型的红色四棱锥,这个红色四棱锥的底面,到整个四棱锥的顶点处,这一段距离为【视锥体近端面】的含义,也叫近裁剪面,如果你的物体出现在这个四棱锥中,你的物体将不会被相机拍摄到(换句话说,这个东西就是在你相机里面,相机里面的东西是看不见的) |
far | Number | 2000 | 上图中,大四棱锥的底面,到四棱锥顶点的距离,这一段距离为【视锥体远端面】的含义,也叫远裁剪面,近端面与远端面构成的橙色四棱台,就是相机的可视范围,所有在这个范围内的物体,均会被渲染器渲染下来,这个范围外的所有物体,均不会被渲染 |
正交相机OrthographicCamera
正交相机是一种用于渲染2D场景的相机,无论物体距离相机有多远,相机看到的物体大小都会一致,如上方案例截图中的正交相机效果
构造器 new OrthographicCamera( left : Number, right : Number, top : Number, bottom : Number, near : Number, far : Number )
left — 摄像机视锥体左侧面。
right — 摄像机视锥体右侧面。
top — 摄像机视锥体上侧面。
bottom — 摄像机视锥体下侧面。
near — 摄像机视锥体近端面。
far — 摄像机视锥体远端面。
这些参数一起定义了摄像机的viewing frustum(视锥体)。
在上面的threejs案例中,按下键盘的O键,可以将相机切换为正交相机
如案例截图所示,正交相机的可视矩阵为一个管廊,然后由近端面和远端面做封口
属性名 | 值类型 | 默认值 | 参数说明 |
---|---|---|---|
left | Number | -1 | 控制管廊左侧到中线的距离 |
right | Number | 1 | 控制管廊右侧到中线的距离 |
top | Number | 1 | 控制管廊上方到中线的距离 |
bottom | Number | -1 | 控制管廊下方到中线的距离 |
near | Number | 0.1 | 与上面透视相机的近裁剪面一样 |
far | Number | 2000 | 与上面的正交相机的远裁剪面一样 |
切换相机
在orbitContorls中有一个属性为object,当你使用new来创建一个orbitControls时,这里就会绑定你传入的相机,如果你想更换绑定的相机,使用orbitControls进行重新绑定即可
属性:orbitControls.obejct :THREE.Camera
这里的属性必须为一个Camera
function addEvent(){document.getElementById("changeO").onclick = function () {orbitControls.object = cameraO;orbitControls.update();useCameraP = false;}document.getElementById("changeP").onclick = function () {orbitControls.object = cameraP;orbitControls.update();useCameraP = true;}}
上方创建了一个useCameraP,这里的主要作用是,控制我们使用哪一个相机进行渲染
function render(){if(useCameraP){renderer.render(scene,cameraP);}else{renderer.render(scene,cameraO);}requestAnimationFrame(render);stats.update();}
这样在点击按钮的时候,我们就可以随时切换正交相机和透视相机了
当然,这种方式也可以用于多个相机切换,且相机也不局限于只能创建非同类,比如说:
function render(){switch(cameraType){case 0: renderer.render(scene,camera0);case 1: renderer.render(scene,camera1);//todo ......}requestAnimationFrame(render);stats.update();}
这种多相机的情况,一般用于你要多视角观察场景,比如说,你想要一个第一人称在地面行走的视角,又同时想要一个在空中飞行观察的视角,这个时候就可以使用多相机来做
掌控相机
很多同学这时候会有疑问,我们该怎么样设置相机才能达到最好的效果呢?
那就搬出来我们的lil.GUI
function addGUI(){let cameraPGUI = gui.addFolder("透视相机参数");cameraPGUI.add(cameraP,"fov",0,90).step(1).name("视角场").onChange(()=>{cameraP.updateProjectionMatrix();});cameraPGUI.add(cameraP,"near",0,20).step(0.01).name("近端面").onChange(()=>{cameraP.updateProjectionMatrix();});cameraPGUI.add(cameraP,"far",1,1000).step(1).name("远端面").onChange(()=>{cameraP.updateProjectionMatrix();});let width = window.innerWidth / 64;let height = window.innerHeight / 64;let cameraOGUI = gui.addFolder("正交相机参数");//left和bottom建议使用负值,这里使用屏幕大小来控制整个可视区大小//但是,由于直接使用window.innerWidth,会使得方块被渲染的非常小,所以我们等比例缩放了画布大小以达到比较好的效果cameraOGUI.add(cameraO,"left",-width,0).step(0.5).name("左边距").onChange(()=>{cameraO.updateProjectionMatrix();})cameraOGUI.add(cameraO,"right",0,width).step(0.5).name("右边距").onChange(()=>{cameraO.updateProjectionMatrix();})cameraOGUI.add(cameraO,"top",0,height).step(0.5).name("上边距").onChange(()=>{cameraO.updateProjectionMatrix();})cameraOGUI.add(cameraO,"bottom",-height,0).step(0.5).name("下边距").onChange(()=>{cameraO.updateProjectionMatrix();})cameraOGUI.add(cameraO,"near",0,20).step(0.01).name("近端面").onChange(()=>{cameraO.updateProjectionMatrix();})cameraOGUI.add(cameraO,"far",0,1000).step(1).name("远端面").onChange(()=>{cameraO.updateProjectionMatrix();})}
这里我们对两种相机都添加了相应的lil.gui的相关控件,控制效果就由在看博客的各位亲自尝试了
函数:cameraO.updateProjectionMatrix()
相机的任何参数发生改变时,都应当更新当前的矩阵
函数:gui.addFolder(name :String)
添加二级控件
使用这个后,可以更清晰的控制对应的物体的属性
【ThreeJS基础教程-初识Threejs】1.5 选择合适的相机与相机切换相关推荐
- 【ThreeJS基础教程-初识Threejs】1.ThreeJS的HelloWorld
ThreeJS的HelloWorld 学习ThreeJS的捷径 杂项 第一个案例 案例效果 案例解析 引入threejs 创建一个场景(演出舞台) 创建相机(摄影师) 创建一个渲染器(相片处理) 创建 ...
- 【ThreeJS基础教程-初识Threejs】1.2掌控我们的物体和模型
掌控我们的物体和模型 学习ThreeJS的捷径 引入帧数监控与调试时使用的GUI 案例解析 引入刷新率检测器stats和lil-gui Stats LIL.GUI (Dat.GUI) 学习ThreeJ ...
- 【ThreeJS基础教程-初识Threejs】1.6各种各样的几何体
各种各样的几何体 学习ThreeJS的捷径 常用内置几何体介绍 立方缓冲几何体BoxGeometry 分段数的意义(该部分仅建议了解即可,无需深入) 圆形缓冲几何体CircleGeometry 圆柱缓 ...
- 【ThreeJS基础教程-初识Threejs】1.3 右手坐标系
右手坐标系 学习ThreeJS的捷径 案例升级 右手坐标系与左手坐标系 右手坐标系旋转规则 可选学习内容推荐:欧拉角,四元数 学习ThreeJS的捷径 本段内容会写在0篇以外所有的,本人所编写的Thr ...
- 【ThreeJS基础教程-材质纹理篇】3.2 初识基础网格材质MeshStandardMaterial
初识标准网格材质 学习ThreeJS的捷径 了解材质的基本知识 材质继承关系 常用的通用材质属性 alphaTest的验证和应用 depthTest和depthWrite应用 渲染哪一面Side 常用 ...
- 【ThreeJS基础教程】0.在学习使用ThreeJS之前
[ThreeJS基础教程]0.在学习使用ThreeJS之前 什么人适合学习ThreeJS 什么人不建议学习ThreeJS或学起来比较累 了解ThreeJS ThreeJS文档在哪 关于<Thre ...
- 【ThreeJS基础教程-高级几何体篇】2.1更好的视觉效果-综合案例(2)
2.1更好的视觉效果-综合案例(2 学习ThreeJS的捷径 初识纹理Texture 如何生成一片草地 Texture与TextureLoader 做一个简单的地球出来 下一篇预告:加载模型 学习Th ...
- 【ThreeJS基础教程-材质纹理篇】3.1 纹理知识进阶
纹理知识进阶 学习ThreeJS的捷径 如何用一张地板砖贴图制作出地板砖效果 旋转纹理 移动纹理 纹理旋转与移动的应用 简单的光圈效果 简单的流水效果 WebGL项目优化技巧:没必要的细节可以用纹理直 ...
- 【ThreeJS基础教程-高级几何体篇】2.6.1 BufferGeometry应用1-物体居中与包围盒的应用
BufferGeometry应用1-物体居中与包围盒的应用 学习ThreeJS的捷径 问题案例:为什么会围绕Y轴旋转 问题代码 案例效果 模型中心的概念 包围盒简介 修正Mesh中心到包围盒中心 关于 ...
最新文章
- java增强for循环
- NeHe教程Qt实现——lesson04
- C语言中的标识符作用域
- 过了双十一之后的你。。| 今日最佳
- 改变定时器获取传感器频度_广东梅州梅县压力传感器*校对
- 略论bs架构设计的几种模式
- linux行位换行符,换行符或标点符号作为elasticsearch中的位置间隔
- Oracle 和Mysql Group by的细节与坑
- C语言学习及项目开发所遇问题总集(一)---Mr.Zhang
- 美团最好战的那个男人要走了
- 甲骨文通知用户需付费取得 Java 8 更新
- 著名加密艺术家XCOPY的NFT作品以1000ETH售出,约合173.5万美元
- 卑微测试员自述:入职新公司一个月,就让我做自动化测试?!
- de4dot构建过程
- 2017年校园招聘中国银行、中国邮政储蓄银行、中国移动笔试内容
- 电源功耗压力测试软件,整机功耗测试_机箱电源新闻-中关村在线
- Android Studio 根据屏幕大小缩放图片
- 从零开始学Excel VBA
- 一个C程序辨别系统是64位还是32位
- vue3项目实战---知乎日报----项目搭建
热门文章
- yandex安卓android,首款Jolla手机国内首测【6】
- [035] 微信公众帐号开发教程第11篇-符号表情的发送(上)
- 暨南大学算法期末复习
- 万卷书 - 大家来写作 [Everybody Writes]
- php微信小程序毕业设计 php后台驾校考试小程序毕业设计开题报告功能参考
- 客观赋权法的python实现
- Java反射机制(反射Field,Method,Constructor,资源绑定器)
- 如何在Google Chrome浏览器中举报网络钓鱼和恶意网站
- 巧用网页分析“反击”钓鱼网站
- 重装系统win7旗舰版教程