Three.js学习6:透视相机和正交相机

一、相机

相机 camera,可以理解为摄像机。在拍影视剧的时候,最终用户看到的画面都是相机拍出来的内容。

Three.js 里,相机 camera 里的内容就是用户能看到的内容。从这个角度来看,相机其实就是用户的视野,就像用户的眼睛

Three.js 主要有四种不同的相机模式:

  • 透视相机 PerspectiveCamera:具有透视效果,近大远小,也是用的最多的相机。

  • 正交相机 OrthographicCamera:不具有透视效果,所有的元素的尺寸大小都是相同的,不管距离。

  • 立体相机 StereoCamera:主要做VR用的。就是让左右视觉有点点不一样的相机。

  • 立方体相机 CubeCamera:主要用作反射镜面纹理。

本文主要讨论透视相机和正交相机。

前面案例中应用到的轨道控制器,名为轨道,其实控制的就是相机的视角。

 二、透视相机

透视相机(PerspectiveCamera)中的物体具有“近大远小”的特点,是3D场景的渲染中使用得最普遍的投影模式。

1. 参数解析

const camera = new THREE.PerspectiveCamera(fov, aspect, near, far );

其参数分别为:

  1. fov :摄像机视锥体垂直视野角度,以角度来表示。默认值是50

  2. aspect :摄像机视锥体宽高比:默认值为 1,一般用渲染器到宽高比

  3. near:摄像机视锥体近截面,默认值是0.1

  4. far:摄像机视锥体远截面,默认值是2000

const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
scene.add( camera );

 只有在视锥体范围内,近截面和远截面之间的物体才会被渲染出来。

Three.js 编辑器里视锥体的样子:

 

可以通过点语法的形式修改相机视锥体的参数,但是必须调用camera.updateProjectionMatrix() 方法,让修改生效。

const camera = new THREE.PerspectiveCamera(50, winW/winH,1, 10);
camera.near = 5;    // 修改参数
camera.far = 37;
camera.updateProjectionMatrix();   // 让参数修改生效

2. 修改相机坐标

因为,相机默认在原点上,物体也默认在原点上。所以,要看到物品,要把相机往后挪动位置,也既修改 z 轴位置。

// 调整相机位置 x,y,z
camera.position.z = 0;
camera.position.x = 0;
camera.position.y = 10;

// 或者 
camera.position.set(0,0,10);

3. 镜头对准物体

不过有时候,移动相机的时候,相机必须要盯着目标物体,避免物体跑出视野之外。

camera.lookAt( Xmesh.position ); // 相机镜头盯着x物体

也可以对准某个具体的位置:

camera.lookAt(new THREE.Vector3(x,y,z));

4. 缩放镜头

camera.zoom = 4;
camera.updateProjectionMatrix();   // 让参数修改生效

获取或者设置摄像机的缩放倍数,其默认值为1

  • >1:镜头里的物体会被放大

  • <1:物体会被缩小

  • =1:物体正常大小

必须调用camera.updateProjectionMatrix() 方法,让修改生效。

三、正交相机

正交相机(OrthographicCamera),无论物体距离相机距离远或者近,在最终渲染物体的大小都保持不变。

主要用于渲染 2D 场景或者UI元素。如下图所示:

 1. 参数解析

const camera = new THREE.OrthographicCamera(OrthographicCamera( left, right, top, bottom, near, far);
scene.add( camera );

其参数依次分别为:

  • left : 摄像机视锥体左侧面

  • right : 摄像机视锥体右侧面。left 与 right 互为反数。

  • top:摄像机视锥体上侧面

  • bottom: 摄像机视锥体下侧面。top 与 bottom 互为反数。

  • near : 摄像机视锥体近截面。其默认值为0.1

  • far: 摄像机视锥体远截面。其默认值为2000

这几个参数刚好组成一个立方体。

 例如:

const k = winW / winH; //canvas画布宽高比
const s = 2; // 显示控制系数。
const camera = new THREE.OrthographicCamera( -s*k, k*s, s, -s, 0.1, 2000 );
camera.position.set(8,8,8);
scene.add( camera );

为了保持照相机的横竖比例,需要保证 (right - left)(top - bottom) 的比例与 Canvas(也就是渲染器)宽度与高度的比例一致。所以才有了两个变量 k、s。

  • 变量 k:render 渲染的宽高比。因为,正交相机默认渲染的是一个正方形,但是我们渲染的范围(canvas)不一定是一个正方形。正交相机区域将被拉伸以适合我们的矩形画布,因此我们需要使用画布的宽高比。

  • 变量 S 是正交相机显示控制系数。值越小,画面越大。反之,画面越小。如果为1,画面会很大。所以,这里用“单位”的2倍。当然,也可以根据需要自行调整数据。

Three.js 编辑器里正交相机视锥体的样子:

跟透视相机一样,可以通过点语法的形式修改相机视锥体的参数,但是必须调用camera.updateProjectionMatrix() 方法,让修改生效。  

2. 正交相机例子

let winW = window.innerWidth;
let winH = window.innerHeight;

// 场景
const scene = new THREE.Scene();
scene.background = new THREE.Color("#cccccc");


// 网格辅助器
const grid = new THREE.GridHelper(1000,10);
scene.add(grid);

// 物体
const geometry = new THREE.BoxGeometry(100,100,100);
const material = new THREE.MeshBasicMaterial({
    color:"#f00"
});
const mesh = new THREE.Mesh( geometry, material );
mesh.position.set(0,0,0);
scene.add( mesh );

// 正投影相机案例
const k = winW / winH; //canvas画布宽高比
const s = 2; // 显示控制系数。网格单位*2
const camera = new THREE.OrthographicCamera( -s*k, k*s, s, -s, 0.1, 2000 );
camera.position.set(8,8,8);
scene.add( camera );

// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize( winW, winH );
document.body.appendChild( renderer.domElement );
renderer.render(scene, camera);

// 轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.update();
controls.addEventListener(function(){
    console.info( camera.position );
});

// 动画
function aniFun(){
    renderer.render( scene, camera );
    controls.update();
    requestAnimationFrame( aniFun );
}
aniFun();

可以看到,正交相机的图像是没有近大远小的透视感的。

四、相机切换示例

 html:

<div class="btns">
    <button type="button"  id="tsBtn">透视相机</button>
    <button type="button"  id="zjBtn">正交相机</button>
    <h1 id="tit">透视相机</h1>
</div>

<script type="importmap">
    {
        "imports":{
            "three":"./js/three.module.min.js",
            "three/addons/":"./js/jsm/"
        }
    }
</script>
<script type="module" src="./js/myjs5-3.js"></script>

JS:

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

let scene,
    camera,
    controls, grid,
    renderer;
let winW = window.innerWidth,
    winH = window.innerHeight;

let  tsBtn = document.getElementById("tsBtn"),
     zjBtn = document.getElementById("zjBtn"),
     tit = document.getElementById("tit");

// 场景
scene = new THREE.Scene();
scene.background = new THREE.Color("#cccccc");

// 透视相机
function pCamera(){
    camera = new THREE.PerspectiveCamera(50, winW/winH,1, 1000);
    camera.position.set( 8,8,8 );
    camera.lookAt( scene.position );
    scene.add( camera );
}

// 正交相机
function oCamera(){
    const k = winW / winH; //canvas画布宽高比
    const s = 8; // 显示控制系数。
    camera = new THREE.OrthographicCamera( -s*k, k*s, s, -s, 0.1, 2000 );
    camera.position.set(8,8,8);
    camera.lookAt( scene.position );
    scene.add( camera );
}

// 渲染器
function renderFun(){
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( winW, winH );
    document.body.appendChild( renderer.domElement );
}


// 网格辅助
function gridHelperFun(){
    grid = new THREE.GridHelper(10,10);
    scene.add(grid);
}

// 立方体
function cubeFun(){
    let geometry = new THREE.BoxGeometry(1,1,1);
    let metiral = new THREE.MeshBasicMaterial({
        color:"#ff3300"
    });
    let mesh = new THREE.Mesh( geometry, metiral);
    scene.add( mesh );
}

// 函数调用
pCamera();
renderFun();
gridHelperFun();
cubeFun();

renderer.render(scene, camera);

// 动画渲染
function animateFun(){
    // 渲染
    renderer.render( scene, camera);
    requestAnimationFrame(animateFun);
}
animateFun();

// 按钮事件
tsBtn.addEventListener("click",function(){
    pCamera();
    renderer.render(scene, camera);
    tit.innerHTML = "透视相机";
});
zjBtn.addEventListener("click",function(){
    oCamera();
    renderer.render(scene, camera);
    tit.innerHTML = "正交相机";
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/374257.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Sentinel(理论版)

Sentinel 1.什么是Sentinel Sentinel 是一个开源的流量控制组件&#xff0c;它主要用于在分布式系统中实现稳定性与可靠性&#xff0c;如流量控制、熔断降级、系统负载保护等功能。简单来说&#xff0c;Sentinel 就像是一个交通警察&#xff0c;它可以根据系统的实时流量&…

电力负荷预测 | 基于TCN的电力负荷预测(Python)———模型构建

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 基于TCN的电力负荷预测(Python) python3.8 keras2.6.0 matplotlib3.5.2 numpy1.19.4 pandas1.4.3 tensorflow==2.6.0

停止内耗,做有用的事

很多读者朋友跟我交流的时候&#xff0c;都以为我有存稿&#xff0c;于是听到我说每周四现写的时候都很惊讶。其实没什么好惊讶的&#xff0c;每周四我都会把自己关在书房里一整天&#xff0c;断掉一切电话、微信、邮件&#xff0c;从中午写到晚上&#xff0c;直到写完为止。 这…

力扣● 62.不同路径 ● 63. 不同路径 II

● 62.不同路径 单解这道题的话&#xff0c;发现第一行或者第一列的这些位置&#xff0c;都只有一条路径走到&#xff0c;所以路径条数都是1。这就是初始化。坐标大于第一行第一列的这些位置&#xff0c;因为机器人只能向下/向右走&#xff0c;所以只能从上个位置向下走和从左…

用友U8 Cloud ReportDetailDataQuery SQL注入漏洞复现(QVD-2023-47860)

0x01 产品简介 用友U8 Cloud 提供企业级云ERP整体解决方案,全面支持多组织业务协同,实现企业互联网资源连接。 U8 Cloud 亦是亚太地区成长型企业最广泛采用的云解决方案。 0x02 漏洞概述 用友U8 cloud ReportDetailDataQuery 接口处存在SQL注入漏洞,攻击者未经授权可以访…

【Docker】了解Docker Desktop桌面应用程序,TA是如何管理和运行Docker容器(2)

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Docker容器》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

redis源码之:集群创建与节点通信(2)

在上一篇redis源码之&#xff1a;集群创建与节点通信&#xff08;1&#xff09;我们可知&#xff0c;在集群中&#xff0c;cluster节点之间&#xff0c;通过meet将对方加入到本方的cluster->nodes列表中&#xff0c;并在后续过程中&#xff0c;不断通过clusterSendPing发送p…

2 月 5 日算法练习- 动态规划

DP&#xff08;动态规划&#xff09;全称Dynamic Programming&#xff0c;是运筹学的一个分支&#xff0c;是一种将复杂问题分解成很多重叠的子问题、并通过子问题的解得到整个问题的解的算法。 在动态规划中有一些概念&#xff1a; n<1e3 [][] &#xff0c;n<100 [][][…

文心一言4.0API接入指南

概述 文心一言是百度打造出来的人工智能大语言模型&#xff0c;具备跨模态、跨语言的深度语义理解与生成能力&#xff0c;文心一言有五大能力&#xff0c;文学创作、商业文案创作、数理逻辑推算、中文理解、多模态生成&#xff0c;其在搜索问答、内容创作生成、智能办公等众多…

租游戏服务器多少钱1个月?一年价格多少?

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;可以选择轻量应用服务器和云服务器&#xff0c;阿腾云atengyu…

42、WEB攻防——通用漏洞文件包含LFIRFI伪协议编码算法代码审计

文章目录 文件包含文件包含原理攻击思路文件包含分类 sessionPHP伪协议进行文件包含 文件包含 文件包含原理 文件包含其实就是引用&#xff0c;相当于C语言中的include <stdio.h>。文件包含漏洞常出现于php脚本中&#xff0c;当include($file)中的$file变量用户可控&am…

Oracle笔记-为表空间新增磁盘(ORA-01691)

如下报错&#xff1a; 原因是Oracle表空间满了&#xff0c;最好是新增一个存储盘。 #查XXX命名空间目前占用了多大的空间 select FILE_NAME,BYTES/1024/1024 from dba_data_files where tablespace_name XXXX #这里的FILE_NAME能查到DBF的存储位置#将对应的datafile设置为30g…

C++中的析构函数

一、析构函数概念 析构函数不是完成对象的销毁&#xff0c;对象的销毁是由编译器完成的。析构函数完成的是对象中资源的清理工作。通常是对对象中动态开辟的空间进行清理。 二、析构函数特性 1.析构函数的函数名是 ~类名 2.析构函数无参数无返回值 3.一个类中只能有一个析…

如何让 Pages 文字分为两栏或更多栏?

通常一份文件都是由上往下仅有「一栏」而已&#xff0c;但在某些情况的排版&#xff0c;我们需要两栏甚至三栏的设计&#xff0c;在Pages 要如何做到呢&#xff1f;来看看吧。 将 Pages 文件改为双栏式设计 点一下「格式」>「布局」&#xff0c;就可以看到预设的「直栏」数…

很容易感到疲惫,怎么办?

最近&#xff0c;经常听到一些朋友诉苦&#xff0c;说&#xff1a;总觉得每天下来都特别累&#xff0c;也没干什么&#xff0c;就觉得无精打采&#xff0c;没有动力&#xff0c;提不起劲&#xff0c;什么都不想干…… 这种疲惫不是身体层面的&#xff0c;而是精神层面的。身体不…

外汇天眼:外汇天眼:注意,19个外汇平台因诈骗被监管拉黑!

近年来&#xff0c;全球金融市场出现了众多非法投资平台&#xff0c;这些平台利用虚假宣传和高回报承诺欺骗投资者&#xff0c;造成了严重的经济损失。为了保护投资者利益&#xff0c;监管机构也在加大力度打击这些非法平台。就在最近&#xff0c;又有19个外汇交易平台因涉嫌诈…

redis下载与安装教程(centos下)

文章目录 一&#xff0c;redis下载1.1上传到linux服务器上 二&#xff0c;redis安装2.1 安装依赖2.2 解压包2.3 编译并安装2.4 指定配置启动2.5 设置redis开机自启 一&#xff0c;redis下载 官网&#xff1a; https://redis.io1.1上传到linux服务器上 我用filezila上传到/us…

【AWS】step-functions服务编排

文章目录 step-functionsState machine typeStandard workflowsExpress workflows design skillsError handlingsaga Transaction processing控制分布式系统中的并发性 收费 作为AWS Serverless无服务器的一个重要一环 使用step-functions方法将 AWS 服务链接在一起 step-funct…

跟着cherno手搓游戏引擎【22】CameraController

前置&#xff1a; YOTO.h: #pragma once//用于YOTO APP#include "YOTO/Application.h" #include"YOTO/Layer.h" #include "YOTO/Log.h"#include"YOTO/Core/Timestep.h"#include"YOTO/Input.h" #include"YOTO/KeyCod…

基于最新koa的Node.js后端API架构与MVC模式

Koa 是一个由 Express 原班人马打造的现代 Web 框架&#xff0c;用于 Node.js。它旨在提供一个更小、更富有表现力和更强大的基础&#xff0c;用于 Web 应用和 API 开发。Koa 不捆绑任何中间件&#xff0c;它提供了一个优雅的方法以组合不同的中间件来处理请求和响应。 Koa 的核…
最新文章