このセクションでは、前セクションを踏まえてカメラ機能をさらに紹介します。
three.js のカメラには主に正投影カメラと透視投影カメラの 2 種類があります。
- 透視投影カメラ: THREE.PerspectiveCamera、最も自然なビューで、カメラから遠ざかるほど小さくレンダリングされます。
- 正投影カメラ: THREE.OrthographicCamera、すべての立方体が同じサイズでレンダリングされます。
- VR カメラ: THREE.StereoCamera は、左目と右目の画像を並べて、または WebVR などを通じてレンダリングします。
レンダリング
ソースコード
導入されたプラグイン js [私の csdn にはダウンロード リソースもあります。git を開けない場合は、csdn でダウンロードできます]:
準備(最初に異なる色の複数のメッシュをクローンする)
異なる色と相対位置を持つ複数のグリッドのクローンを作成できる gui メソッドを追加します。ここで、ページの右上隅にあるクローン メソッドをクリックして、さまざまなキューブを追加できます。
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');
注意点:
- translation() メソッドを使用してオブジェクトの位置を変更できますが、このメソッドはオブジェクトの絶対位置を設定するのではなく、現在の位置を基準としたオブジェクトの移動距離を設定します。
- Math.random() * 0xffffff: 色の乱数を実現するメソッドです。
透視投影カメラ
このカメラの効果は現実世界に近くなり、カメラの fov 属性によって水平視野が決まります。アスペクト特性に基づいて、縦方向の視野がそれに応じて決定されます。Near 属性は近距離を決定し、Far 属性は遠距離を決定します。近い顔の距離と遠い顔の距離の間の領域がレンダリングされます。
正投影カメラ
正射投影カメラによってレンダリングされるオブジェクトはすべて同じサイズであるため、使用されるアスペクト比やシーンがどのような視点から見られるかは関係ありません。正投影カメラを使用する場合、定義するのはレンダリングする必要があるボックス領域です。
カメラのフォーカス
- 以前は、通常、さまざまな方法で
camera.lookAt(scene.position)
カメラの焦点をシーンの中心に合わせていました。 camera.lookAt(new THREE.Vector3(x, y, z));
これで、カメラが焦点を当てる 3D 座標点の指定をサポートするために を使用できるようになりました。- もちろん、特別なグリッドを指定して、カメラがこのグリッドに焦点を合わせるようにすることもできます。
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);
}