three.js之摄像机

news2024/9/20 22:34:02

本节将在上一节的基础上进一步介绍一下摄像机功能。
three.js的摄像机主要包括两类:正交投影摄像机和透视投影摄像机。

  1. 透视投影摄像机:THREE.PerspectiveCamera,最自然的视图,距离摄像机越远,它们就会被渲染得越小。
  2. 正交投影摄像机:THREE.OrthographicCamera,所有的立方体被渲染出来的尺寸都是一样的。
  3. VR摄像机:THREE.StereoCamera将左右眼画面并排渲染,或者通过WebVR等。

效果图

在这里插入图片描述

源码

引入的插件js【本人的csdn也有下载资源,如果打不开git可以在csdn下载】:

  • three.js
  • dat.gui.js
  • Stats.js
  • TrackballControls.js
  • SceneUtils.js
  • util.js

准备工作(先克隆几个不同颜色的网格)

添加一个gui方法,作用是能够克隆几个不同颜色和相对位置的网格。现在我们可以点击页面右上角的clone方法添加不同的立方体了。

var gui = new dat.GUI();
var cloneIndex = 0
gui.add(new function () {
  this.clone = function () {
	  cloneIndex += 3
	  var clonedGeometry = mesh.children[0].geometry.clone();
	  var materials = [
		  new THREE.MeshLambertMaterial({opacity: 0.8, color: Math.random() * 0xffffff, transparent: true}),
		  new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
	  ];

	  var mesh2 = THREE.SceneUtils.createMultiMaterialObject(clonedGeometry, materials);
	  mesh2.children.forEach(function (e) {
		  e.castShadow = true
	  });
	  mesh2.translateX(cloneIndex);
	  mesh2.translateZ(-cloneIndex);
	  mesh2.name = "clone" + cloneIndex;
	  scene.remove(scene.getChildByName("clone"));
	  scene.add(mesh2);
  }
}, 'clone');

注意点:

  • 使用translate()方法你可以改变对象的位置,但是该方法设置的不是物体的绝对位置,而是物体相对于当前位置的平移距离。
  • Math.random() * 0xffffff:方法是实现颜色随机数而已。

透视投影摄像机

这种摄像机的效果更贴近真实世界,摄像机的fov属性决定了横向视场。基于aspect属性,纵向视场也就相应地确定了。near属性决定了近面距离,far属性决定了远面距离。近面距离和远面距离之间的区域将会被渲染。
在这里插入图片描述
在这里插入图片描述

正交投影摄像机

由于正交投影摄像机渲染出的物体大小都是一样的,所以它并不关心使用什么长宽比,或者以什么样的视角来观察场景。当使用正交投影摄像机时,你要定义的是一个需要被渲染的方块区域。
在这里插入图片描述
在这里插入图片描述

摄像机聚焦

  • 在之前我们通常通过方法camera.lookAt(scene.position)方法让摄像机聚焦到场景的中心
  • 现在我们可以使用camera.lookAt(new THREE.Vector3(x, y, z));来支持指定一个三维坐标点,让摄像机聚焦。
  • 当然你也可以指定某个特殊的网格,让摄像机去聚焦在这一网格上:camera.lookAt(mesh.position),这样在网格位置变化过程中,摄像机会跟随网格的坐标变化而去追踪它。

源码

4.js

var stats = initStats();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color(0x000000));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;

var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
var planeMaterial = new THREE.MeshLambertMaterial({
	color: 0xffffff
});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = 0;
scene.add(plane);

camera.position.x = -80;
camera.position.y = 100;
camera.position.z = 240;
camera.lookAt(scene.position);

// 设置8个顶点
var vertices = [
	new THREE.Vector3(1,1,1),
	new THREE.Vector3(1,5,1),
	new THREE.Vector3(1,1,5),
	new THREE.Vector3(1,5,5),
	new THREE.Vector3(5,1,1),
	new THREE.Vector3(5,5,1),
	new THREE.Vector3(5,1,5),
	new THREE.Vector3(5,5,5)
]

// 构建立方体所需要的十二个三角形平面
var faces = [
	new THREE.Face3(0,2,1),
	new THREE.Face3(2,3,1),
	new THREE.Face3(7,3,2),
	new THREE.Face3(7,2,6),
	new THREE.Face3(5,7,6),
	new THREE.Face3(4,5,6),
	new THREE.Face3(1,5,0),
	new THREE.Face3(0,5,4),
	new THREE.Face3(5,1,3),
	new THREE.Face3(5,3,7),
	new THREE.Face3(2,0,4),
	new THREE.Face3(2,4,6)
]

var geom = new THREE.Geometry()
geom.vertices = vertices
geom.faces = faces
geom.computeFaceNormals()
// 设置两种材质,这样方便同时看颜色和骨架
var materials = [
	new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}),
	new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true})
];
// materials这样做的原因是,除了显示绿色透明的立方体外,我还想显示一个线框。因为使用线框可以很容易地找出顶点和面的位置。
// SceneUtils是SceneUtils里的方法
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, materials);
mesh.castShadow = true;
mesh.children.forEach(function (e) {
  e.castShadow = true
});

scene.add(mesh);

var ambientLight = new THREE.AmbientLight(0x3c3c3c);
scene.add(ambientLight);

var spotLight = new THREE.SpotLight(0xffffff, 1.2, 150, 120);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
scene.add(spotLight);

document.getElementById("webgl-output").appendChild(renderer.domElement);
var trackballControls = initTrackballControls(camera, renderer);
var clock = new THREE.Clock();

var gui = new dat.GUI();
var cloneIndex = 0
gui.add(new function () {
  this.clone = function () {
	  cloneIndex += 3
	  var clonedGeometry = mesh.children[0].geometry.clone();
	  var materials = [
		  new THREE.MeshLambertMaterial({opacity: 0.8, color: Math.random() * 0xffffff, transparent: true}),
		  new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
	  ];

	  var mesh2 = THREE.SceneUtils.createMultiMaterialObject(clonedGeometry, materials);
	  mesh2.children.forEach(function (e) {
		  e.castShadow = true
	  });
	  mesh2.translateX(cloneIndex);
	  mesh2.translateZ(-cloneIndex);
	  mesh2.name = "clone" + cloneIndex;
	  scene.remove(scene.getChildByName("clone"));
	  scene.add(mesh2);
  }
}, 'clone');

var controls = new function () {
  this.perspective = "Perspective";
  this.switchCamera = function () {
	  if (camera instanceof THREE.PerspectiveCamera) {
		  camera = new THREE.OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
		  camera.position.x = -80;
		  camera.position.y = 100;
		  camera.position.z = 240;
		  camera.lookAt(scene.position);
		  trackballControls = initTrackballControls(camera, renderer);
		  this.perspective = "Orthographic";
	  } else {
		  camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
		  camera.position.x = -80;
		  camera.position.y = 100;
		  camera.position.z = 240;
		  camera.lookAt(scene.position);
		  trackballControls = initTrackballControls(camera, renderer);
		  this.perspective = "Perspective";
	  }
  };
};
gui.add(controls, 'switchCamera');
gui.add(controls, 'perspective').listen();

render();

var step = 0
function render() {
	trackballControls.update(clock.getDelta());
	stats.update();
	if (camera instanceof THREE.Camera) {
		step += 0.02;
		var x = 10 + ( 100 * (Math.sin(step)));
		camera.lookAt(new THREE.Vector3(x, 10, 0));
	}
	requestAnimationFrame(render);
	renderer.render(scene, camera);
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【编程问题】解决 mapper.xml 文件的 resultType 爆红问题:Cannot resolve symbol ‘xxx‘

解决mapper.xml文件的resultType爆红问题:Cannot resolve symbol xxx 1.问题描述2.问题分析3.问题解决3.1 配置注解(推荐)3.2 配置全类名3.3 删除插件 4.事件感悟 系统:Win10 JDK:1.8.0_333 IDEA:2022.2.4 …

HCIP之MPLS中的VPN

目录 HCIP之MPLS中的VPN 定义 例图 解读 流程 双层标签技术 控制层面 数据层面 配置 HCIP之MPLS中的VPN 定义 VPN --- 虚拟网专用 --- 是一种运营商提供的,专门解决虚拟专线安全及宽带问题的综合解决方案 例图 解读 站点 --- 可以理…

Day936.如何重构过大类 -系统重构实战

如何重构过大类 Hi,我是阿昌,今天学习记录的是关于如何重构过大类的内容。 在过去的代码里一定会遇到一种典型的代码坏味道,那就是“过大类”。 在产品迭代的过程中,由于缺少规范和守护,单个类很容易急剧膨胀&#…

婴儿尿布台出口美国CPC认证

什么是尿布台?尿布台上架亚马逊要怎么做?咱们接着往下看。 什么是尿布台? 尿布台:尿布台是一种自立式抬升结构,通常设计用于承托体重不超过 13.61 千克(30 磅)的儿童。儿童采用平躺姿势&#…

Forest-声明式HTTP客户端框架-集成到SpringBoot实现调用第三方restful api并实现接口数据转换

场景 Forest 声明式HTTP客户端API框架,让Java发送HTTP/HTTPS请求不再难。它比OkHttp和HttpClient更高层, 是封装调用第三方restful api client接口的好帮手,是retrofit和feign之外另一个选择。 通过在接口上声明注解的方式配置HTTP请求接…

echarts中横坐标显示为time,使用手册

需求: 后端传递(两段数据,不同时间间隔)的24h实时数据,前端需要根据24小时时间展示,要求:x轴为0-24h,每个两小时一个刻度 误区: 刚开始通过二维数据的形式秒点&#xff…

Python入门到精通12天(迭代器与生成器)

迭代器与生成器 迭代器生成器 迭代器 迭代器是可迭代的对象,即可以进行遍历的对象。列表、字符串、元组、字典和集合这些都是可迭代的对象,都可以进行遍历。 迭代器是一种访问序列元素的方式,它可以通过next()函数逐个返回序列中的元素。并…

mybatis3源码篇(1)——构建流程

mybatis 版本:v3.3.0 文章目录 构建流程SqlSessionFactoryBuilderXMLConfigBuildertypeAliasesElementtypeHandlerElementmapperElementMapperRegistry MappedStatementMapperAnnotationBuilderXMLMapperBuilderMapperBuilderAssistant SqlSessionFactorySqlSession…

【录用案例】1区SCI仅36天录用,新增多本1-2区SCI,CNKI评职好刊发表案例

我处上周(2023年4月8日-2023年4月14日)经核实,由我处Unionpub学术推荐的24篇论文已被期刊部录用、20篇见刊,5篇检索: ✔新增1区纳米与环境类SCI&EI,仅36天录用,录用后17天见刊;…

前端canvas截图酷游地址的方法!

前情提要 想在在JavaScript中&#xff0c;酷游专员KW9㍠ㄇEㄒ提供用HTML5的Canvas元素来剪取画面并存成SVG或PNG。 程式写法(一) 首先&#xff0c;需要在HTML中创建一个Canvas元素<canvas id"myCanvas"></canvas> 在JavaScript中&#xff0c;使用canv…

【Java面试】ArrayList、LinkedList 查找数据哪个快

ArrayList、LinkedList查找数据哪个快 这里有几种不同情况 1、是不是有序的&#xff1f; 2、说的查找是什么意思&#xff1f;是调用get(1)&#xff0c;还是调用的contains(o)方法&#xff1f; 根据上面的问题&#xff0c;我们可以分开讨论&#xff1a; 1、数据是有序的 指定…

Apifox自动生成接口文档

1、安装 1.1 Apifox安装 官方文档&#xff1a;Apifox - API 文档、调试、Mock、测试一体化协作平台 - 接口文档工具&#xff0c;接口自动化测试工具&#xff0c;接口Mock工具&#xff0c;API文档工具&#xff0c;API Mock工具&#xff0c;API自动化测试工具 1.2 IDEA 插件安装…

Vue 复学 之 状态管理 Vuex

Vuex是vue中的一种状态管理模式&#xff0c;就是一个 状态仓库&#xff0c;仓库做什么&#xff1f;存储状态、管理状态&#xff08;数据&#xff09;的变化、提供状态获取窗口。 本文中一些测试用例基于vue/composition-api1.7.1 &#xff0c; vuex3.6.2&#xff0c; vue2.6.1…

【unity实战】随机地下城生成1——随机生成地下城初稿(含源码)

先看看实现的最终效果 #用到的素材 https://download.csdn.net/download/qq_36303853/87712757 导入素材 导入房间图片素材,配置图片信息信息 点击sprite Editor,开始切割图片 随机创建基本房间 已一个白底图片模拟房间预设体 思路:建立一个空的 GameObject 用来做…

C++中的STL容器

文章目录 一、序列式容器1.vector2.array3.deque4.list5.forward_list 二、关联式容器1.set、multiset、unordered_set和unordered_multiset2.map、multimap、unordered_map和unordered_multimap STL中的容器将一些应用最为广泛的数据结构实现了出来&#xff0c;它主要分为序列…

使用python下载wallpaper Engine订阅的壁纸/视频

一、为什么想下载wallpaper Engine的壁纸 在游戏平台steam上&#xff0c;有一个壁纸软件wallpaper Engine&#xff0c;人称小红车&#xff0c;里面有各种好看的动态壁纸和视频&#xff0c;可以给我们的电脑设置动态桌面&#xff0c;非常好用。   用过几次后&#xff0c;我有了…

Doris(14):索引

1 概念 索引用于帮助快速过滤或查找数据。 目前 Doris 主要支持两类索引&#xff1a; 内建的智能索引&#xff0c;包括前缀索引和ZoneMap索引用户创建的二级索引&#xff0c;包括Bloom Filter索引和Bitmap倒排索引。 前缀索引&#xff1a;即在排序的基础上&#xff0c;实现的…

kv server(配置以及性能测试)

首先在 Cargo.toml 里添加 serde 和 toml。我们计划使用 toml 做配置文件&#xff0c;serde 用来处理配置的序列化和反序列化&#xff1a; [dependencies] ... serde { version "1", features ["derive"] } # 序列化/反序列化 ... toml "0.5"…

antd表格a-table滚动失效。x轴滚动失效

目录 antd表格a-table滚动失效。x轴滚动失效 页面html代码如下。实现左右布局&#xff0c;左边侧边栏固定宽度&#xff0c;右边沾满剩余宽度 解决方案&#xff1a;在计算右侧宽度时&#xff0c;左边侧边栏固定宽度&#xff0c;右边沾满剩余宽度 情况1&#xff1a;左侧侧边栏…

第八章 查询和检索:Query DSL

版权声明 本文为Elastic开源社区版权所有,保证独立性和原创性,未获得授权和允许,任何组织和个人不得以任何方式传播或复制或分享。否则必将追究法律责任。 知识内容输出不易,请尊重他人劳动成果。严禁随意传播、复制和盗用他人成果或文章内容用以商业或盈利目的! 1、查询…