Universo de Instructables en Three.js (11 / 13 paso)

Paso 11: Three.js: cámara de posicionamiento

Control de la cámara es probablemente la parte más difícil de trabajar con ThreeJS. Animo fuertemente a todos no te molestes con este ejercicio de frustración. Elige uno de los controladores de cámara genérico ejemplo, inserte el script en tu página y disfrutar. Si necesita calcular parámetros de la cámara de medida, es probablemente mejor fuera aprendiendo sobre Quaternions, que no lo hice.

El camino plain-Jane trig te deja en un mundo de dolor. No tiene esencialmente útiles para depurar sus matemáticas, e incluso una vez que la matemática es correcta los resultados pueden mirar mal a causa de cosas como la "orden de Euler" (que se debe establecer a YXZ si desea que los controles de la cámara sienta como Pitch, Roll y Yaw... set camera.rotation.order = "YXZ";). Rotaciones de la cámara están en el sistema de coordenadas de la cámara, así que siempre tienes que recordar darle instrucciones camino o uso el hacky "objetivo" y "lookAt" estrategia (que) que invariablemente lleva a orientaciones totalmente chifladas... que es cuando empiezas a tener que configurar "para arriba" vector la cámara manualmente para mantenerlo hacia arriba y usted siempre debe estar pendiente de cosas como cerradura del cardán (donde pierde un grado de libertad debido a dos ejes paralelos en la cámara) y el hecho de que interpolación los * valores * de vectores de rotación de la cámara puede tomar correctamente de la A--> B en el espacio, pero a lo largo de la dirección de rotación errónea. Puede pensar que es natural de giro de 180 grados girando la cabeza hacia los lados, pero el camino más simple de rotación bien puede ser que va recto arriba en su lugar. Blech!

No voy a llevarte a través de las soluciones a todos esos problemas, y si te fijas bien encontrarás que mis soluciones son, en algunos lugares, un poco áspero. En cambio, voy a pegar todo el código de movimiento de la cámara junto con notas poco aquí sobre qué partes de él. Si usted está realmente zambullirse en una pieza y le gustaría una explicación más detallada, seguir adelante y publicar un comentario así puedo encarnar de esa parte.

Criterio de la cámara: destaca

-Poner una estrella seleccionada en el centro de la pantalla (zoomAndDollyToPoint)
-Poner una estrella seleccionada en el centro de la pantalla con el centro de la galaxia en el fondo para evitar que la navegación fuera del borde del universo (zoomToFitPointsFrom, CAMERA_RELATION. TOWARD_CENTER)
-Pasar de una estrella seleccionada a otro sin cambiar de ángulo de la cámara (strafeFromPointToPoint)
-Encontrar el ámbito delimitador para un grupo de estrellas y luego buscar una posición de la cámara que esas estrellas cabrían en la pantalla (zoomToFitPointsFrom, todos CAMERA_RELATIONs)
-Poner estrellas adyacentes en el mismo cluster en posiciones de pantalla cómodo en relación a un solo "seleccionado" estrellas en la constelación de un autor (showThreePointsNicely)
-Volver a una posición "inicial" (reset)
-Parametrización de una trayectoria para la cámara por lo que puede poco a poco volar a través de la galaxia en su propia cuando no asistió (esperar los 90 sin hacer clic para ver la animación de inicio)-- (beginAutomaticTravel y cameraSetupForParameter)

El código:

Galaxy.Settings = Galaxy.Settings || {}; Galaxy.CameraMotions = function(camera) {_.bindAll(this,'zoomToFitPointsFrom','startAnimation','endAnimation','cameraSetupForParameter','beginAutomaticTravel'); this.target = Galaxy.Settings.cameraDefaultTarget.clone(); this.camera = cámara; / / borrar esta propiedad finalmente this.firstClick = true; this.isAnimating = false;} Galaxy.CameraMotions.prototype = {constructor: Galaxy.CameraMotions, startAnimation: function() {/ / startAnimation se refiere a animaciones iniciada por el usuario. La animación por defecto debe quitarse si continua. this.endAutomaticTravel(); this.isAnimating = true; }, endAnimation: function() {this.isAnimating = false;}, zoomAndDollyToPoint: function(point,callback) {si (this.isAnimating === verdadero) volver; / / temporalmente: el primer clic se zoom y a bombardear después de que. Si (this.firstClick === false) {/ / this.strafeFromPointToPoint(this.target,point,callback); this.zoomToFitPointsFrom ([punto], este. CAMERA_RELATION. TOWARD_CENTER, callback); retorno; } this.firstClick = false; var que = esta, pointClone = point.clone(), cameraPath = this.cameraPathToPoint(this.camera.position.clone(), point.clone()), currentPosition = {ahora: 0}, duración = 1.3, upClone = Galaxy.Settings.cameraDefaultUp.clone(), targetCurrent = this.target.clone(); TweenMax.to (targetCurrent, duración/1.5 {x:pointClone.x, y:pointClone.y, z:pointClone.z}); TweenMax.to (currentPosition, duración, {ahora: 0.8, onUpdate: function() {var pos = cameraPath.getPoint(currentPosition.now); that.target = tres nuevos. Vector3(targetCurrent.x,targetCurrent.y,targetCurrent.z); that.Camera.position.set(pos.x,pos.y,pos.z); that.Camera.up.set(upClone.x,upClone.y,upClone.z); that.camera.lookAt(that.target); that.camera.updateProjectionMatrix(); }, onStart: that.startAnimation, onComplete: function() {that.endAnimation(); si (typeof callback === "función") callback();}}); }, cameraPathToPoint: function(fromPoint,toPoint) {var spline = tres nuevos. SplineCurve3 ([fromPoint, tres nuevos. Vector3 ((toPoint.x-fromPoint.x) * 0,5 + fromPoint.x, (toPoint.y-fromPoint.y) * 0,5 + fromPoint.y, (toPoint.z-fromPoint.z) * 0,7 + fromPoint.z), apunto]); volver la tira; }, strafeFromPointToPoint: function(fromPoint,toPoint,callback) {var dest = toPoint.clone(), actual = this.camera.position.clone(), duración = 0.5, que = esto; dest.sub(fromPoint.clone()); dest.add(current.clone()); / / console.log("\n\n",fromPoint,toPoint,current,dest); si (that.isAnimating === true) volver; TweenMax.to (this.camera.position,duration, {x: dest.x,y: dest.y, z: dest.z, onComplete: function() {that.endAnimation(); that.camera.lookAt(toPoint.clone()); that.target = toPoint.clone(); if (typeof callback === "función") callback();}, onStart: that.startAnimation})}, reset: function(callback) {var duración = 2, que = esto, Inicio = Galaxy.Settings.cameraDefaultPosition.clone(), centro = Galaxy.Settings.cameraDefaultTarget.clone(), upGoal = Galaxy.Settings.cameraDefaultUp.clone(), upCurrent = this.camera.up.clone(), targetCurrent = this.target.clone(), positionCurrent = this.camera.position.clone(); / / no hacer nada cuando nada es suficiente. La devolución de llamada no debe tener ningún retraso. Si (this.camera.up.equals(Galaxy.Settings.cameraDefaultUp) & & this.camera.position.equals(Galaxy.Settings.cameraDefaultPosition) & & this.target.equals(Galaxy.Settings.cameraDefaultTarget)) {duración = 0.1;} si (that.isAnimating === true) volver; TweenMax.to (upCurrent, duración/1.5, {x: upGoal.x,y: upGoal.y,z: upGoal.z}); TweenMax.to (targetCurrent, duración/1.5, {x: center.x,y: center.y, z: center.z}); TweenMax.to (positionCurrent, duración, {x: home.x,y: home.y, z: home.z,ease: Power1.easeInOut, onUpdate: function() {that.target = tres nuevos. Vector3(targetCurrent.x,targetCurrent.y,targetCurrent.z); that.Camera.position.set(positionCurrent.x,positionCurrent.y,positionCurrent.z); that.Camera.up.set (upCurrent.x,upCurrent.y,upCurrent.z); that.camera.lookAt(that.target.clone()); that.camera.updateProjectionMatrix(); }, onComplete: function() {that.endAnimation(); that.firstClick = true; if (typeof callback === "función") callback();}, onStart: that.startAnimation})}, CAMERA_RELATION: {arriba: 0, SAME_ANGLE: 1, TOWARD_CENTER: 2}, zoomToFitPointsFrom: function(pointList,cameraRelation,callback) {si (! _.has (_.values (esto. CAMERA_RELATION), cameraRelation)) {/ / console.log (_.values (esto. CAMERA_RELATION)); Console.error (cameraRelation + "no es uno de los RELATIVE_LOCATION"); retorno; } Si (this.isAnimating == true) volver; pointList asumida que ya está en coordenadas de mundo. Averiguar delimitador de la esfera, a continuación, mover la cámara con respecto a su centro var bSphere = tres nuevos. Esfera (tres nuevos. Vector3(0,0,0),5); bSphere.setFromPoints(pointList); a qué distancia tenemos que para esta esfera
? var targetDistance = (bSphere.radius / (Math.tan(Math.PI*this.camera.fov/360))), cameraPositionEnd, que =, duración = 1, = hasta this.camera.up.clone(), currentCameraPosition = this.camera.position.clone(); interruptor (cameraRelation) {caso 0: / / CAMERA_RELATION. ARRIBA cameraPositionEnd = bSphere.center.clone () Add (tres nuevos. Vector3(40,40,targetDistance)); rotura; caso 1: / / CAMERA_RELATION. SAME_ANGLE dollies la cámara de entrada/salida que estos puntos se convierten en visibles var centro = bSphere.center.clone(), currentPos = that.camera.position.clone(), finalViewAngle = currentPos.sub(center).setLength(targetDistance); cameraPositionEnd = bSphere.center.clone().add(finalViewAngle); para evitar atravesar el plano de fondo: cameraPositionEnd.z = Math.max(cameraPositionEnd.z,40); rotura; caso 2: / / CAMERA_RELATION. TOWARD_CENTER dibuja una línea desde el origen del mundo a través del punto central de la delimitación de la esfera, / / y pone la cámara en el extremo de un vector de dos veces esa longitud. cameraPositionEnd = bSphere.center.clone().multiplyScalar(2); Si cameraPositionEnd.setLength(125) (cameraPositionEnd.length() < 125); Es raro cuando la cámara consigue demasiado cerca a las estrellas en la rotura del media; } var cameraTargetCurrent = {x: this.target.x, y: this.target.y z: this.target.z}; var cameraTargetEnd = bSphere.center.clone(); that.logVec('up',that.camera.up.clone()); that.logVec('target',that.target.clone()); that.logVec('position',that.camera.position.clone()); TweenMax.to (cameraTargetCurrent, duración/1.5, {x: cameraTargetEnd.x,y: cameraTargetEnd.y, z: cameraTargetEnd.z}); NO cambie "up" de alto ángulo. Se pone chiflado y gira la cámara desagradable. Si (cameraRelation! == 0) {TweenMax.to (up, duración/1.5 {x: 0, y: 0, z: 1});} TweenMax.to (currentCameraPosition, duración, {x: cameraPositionEnd.x,y: cameraPositionEnd.y, cameraPositionEnd.z z:, onUpdate: function() {that.target = tres nuevos. Vector3(cameraTargetCurrent.x,cameraTargetCurrent.y,cameraTargetCurrent.z); that.Camera.position.set(currentCameraPosition.x,currentCameraPosition.y,currentCameraPosition.z); that.Camera.up.set (up.x,up.y,up.z); that.camera.lookAt(that.target.clone()); that.camera.updateProjectionMatrix(); }, onComplete: function() {/ / that.logVec('up',that.camera.up.clone()); / / that.logVec('target',that.target.clone()); / / that.logVec('position',that.camera.position.clone()); that.endAnimation(); if (typeof callback === "función") callback();}, onStart: that.startAnimation})}, showThreePointsNicely: función (pointList, callback) {/ / buscar una ubicación de la cámara y la rotación tal que aparece el primer punto hacia la parte inferior de la pantalla, y / o los otros dos aparecen y a la izquierda y derecha. O algo así. Si (this.isAnimating == true) volver; this.firstClick = false; Si (! _.isArray(pointList)) {throw new Error ("matriz de puntos para showThreePointsNicely");} else if (pointList.length! == 3) {/ / Mostrar sólo la primera de ellas. this.zoomAndDollyToPoint(pointList[0],callback); return;} var pointZero = pointList[0].clone(); mirar el mundo desde la perspectiva de la estrella que se centrarán: var viewFromPointZero = function(vector) {return vector.clone().sub(pointZero.clone());}; El vector "atraviesan" es un ángulo central entre las estrellas de izquierda y derecha que estamos tratando de hacer visible en pantalla, junto con el vector cero var bisectLocal = viewFromPointZero (pointList [1]) Add (viewFromPointZero (pointList[2])).multiplyScalar(0.5); La ruta lineal sería descrito como... var A = viewFromPointZero(pointList[1]); var B = viewFromPointZero(pointList[2]); var theta = Math.acos(A.clone().dot(B.clone()) / A.length() / B.length()); var distanceAwayBasedOnAngle = Math.min(Math.max(theta*2.5,2),4); var cameraEndPosition = pointZero.clone().sub(bisectLocal.clone().multiplyScalar(distanceAwayBasedOnAngle)); var cameraStartPosition = this.camera.position.clone(); var cameraPathMidpoint = cameraEndPosition.clone().add(cameraStartPosition.clone()).multiplyScalar(0.5); La trayectoria circular alrededor de punto medio de la trayectoria lineal, entonces sería: Radio var = cameraStartPosition.clone().sub(cameraPathMidpoint.clone()).length(); var que = esto; var worldPointOnCircularPath = function(t) {var x = radius * Math.cos(t); var y = radio * Math.sin(t); var vectorPointLocal = tres nuevos. Vector3(x,y,0); volver vectorPointLocal.add(cameraPathMidpoint.clone()); }; backsolve el ángulo de inicio de la trayectoria circular. Es la inversa de x=a+r*cos(theta) = > theta = acos((x-a)/r); var startPointRelativeToMidpoint = cameraStartPosition.clone().sub(cameraPathMidpoint.clone()); startAngle var = Math.atan(startPointRelativeToMidpoint.y/startPointRelativeToMidpoint.x); Es el ángulo de inicio o el ángulo final? Es uno o el otro, pero tenemos que saber que... Otro sea + PI si (worldPointOnCircularPath(startAngle).setZ(0).distanceTo(cameraStartPosition.clone().setZ(0)) > 100) {/ / tienes que comenzar a mitad de camino alrededor en lugar de otro. tal es el mundo de la inversa trigonométricas funciones startAngle += Math.PI;} parámetros var = {t: startAngle, z: cameraStartPosition.clone () .z}, duración = 2.0, hasta = that.camera.up.clone(); var pointZeroClone = pointZero.clone(); TweenMax.to (that.target,duration/1.5, {x: pointZeroClone.x,y: pointZeroClone.y,z: pointZeroClone.z}); TweenMax.to (up, duración/1.5 {x: 0, y: 0, z: 1}); TweenMax.to (parámetros, duración, {t: startAngle - Math.PI, z: cameraEndPosition.clone () .z, facilidad: Power1.easeOut, onUpdate: function() {var xyCurrent = worldPointOnCircularPath(parameters.t); that.camera.position.set(xyCurrent.x,xyCurrent.y,parameters.z); that.camera.up.set (up.x,up.y,up.z); that.camera.lookAt(that.target); that.camera.updateProjectionMatrix();}, onComplete: function() {that.endAnimation(); si (typeof callback === "función") callback();}, onStart: that.startAnimation}); }, / / La cámara puede también "viajar" en el modo desatendido. Este comportamiento requiere algo de código para definir paramétricamente y luego animar el camino complejo, / / pero es algo diferente en especie de los movimientos de cámara iniciada por el usuario descritos anteriormente. beginAutomaticTravel: function() {/ / esta función absolutamente positivamente debe comenzar desde las posiciones de casa cámara. / / console.log ('comenzando el recorrido automático de la cámara'); var obj = {cameraParameter: Math.PI/2}, ese = este, loopConstants = this.loopConstants(); this.reset(function() {eso .__automaticCameraAnimation = TweenMax.to (obj, loopConstants.duration, {cameraParameter: 5*Math.PI/2, onUpdate:function() {that.cameraSetupForParameter(obj.cameraParameter,loopConstants);}, facilidad: null, repita: -1 / / loop infinitamente});});}, loopConstants: function() {var galaxyLoopStart = tres nuevos. Vector3(200,0,15), targetLoopStart = tres nuevos. Vector3(200,200,5), upLoopStart = tres nuevos. Vector3(0,0,1); volver {duración: 400, / segundos galaxyLoopStart: galaxyLoopStart, targetLoopStart: targetLoopStart, upLoopStart: upLoopStart, galaxyLoopToHome: Galaxy.Settings.cameraDefaultPosition.clone().sub(galaxyLoopStart.clone()), targetLoopToHome: Galaxy.Settings.cameraDefaultTarget.clone().sub(targetLoopStart.clone()), upLoopToHome: Galaxy.Settings.cameraDefaultUp.clone().sub(upLoopStart.clone())}}, cameraSetupForParameter: function(cameraParameter,loopConstants) {var pos, lookAt = loopConstants.targetLoopStart.clone (), hasta = loopConstants.upLoopStart.clone(); if (cameraParameter < 2*Math.PI & & cameraParameter > Math.PI) {cameraParameter-= Math.PI; / / vaya un círculo completo alrededor de las galaxia pos = tres nuevos. Vector3(200*Math.cos(cameraParameter),200*Math.sin(cameraParameter),15); copia de var = pos.clone(); lookAt = tres nuevos. Vector3 (copy.x, copy.y + copy.x,5); } else {/ / después de pasar un círculo completo alrededor de la galaxia, animar a todas las características de la cámara a la posición "Inicio", luego repita de inicio var pathMultiplier = Math.sin (cameraParameter); / / bueno de 0 a PI. Fuera de dicho rango, esto va negativo y parece haywire. pos = loopConstants.galaxyLoopStart.clone().add(loopConstants.galaxyLoopToHome.clone().multiplyScalar(pathMultiplier)); lookAt = loopConstants.targetLoopStart.clone().add(loopConstants.targetLoopToHome.clone().multiplyScalar(pathMultiplier)); alto = loopConstants.upLoopStart.clone().add(loopConstants.upLoopToHome.clone().multiplyScalar(pathMultiplier)); } this.camera.position.set(pos.x,pos.y,pos.z); this.Camera.up.set(up.x,up.y,up.z); this.Target = lookAt; this.camera.lookAt(lookAt); this.camera.updateProjectionMatrix(); }, endAutomaticTravel: function() {si (este .__automaticCameraAnimation) {this.__automaticCameraAnimation.kill();}}, / / logVec de herramientas de depuración: function(message,vec) {console.log (mensaje + ":" + vec.x + "" + vec.y + "" + vec.z);}, addTestCubeAtPosition: function(position) {var cubo = tres nuevos. Malla (tres nuevos. CubeGeometry (5, 5, 5), tres nuevos. MeshNormalMaterial()); Cube.Position = position.clone(); Galaxy.Scene.add (cubo); } }

Artículos Relacionados

Cómo crear una cuenta de Instructables

Cómo crear una cuenta de Instructables

cómo a lo más grande desde la invención de gafas de TV!!Y todo lo que necesitas es:[] Un equipo de trabajo con conexión a internet (usas uno ahora mismo.)[] A versión reciente de Java (recomendado pero no necesario).[] Una versión reciente de Flash (
Ser artista en residencia en Instructables

Ser artista en residencia en Instructables

soy Samuel Bernier, conocido como Patenteux du Nord. Soy diseñador industrial, un fabricante, un granjero, un viajero y un trabajador. Pasé las últimas tres semanas en "artista en residencia". (Me encanta este título). Esto prácticamente signifi
El universo dentro de un mármol de impresión 3D

El universo dentro de un mármol de impresión 3D

Este instructivo le guiará por el proceso de partículas suspendidas en un mármol claro de la impresión en 3D. Incluye simulación de partículas, conversión de las partículas a polígonos, exportación de asambleas y la impresión de múltiples material.Qu
BRICOLAJE auto activado universo privado

BRICOLAJE auto activado universo privado

este es mi primer siempre Instructables subir así que por favor, ser amable conmigo.Hice esto para una pequeña galería en un ARI llamada a Constanza en Hobart, Tasmania, Australia y fue diseñado específicamente para ser activado cuando la gente mire
Últimos proyectos/Pre Instructables...

Últimos proyectos/Pre Instructables...

I wish I would have found Instructables two or three years ago. Pude haber contribuido un heck de mucho más. Con mi reciente movimiento inevitable que he decidido recopilar algunas imágenes de proyectos anteriores en mi casa actual y publicarlos.List
Doctor que tiempo Crack en el universo de luz de pared

Doctor que tiempo Crack en el universo de luz de pared

Si construir un TARDIS es demasiado intimidante para usted, ¿qué le parece lo mejor, tener una grieta en el tiempo y el espacio aparecen en su propia habitación? Este instructable le mostrará cómo hacer un facsímil razonable sin desatar las fuerzas p
Cómo: construir tu propio universo

Cómo: construir tu propio universo

Este instructable es un ejercicio rápido para iniciarte en el negocio de la construcción del universo.Materiales necesarios:-tiempo (s)-espacio (m)Paso 1: Definir el espacio-tiempoPrimero tendrá que definir la relación entre espacio y tiempo con una
Simulación del universo en su ordenador portátil

Simulación del universo en su ordenador portátil

Hey!Bienvenido a este impresionante instructable donde vamos a hacer una simulación desde el principio del universo en su ordenador portátil simple. El programa que uso es Adobe After Effects, y fácilmente puede descargar la versión gratuita de la mi
Sobrevivir en el salvaje, el más singular instructable hasta la fecha

Sobrevivir en el salvaje, el más singular instructable hasta la fecha

sólo han despertado para encontrarse en el suelo en la naturaleza.  Antes de levantarse de la posición supina te das cuenta de que, además de no estar en su propia cama caliente, ha despertado en la maleza debajo del dosel de lo que tal vez un bosque
Cadena de instructables increíble arte de la pared

Cadena de instructables increíble arte de la pared

Mi nombre es Ashish Kumar y este es mi primer proyecto de la cadena. Espero que todos ustedes como este.Material utilizadoLos siguientes son el material utilizado para la construcción de este logotipo:1.String.2 papeles (para la impresión de la insig
Ganchillo gorro cuadrado - Robot Instructable, esponja Bob y WALL-E

Ganchillo gorro cuadrado - Robot Instructable, esponja Bob y WALL-E

Uno de los proyectos que ha estado nadando alrededor en mi cabeza fue este sombrero estilo "cuadrado", también llamado un sombrero de bufón. No pude resistirme a participar en el concurso de Robot Instructable así este Instructable es un product
Cruz Instructables Robot

Cruz Instructables Robot

Fijé una solicitud en este tema del foro para el concurso de robot de Instructables! Aunque no obtengo ninguna respuesta pero estaba realmente sorprendido y emocionado cuando una sierra Instructables ha lanzado finalmente 'Instructables robot concurs
Instructable vistas y favoritos comprobador automatizado

Instructable vistas y favoritos comprobador automatizado

Como un usuario de Instructables, en algún momento pensé en tener una simple herramienta automática que puede consultar las opiniones y favoritos de mi Instrucatbles de Instructables.com sitio sin mi realidad buscando en la aplicación.Instructable vi
Oficial Robot de Instructables de Papercraft!

Oficial Robot de Instructables de Papercraft!

¡ Felicidades! Han decidido entrar en el fabuloso mundo de oficial Instructables Robot manualidades en papel. Con pocos suministros (esperemos) tiene alrededor de la casa, se puede construir un compañero de escritorio, un guardián del televisor remot