The task is as follows: There is a scene type of landscape. It contains two 3D models of people. How to make it possible to look at the scene from the point of view of each of these people?

Do I understand correctly that I need to emulate a camera in the first person, as in games. Use FirstPersonControls? Or it is possible by means of standard three.js to put cameras on these objects and switch between them?

  • To avoid such a pluralism of opinions in the answers, it is better to add an example in the question in the form of a code snippet or on jsfiddle. - prisoner849
  • one
    Dear users. If you have received an answer to your question, please do not forget to mark it as an answer! It is important! - Stanislav Hmelevsky

2 answers 2

You can explicitly set the camera position and direction where it looks each time you switch from one character to another.

//camera placed at human1's head and facing at human2 var humanHeight = 10; camera.position.set(human1.matrixWorld.getPosition().x, human1.matrixWorld.getPosition().y + humanHeight, human1.matrixWorld.getPosition().z); camera.lookAt(human2); 

    There was a similar question in the English version.
    Try this: JSFiddle

     if (!Detector.webgl) Detector.addGetWebGLMessage(); var container, stats; var views, scene, renderer; var mesh, group1, group2, group3, light; var mouseX = 0, mouseY = 0; var windowWidth, windowHeight; var views = [{ left: 0, top: 0, width: 0.5, height: 1.0, background: new THREE.Color().setRGB(0.5, 0.5, 0.7), eye: [0, 300, 1800], up: [0, 1, 0], fov: 30, updateCamera: function(camera, scene, mouseX, mouseY) { camera.position.x += mouseX * 0.05; camera.position.x = Math.max(Math.min(camera.position.x, 2000), -2000); camera.lookAt(scene.position); } }, { left: 0.5, top: 0.5, width: 0.5, height: 0.5, background: new THREE.Color().setRGB(0.7, 0.5, 0.5), eye: [0, 1800, 0], up: [0, 0, 1], fov: 45, updateCamera: function(camera, scene, mouseX, mouseY) { camera.position.x -= mouseX * 0.05; camera.position.x = Math.max(Math.min(camera.position.x, 2000), -2000); camera.lookAt(camera.position.clone().setY(0)); } }, { left: 0.5, top: 0, width: 0.5, height: 0.5, background: new THREE.Color().setRGB(0.5, 0.7, 0.7), eye: [1400, 800, 1400], up: [0, 1, 0], fov: 60, updateCamera: function(camera, scene, mouseX, mouseY) { camera.position.y -= mouseX * 0.05; camera.position.y = Math.max(Math.min(camera.position.y, 1600), -1600); camera.lookAt(scene.position); } } ]; init(); animate(); function init() { container = document.getElementById('container'); for (var ii = 0; ii < views.length; ++ii) { var view = views[ii]; var camera = new THREE.PerspectiveCamera(view.fov, window.innerWidth / window.innerHeight, 1, 10000); camera.position.fromArray(view.eye); camera.up.fromArray(view.up); view.camera = camera; } scene = new THREE.Scene(); light = new THREE.DirectionalLight(0xffffff); light.position.set(0, 0, 1); scene.add(light); // shadow var canvas = document.createElement('canvas'); canvas.width = 128; canvas.height = 128; var context = canvas.getContext('2d'); var gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2); gradient.addColorStop(0.1, 'rgba(0,0,0,0.15)'); gradient.addColorStop(1, 'rgba(0,0,0,0)'); context.fillStyle = gradient; context.fillRect(0, 0, canvas.width, canvas.height); var shadowTexture = new THREE.CanvasTexture(canvas); var shadowMaterial = new THREE.MeshBasicMaterial({ map: shadowTexture, transparent: true }); var shadowGeo = new THREE.PlaneBufferGeometry(300, 300, 1, 1); mesh = new THREE.Mesh(shadowGeo, shadowMaterial); mesh.position.y = -250; mesh.rotation.x = -Math.PI / 2; scene.add(mesh); mesh = new THREE.Mesh(shadowGeo, shadowMaterial); mesh.position.x = -400; mesh.position.y = -250; mesh.rotation.x = -Math.PI / 2; scene.add(mesh); mesh = new THREE.Mesh(shadowGeo, shadowMaterial); mesh.position.x = 400; mesh.position.y = -250; mesh.rotation.x = -Math.PI / 2; scene.add(mesh); var faceIndices = ['a', 'b', 'c']; var color, f, f2, f3, p, vertexIndex, radius = 200, geometry = new THREE.IcosahedronGeometry(radius, 1), geometry2 = new THREE.IcosahedronGeometry(radius, 1), geometry3 = new THREE.IcosahedronGeometry(radius, 1); for (var i = 0; i < geometry.faces.length; i++) { f = geometry.faces[i]; f2 = geometry2.faces[i]; f3 = geometry3.faces[i]; for (var j = 0; j < 3; j++) { vertexIndex = f[faceIndices[j]]; p = geometry.vertices[vertexIndex]; color = new THREE.Color(0xffffff); color.setHSL((py / radius + 1) / 2, 1.0, 0.5); f.vertexColors[j] = color; color = new THREE.Color(0xffffff); color.setHSL(0.0, (py / radius + 1) / 2, 0.5); f2.vertexColors[j] = color; color = new THREE.Color(0xffffff); color.setHSL(0.125 * vertexIndex / geometry.vertices.length, 1.0, 0.5); f3.vertexColors[j] = color; } } var materials = [ new THREE.MeshPhongMaterial({ color: 0xffffff, shading: THREE.FlatShading, vertexColors: THREE.VertexColors, shininess: 0 }), new THREE.MeshBasicMaterial({ color: 0x000000, shading: THREE.FlatShading, wireframe: true, transparent: true }) ]; group1 = THREE.SceneUtils.createMultiMaterialObject(geometry, materials); group1.position.x = -400; group1.rotation.x = -1.87; scene.add(group1); group2 = THREE.SceneUtils.createMultiMaterialObject(geometry2, materials); group2.position.x = 400; group2.rotation.x = 0; scene.add(group2); group3 = THREE.SceneUtils.createMultiMaterialObject(geometry3, materials); group3.position.x = 0; group3.rotation.x = 0; scene.add(group3); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement); stats = new Stats(); container.appendChild(stats.dom); document.addEventListener('mousemove', onDocumentMouseMove, false); } function onDocumentMouseMove(event) { mouseX = (event.clientX - windowWidth / 2); mouseY = (event.clientY - windowHeight / 2); } function updateSize() { if (windowWidth != window.innerWidth || windowHeight != window.innerHeight) { windowWidth = window.innerWidth; windowHeight = window.innerHeight; renderer.setSize(windowWidth, windowHeight); } } function animate() { render(); stats.update(); requestAnimationFrame(animate); } function render() { updateSize(); for (var ii = 0; ii < views.length; ++ii) { var view = views[ii]; var camera = view.camera; view.updateCamera(camera, scene, mouseX, mouseY); var left = Math.floor(windowWidth * view.left); var top = Math.floor(windowHeight * view.top); var width = Math.floor(windowWidth * view.width); var height = Math.floor(windowHeight * view.height); renderer.setViewport(left, top, width, height); renderer.setScissor(left, top, width, height); renderer.setScissorTest(true); renderer.setClearColor(view.background); camera.aspect = width / height; camera.updateProjectionMatrix(); renderer.render(scene, camera); } } 
     body { color: #000; font-family: Monospace; font-size: 13px; text-align: center; background-color: #fff; margin: 0px; overflow: hidden; } #info { position: absolute; top: 0px; width: 100%; padding: 5px; } a { color: #0080ff; } 
     <script src="https://threejs.org/examples/js/libs/stats.min.js"></script> <script src="https://threejs.org/examples/js/Detector.js"></script> <script src="https://threejs.org/build/three.js"></script> <div id="container"></div> 

    • I understand that he doesn’t need two views at once, but switching the camera position - larrymacbarry