选择合适的相机

  • 学习ThreeJS的捷径
  • 两种常用相机
  • 案例分析
    • 创建两种相机
    • 透视相机 PerspectiveCamera
    • 正交相机OrthographicCamera
    • 切换相机
  • 掌控相机

学习ThreeJS的捷径

本段内容会写在0篇以外所有的,本人所编写的Threejs教程中

对,学习ThreeJS有捷径
当你有哪个函数不懂的时候,第一时间去翻一翻文档
当你有哪个效果不会做的时候,第一时间去翻一翻所有的案例,也许就能找到你想要的效果
最重要的一点,就是,绝对不要怕问问题,越怕找找别人问题,你的问题就会被拖的越久

如果你确定要走WebGL/ThreeJS的开发者路线的话,以下行为可以让你更快的学习ThreeJS

  1. 没事就把所有的文档翻一遍,哪怕看不懂,也要留个印象,至少要知道Threejs有什么
  2. 没事多看看案例效果,当你记忆的案例效果足够多时,下次再遇到相似问题时,你就有可能第一时间来找对应的案例,能更快解决你自己的问题
  3. 上述案例不只是官网的案例,郭隆邦技术博客,跃焱邵隼,暮志未晚等站点均有不少优质案例,记得一并收藏
    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 选择合适的相机与相机切换相关推荐

  1. 【ThreeJS基础教程-初识Threejs】1.ThreeJS的HelloWorld

    ThreeJS的HelloWorld 学习ThreeJS的捷径 杂项 第一个案例 案例效果 案例解析 引入threejs 创建一个场景(演出舞台) 创建相机(摄影师) 创建一个渲染器(相片处理) 创建 ...

  2. 【ThreeJS基础教程-初识Threejs】1.2掌控我们的物体和模型

    掌控我们的物体和模型 学习ThreeJS的捷径 引入帧数监控与调试时使用的GUI 案例解析 引入刷新率检测器stats和lil-gui Stats LIL.GUI (Dat.GUI) 学习ThreeJ ...

  3. 【ThreeJS基础教程-初识Threejs】1.6各种各样的几何体

    各种各样的几何体 学习ThreeJS的捷径 常用内置几何体介绍 立方缓冲几何体BoxGeometry 分段数的意义(该部分仅建议了解即可,无需深入) 圆形缓冲几何体CircleGeometry 圆柱缓 ...

  4. 【ThreeJS基础教程-初识Threejs】1.3 右手坐标系

    右手坐标系 学习ThreeJS的捷径 案例升级 右手坐标系与左手坐标系 右手坐标系旋转规则 可选学习内容推荐:欧拉角,四元数 学习ThreeJS的捷径 本段内容会写在0篇以外所有的,本人所编写的Thr ...

  5. 【ThreeJS基础教程-材质纹理篇】3.2 初识基础网格材质MeshStandardMaterial

    初识标准网格材质 学习ThreeJS的捷径 了解材质的基本知识 材质继承关系 常用的通用材质属性 alphaTest的验证和应用 depthTest和depthWrite应用 渲染哪一面Side 常用 ...

  6. 【ThreeJS基础教程】0.在学习使用ThreeJS之前

    [ThreeJS基础教程]0.在学习使用ThreeJS之前 什么人适合学习ThreeJS 什么人不建议学习ThreeJS或学起来比较累 了解ThreeJS ThreeJS文档在哪 关于<Thre ...

  7. 【ThreeJS基础教程-高级几何体篇】2.1更好的视觉效果-综合案例(2)

    2.1更好的视觉效果-综合案例(2 学习ThreeJS的捷径 初识纹理Texture 如何生成一片草地 Texture与TextureLoader 做一个简单的地球出来 下一篇预告:加载模型 学习Th ...

  8. 【ThreeJS基础教程-材质纹理篇】3.1 纹理知识进阶

    纹理知识进阶 学习ThreeJS的捷径 如何用一张地板砖贴图制作出地板砖效果 旋转纹理 移动纹理 纹理旋转与移动的应用 简单的光圈效果 简单的流水效果 WebGL项目优化技巧:没必要的细节可以用纹理直 ...

  9. 【ThreeJS基础教程-高级几何体篇】2.6.1 BufferGeometry应用1-物体居中与包围盒的应用

    BufferGeometry应用1-物体居中与包围盒的应用 学习ThreeJS的捷径 问题案例:为什么会围绕Y轴旋转 问题代码 案例效果 模型中心的概念 包围盒简介 修正Mesh中心到包围盒中心 关于 ...

最新文章

  1. java增强for循环
  2. NeHe教程Qt实现——lesson04
  3. C语言中的标识符作用域
  4. 过了双十一之后的你。。| 今日最佳
  5. 改变定时器获取传感器频度_广东梅州梅县压力传感器*校对
  6. 略论bs架构设计的几种模式
  7. linux行位换行符,换行符或标点符号作为elasticsearch中的位置间隔
  8. Oracle 和Mysql Group by的细节与坑
  9. C语言学习及项目开发所遇问题总集(一)---Mr.Zhang
  10. 美团最好战的那个男人要走了
  11. 甲骨文通知用户需付费取得 Java 8 更新
  12. 著名加密艺术家XCOPY的NFT作品以1000ETH售出,约合173.5万美元
  13. 卑微测试员自述:入职新公司一个月,就让我做自动化测试?!
  14. de4dot构建过程
  15. 2017年校园招聘中国银行、中国邮政储蓄银行、中国移动笔试内容
  16. 电源功耗压力测试软件,整机功耗测试_机箱电源新闻-中关村在线
  17. Android Studio 根据屏幕大小缩放图片
  18. 从零开始学Excel VBA
  19. 一个C程序辨别系统是64位还是32位
  20. vue3项目实战---知乎日报----项目搭建

热门文章

  1. yandex安卓android,首款Jolla手机国内首测【6】
  2. [035] 微信公众帐号开发教程第11篇-符号表情的发送(上)
  3. 暨南大学算法期末复习
  4. 万卷书 - 大家来写作 [Everybody Writes]
  5. php微信小程序毕业设计 php后台驾校考试小程序毕业设计开题报告功能参考
  6. 客观赋权法的python实现
  7. Java反射机制(反射Field,Method,Constructor,资源绑定器)
  8. 如何在Google Chrome浏览器中举报网络钓鱼和恶意网站
  9. 巧用网页分析“反击”钓鱼网站
  10. 重装系统win7旗舰版教程