I have a three.js scene that is using ArrayCamera
with 2 cameras. One is first-person, the other an aerial view. For the aerial view, I'm rendering 2 spheres but only one is visible. It seems anything with a position.z value greater than 0 doesn't render but I'm not sure why.
Codepen
import * as THREE from ";;
//
const canvasWidth = window.innerWidth;
const canvasHeight = window.innerHeight;
const canvasPixelRatio = Math.min(window.devicePixelRatio, 2);
// Divide by 2 because each camera takes up half the viewport.
const cameraWidth = (window.innerWidth / 2) * window.devicePixelRatio;
const cameraHeight = window.innerHeight * window.devicePixelRatio;
const cameraAspectRatio = cameraWidth / cameraHeight;
const layout = document.querySelector("#myDiv");
// SCENE
const scene = new THREE.Scene();
// MESHES
const sphere1 = new THREE.Mesh(
new THREE.SphereGeometry(0.5),
new THREE.MeshBasicMaterial({ color: "white", wireframe: true })
);
sphere1.position.set(0, 0, -1);
scene.add(sphere1);
const sphere2 = new THREE.Mesh(
new THREE.SphereGeometry(0.5),
new THREE.MeshBasicMaterial({ color: "white", wireframe: true })
);
sphere2.position.set(0, 0, 1);
scene.add(sphere2);
// Ground plane
const meshPlane = new THREE.Mesh(
new THREE.PlaneGeometry(100, 100, 40, 40),
new THREE.MeshBasicMaterial({
color: "white",
wireframe: true
})
);
meshPlane.rotation.x = Math.PI / 2; // Rotate to lie flat
scene.add(meshPlane);
// First-person camera
const firstPersonCamera = new THREE.PerspectiveCamera(
75,
cameraAspectRatio,
0.1,
100
);
firstPersonCamera.position.set(0, 0, 5); // In front of cube
firstPersonCamera.lookAt(0, 0, -1); // Look forward
// Not sure what this is doing but without it, things break.
firstPersonCamera.updateMatrixWorld();
const aerialCamera = new THREE.OrthographicCamera(
cameraWidth / -2,
cameraWidth / 2,
cameraHeight / 2,
cameraHeight / -2,
0,
2000
);
aerialCamera.position.set(0, 1, 0); // Above origin
aerialCamera.lookAt(0, 0, 0); // Look down
aerialCamera.zoom = 40;
// Not sure what this is doing but without it, things break.
aerialCamera.updateMatrixWorld();
const cameras = new THREE.ArrayCamera([firstPersonCamera, aerialCamera]);
cameras.cameras[0].viewport = new THREE.Vector4(
0,
0,
cameraWidth,
cameraHeight
); // Left half
cameras.cameras[1].viewport = new THREE.Vector4(
cameraWidth,
0,
cameraWidth,
cameraHeight
); // Right half
// Must be called after any change of parameters.
cameras.cameras[0].updateProjectionMatrix();
cameras.cameras[1].updateProjectionMatrix();
const helper = new THREE.CameraHelper(cameras);
scene.add(helper);
// HELPERS
const axesHelper = new THREE.AxesHelper();
scene.add(axesHelper);
// RENDERER
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(canvasWidth, canvasHeight);
renderer.setPixelRatio(canvasPixelRatio);
layout.appendChild(renderer.domElement);
// ANIMATE
function onNewFrame() {
renderer.render(scene, cameras);
}
renderer.setAnimationLoop(onNewFrame);
I have a three.js scene that is using ArrayCamera
with 2 cameras. One is first-person, the other an aerial view. For the aerial view, I'm rendering 2 spheres but only one is visible. It seems anything with a position.z value greater than 0 doesn't render but I'm not sure why.
Codepen
import * as THREE from "https://esm.sh/three";
// https://threejs.org/examples/#webgl_camera_array
const canvasWidth = window.innerWidth;
const canvasHeight = window.innerHeight;
const canvasPixelRatio = Math.min(window.devicePixelRatio, 2);
// Divide by 2 because each camera takes up half the viewport.
const cameraWidth = (window.innerWidth / 2) * window.devicePixelRatio;
const cameraHeight = window.innerHeight * window.devicePixelRatio;
const cameraAspectRatio = cameraWidth / cameraHeight;
const layout = document.querySelector("#myDiv");
// SCENE
const scene = new THREE.Scene();
// MESHES
const sphere1 = new THREE.Mesh(
new THREE.SphereGeometry(0.5),
new THREE.MeshBasicMaterial({ color: "white", wireframe: true })
);
sphere1.position.set(0, 0, -1);
scene.add(sphere1);
const sphere2 = new THREE.Mesh(
new THREE.SphereGeometry(0.5),
new THREE.MeshBasicMaterial({ color: "white", wireframe: true })
);
sphere2.position.set(0, 0, 1);
scene.add(sphere2);
// Ground plane
const meshPlane = new THREE.Mesh(
new THREE.PlaneGeometry(100, 100, 40, 40),
new THREE.MeshBasicMaterial({
color: "white",
wireframe: true
})
);
meshPlane.rotation.x = Math.PI / 2; // Rotate to lie flat
scene.add(meshPlane);
// First-person camera
const firstPersonCamera = new THREE.PerspectiveCamera(
75,
cameraAspectRatio,
0.1,
100
);
firstPersonCamera.position.set(0, 0, 5); // In front of cube
firstPersonCamera.lookAt(0, 0, -1); // Look forward
// Not sure what this is doing but without it, things break.
firstPersonCamera.updateMatrixWorld();
const aerialCamera = new THREE.OrthographicCamera(
cameraWidth / -2,
cameraWidth / 2,
cameraHeight / 2,
cameraHeight / -2,
0,
2000
);
aerialCamera.position.set(0, 1, 0); // Above origin
aerialCamera.lookAt(0, 0, 0); // Look down
aerialCamera.zoom = 40;
// Not sure what this is doing but without it, things break.
aerialCamera.updateMatrixWorld();
const cameras = new THREE.ArrayCamera([firstPersonCamera, aerialCamera]);
cameras.cameras[0].viewport = new THREE.Vector4(
0,
0,
cameraWidth,
cameraHeight
); // Left half
cameras.cameras[1].viewport = new THREE.Vector4(
cameraWidth,
0,
cameraWidth,
cameraHeight
); // Right half
// Must be called after any change of parameters.
cameras.cameras[0].updateProjectionMatrix();
cameras.cameras[1].updateProjectionMatrix();
const helper = new THREE.CameraHelper(cameras);
scene.add(helper);
// HELPERS
const axesHelper = new THREE.AxesHelper();
scene.add(axesHelper);
// RENDERER
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(canvasWidth, canvasHeight);
renderer.setPixelRatio(canvasPixelRatio);
layout.appendChild(renderer.domElement);
// ANIMATE
function onNewFrame() {
renderer.render(scene, cameras);
}
renderer.setAnimationLoop(onNewFrame);
sphere1.position.set(0, 0, -1);
sphere2.position.set(0, 0, 1);
Those sphere's both need an negative Z. But that will overlap them, so lets move one to the left, and one to the right. Also place them more behind so they are still inside your frustum:
sphere1.position.set(-1, 0, -5);
sphere2.position.set(1, 0, -5);
Gives: