three.js之摄像机

本节将在上一节的基础上进一步介绍一下摄像机功能。
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属性决定了远面距离。近面距离和远面距离之间的区域将会被渲染。
three.js之摄像机_第1张图片
three.js之摄像机_第2张图片

正交投影摄像机

由于正交投影摄像机渲染出的物体大小都是一样的,所以它并不关心使用什么长宽比,或者以什么样的视角来观察场景。当使用正交投影摄像机时,你要定义的是一个需要被渲染的方块区域。
three.js之摄像机_第3张图片
three.js之摄像机_第4张图片

摄像机聚焦

  • 在之前我们通常通过方法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);
}

你可能感兴趣的:(three.js,javascript,three.js)