tipos teoria tecnico sistemas que proyecciones proyeccion planos plano las hacer geometricas dibujo como angulos c# java math 3d projection

c# - sistemas - teoria de las proyecciones dibujo tecnico



Proyección básica en 3D de proyección en perspectiva en una pantalla 2D con cámara(sin OpenGL) (8)

Digamos que tengo una estructura de datos como la siguiente:

Camera { double x, y, z /** ideally the camera angle is positioned to aim at the 0,0,0 point */ double angleX, angleY, angleZ; } SomePointIn3DSpace { double x, y, z } ScreenData { /** Convert from some point 3d space to 2d space, end up with x, y */ int x_screenPositionOfPt, y_screenPositionOfPt double zFar = 100; int width=640, height=480 }

...

Sin recorte de pantalla ni mucho más, ¿cómo podría calcular la posición x, y de la pantalla de algún punto dado algún punto 3d en el espacio? Quiero proyectar ese punto 3d en la pantalla 2d.

Camera.x = 0 Camera.y = 10; Camera.z = -10; /** ideally, I want the camera to point at the ground at 3d space 0,0,0 */ Camera.angleX = ???; Camera.angleY = ???? Camera.angleZ = ????; SomePointIn3DSpace.x = 5; SomePointIn3DSpace.y = 5; SomePointIn3DSpace.z = 5;

ScreenData.x y y es la posición x de la pantalla del punto 3d en el espacio. ¿Cómo calculo esos valores?

Posiblemente podría usar las ecuaciones que se encuentran aquí, pero no entiendo cómo el ancho / alto de la pantalla entra en juego. Además, no entiendo en la entrada wiki cuál es la posición del espectador frente a la posición de la cámara.

http://en.wikipedia.org/wiki/3D_projection


Ejecutar a través de un trazador de rayos:

Ray Tracer en C # - Algunos de los objetos que tiene le resultarán familiares ;-)

Y solo por patadas una versión LINQ .

No estoy seguro de cuál es el propósito principal de su aplicación (debería decirnos, podría generar mejores ideas), pero si bien está claro que la proyección y el trazado de rayos son conjuntos de problemas diferentes, tienen un montón de superposición.

Si tu aplicación solo está tratando de dibujar toda la escena, esto sería genial.

Resolviendo el problema # 1 : los puntos oscuros no serán proyectados.
Solución : Aunque no vi nada sobre la opacidad o la transparencia en la página del blog, probablemente podría agregar estas propiedades y código para procesar un rayo que rebotó (como siempre) y otro que continuó (para la "transparencia").

Solución del problema nº 2 : la proyección de un solo píxel requerirá un seguimiento costoso de la imagen completa de todos los píxeles .
Obviamente, si solo quieres dibujar los objetos, ¡usa el trazador de rayos para lo que es! Pero si desea buscar miles de píxeles en la imagen, desde partes aleatorias de objetos aleatorios (¿por qué?), Hacer un seguimiento completo de rayos para cada solicitud sería un gran perro de rendimiento.

Afortunadamente, con más ajustes en su código, es posible que pueda hacer un trazado de rayos al frente (con transparencia) y almacenar en caché los resultados hasta que los objetos cambien.

Si no está familiarizado con el trazado de rayos, lea la entrada del blog. Creo que explica cómo las cosas realmente funcionan hacia atrás desde cada píxel 2D, a los objetos, luego a las luces, lo que determina el valor del píxel.

Puede agregar código para que se realicen intersecciones con los objetos; está creando listas indexadas por puntos intersecados de los objetos, y el elemento es el píxel 2d actual que se está rastreando.

Luego, cuando desee proyectar un punto, vaya a la lista de ese objeto, busque el punto más cercano al que desea proyectar y busque el píxel 2D que le interesa. Las matemáticas serían mucho más mínimas que las ecuaciones de tus artículos. Desafortunadamente, al utilizar, por ejemplo, un diccionario de su estructura de objetos y puntos que se asigna a 2d píxeles, no estoy seguro de cómo encontrar el punto más cercano en un objeto sin recorrer toda la lista de puntos asignados. Aunque eso no sería la cosa más lenta del mundo y probablemente podrías resolverlo, simplemente no tengo tiempo para pensar en ello. ¿Nadie?

¡buena suerte!

" Además, no entiendo en la entrada del wiki cuál es la posición del espectador frente a la posición de la cámara " ... estoy 99% seguro de que esto es lo mismo.


@BerlinBrown solo como un comentario general, no debe almacenar la rotación de su cámara como los ángulos X, Y, Z, ya que esto puede llevar a una ambigüedad.

Por ejemplo, x = 60 grados es lo mismo que -300 grados. Cuando se usa x, y, z, el número de posibilidades ambiguas es muy alto.

En su lugar, intente usar dos puntos en el espacio 3D, x1, y1, z1 para la ubicación de la cámara y x2, y2, z2 para la cámara "objetivo". Los ángulos se pueden calcular hacia atrás desde / hacia la ubicación / objetivo, pero en mi opinión no se recomienda. El uso de una ubicación / objetivo de la cámara le permite construir un vector "LookAt" que es un vector unitario en la dirección de la cámara (v ''). A partir de esto, también puede construir una matriz LookAt, que es una matriz 4x4 utilizada para proyectar objetos en el espacio 3D a píxeles en el espacio 2D.

Por favor vea esta pregunta relacionada , donde discuto cómo calcular un vector R, que está en el plano ortogonal a la cámara.

Dado un vector de tu cámara para apuntar, v = xi, yj, zk
Normaliza el vector, v ''= xi, yj, zk / sqrt (xi ^ 2 + yj ^ 2 + zk ^ 2)
Sea U = mundo global hasta vector u = 0, 0, 1
Luego podemos calcular R = Vector horizontal que es paralelo a la dirección de vista de la cámara R = v ''^ U,
donde ^ es el producto cruzado, dado por
a ^ b = (a2b3 - a3b2) i + (a3b1 - a1b3) j + (a1b2 - a2b1) k

Esto te dará un vector que se ve así.

Esto podría ser útil para su pregunta, ya que una vez que tenga LookAt Vector v '', el vector ortogonal R puede comenzar a proyectar desde el punto en el espacio 3D al plano de la cámara.

Básicamente, todos estos problemas de manipulación 3D se reducen a la transformación de un punto en el espacio mundial al espacio local, donde los ejes x, y, z locales están orientados con la cámara. ¿Tiene sentido? Entonces, si tiene un punto, Q = x, y, z, y conoce R y v ''(ejes de cámara), entonces puede proyectarlo a la "pantalla" utilizando simples manipulaciones de vectores. Los ángulos involucrados se pueden encontrar utilizando el operador de producto punto en Vectores.


Desea transformar su escena con una matriz similar a gluLookAt de OpenGL y luego calcular la proyección utilizando una matriz de proyección similar a gluPerspective de OpenGL.

Podrías intentar simplemente calcular las matrices y hacer la multiplicación en el software.


La "manera en que se hace" es usar transformaciones y coordenadas homogéneas. Tomas un punto en el espacio y:

  • Colóquelo en relación con la cámara utilizando la matriz del modelo.
  • Proyecte ortográficamente o en perspectiva usando la matriz de proyección.
  • Aplique la información de la ventana gráfica para colocarlo en la pantalla.

Esto se vuelve bastante vago, pero trataré de cubrir las partes importantes y dejaré algo para ti. Supongo que entiendes lo básico de las matrices matematicas :).

Vectores homogéneos, puntos, transformaciones.

En 3D, un punto homogéneo sería una matriz de columnas de la forma [x, y, z, 1]. El componente final es ''w'', un factor de escala, que para los vectores es 0: esto tiene el efecto de que no se pueden traducir vectores, que es matemáticamente correcto. No iremos allí, estamos hablando de puntos.

Las transformaciones homogéneas son matrices 4x4, utilizadas porque permiten que la traducción se represente como una multiplicación de matrices, en lugar de una adición, lo que es agradable y rápido para su tarjeta de video. También es conveniente porque podemos representar transformaciones sucesivas multiplicándolas juntas. Aplicamos transformaciones a los puntos realizando la transformación * punto.

Hay 3 transformaciones homogéneas primarias:

Hay otros, en particular la transformación ''mirar'', que vale la pena explorar. Sin embargo, solo quería dar una breve lista y algunos enlaces. La aplicación sucesiva de movimiento, escalado y rotación aplicada a puntos es colectivamente la matriz de transformación del modelo, y los coloca en la escena, en relación con la cámara. Es importante darse cuenta de que lo que estamos haciendo es similar a mover objetos alrededor de la cámara, no al revés.

Ortogonal y perspectiva

Para transformar las coordenadas mundiales en coordenadas de pantalla, primero debe usar una matriz de proyección, que comúnmente viene en dos sabores:

  • Ortográfico, comúnmente utilizado para 2D y CAD.
  • Perspectiva, buena para juegos y entornos 3D.

Una matriz de proyección ortográfica se construye de la siguiente manera:

Donde los parámetros incluyen:

  • Superior : la coordenada Y del borde superior del espacio visible.
  • Inferior : la coordenada Y del borde inferior del espacio visible.
  • Izquierda : la coordenada X del borde izquierdo del espacio visible.
  • Derecha : la coordenada X del borde derecho del espacio visible.

Creo que eso es bastante simple. Lo que establece es un área de espacio que aparecerá en la pantalla, con la que puede recortar. Es simple aquí, porque el área del espacio visible es un rectángulo. Recortar en perspectiva es más complicado porque el área que aparece en la pantalla o el volumen de visualización es un frustrum .

Si está teniendo dificultades con la wikipedia en proyección en perspectiva, aquí está el código para construir una matriz adecuada, cortesía de geeks3D

void BuildPerspProjMat(float *m, float fov, float aspect, float znear, float zfar) { float xymax = znear * tan(fov * PI_OVER_360); float ymin = -xymax; float xmin = -xymax; float width = xymax - xmin; float height = xymax - ymin; float depth = zfar - znear; float q = -(zfar + znear) / depth; float qn = -2 * (zfar * znear) / depth; float w = 2 * znear / width; w = w / aspect; float h = 2 * znear / height; m[0] = w; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = h; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = q; m[11] = -1; m[12] = 0; m[13] = 0; m[14] = qn; m[15] = 0; }

Las variables son:

  • fov : Campo de visión, pi / 4 radianes es un buen valor.
  • Aspecto : Relación entre altura y anchura.
  • znear, zfar : usado para recortar, ignoraré estos.

y la matriz generada es la columna principal, indexada de la siguiente manera en el código anterior:

0 4 8 12 1 5 9 13 2 6 10 14 3 7 11 15

Transformación de la ventana gráfica, coordenadas de pantalla

Ambas transformaciones requieren otra matriz de matriz para poner las cosas en las coordenadas de la pantalla, llamada transformación de la ventana gráfica. Eso se describe aquí, no lo cubriré (es muy simple) .

Así, para un punto p, deberíamos:

  • Realice la matriz de transformación del modelo * p, resultando en pm.
  • Realizar la matriz de proyección * pm, resultando en pp.
  • Clipping pp contra el volumen de visualización.
  • Realice la matriz de transformación de la ventana gráfica * pp, lo que resulta es ps: point on screen.

Resumen

Espero que eso cubra la mayor parte. Hay agujeros en lo anterior y es vago en algunos lugares, publique cualquier pregunta a continuación. Este tema suele ser digno de un capítulo entero en un libro de texto. He hecho todo lo posible por resumir el proceso, ¡y espero que para su ventaja!

He vinculado a esto anteriormente, pero le sugiero que lea esto y descargue el binario. Es una excelente herramienta para mejorar su comprensión de estas transformaciones y cómo obtiene puntos en la pantalla:

http://www.songho.ca/opengl/gl_transform.html

En cuanto al trabajo real, deberá implementar una clase de matriz 4x4 para transformaciones homogéneas, así como una clase de puntos homogénea que puede multiplicar en su contra para aplicar transformaciones (recuerde, [x, y, z, 1]). Tendrá que generar las transformaciones como se describe anteriormente y en los enlaces. No es tan difícil una vez que entiendes el procedimiento. La mejor de las suertes :).


La conversión de puntos en el espacio 3D en un punto 2D en una pantalla se realiza simplemente mediante el uso de una matrix . Utilice una matriz para calcular la posición de la pantalla de su punto, esto le ahorra mucho trabajo.

Cuando trabaje con cámaras, debe considerar usar una look-at-matrix mirada y multiplicar la matriz de proyección con su matriz de proyección.


Quizás te interese solo ver cómo GLUT lo hace entre bastidores. Todos estos métodos tienen documentación similar que muestra las matemáticas que se incluyen en ellos.

Las tres primeras conferencias de UCSD podrían ser muy útiles y contener varias ilustraciones sobre este tema, que, por lo que puedo ver, es lo que realmente busca.


Siguiendo la wikipedia, primero calcule "d":

http://upload.wikimedia.org/wikipedia/en/math/6/0/b/60b64ec331ba2493a2b93e8829e864b6.png

Para hacer esto, construye esas matrices en tu código. Las asignaciones de sus ejemplos a sus variables:

θ = Camera.angle*

a = SomePointIn3DSpace

c = Camera.x | y | z Camera.x | y | z

O simplemente haga las ecuaciones por separado sin usar matrices, su elección:

http://upload.wikimedia.org/wikipedia/en/math/1/c/8/1c89722619b756d05adb4ea38ee6f62b.png

Ahora calculamos "b", un punto 2D:

http://upload.wikimedia.org/wikipedia/en/math/2/5/6/256a0e12b8e6cc7cd71fa9495c0c3668.png

En este caso, ex y ey son la posición del espectador, creo que en la mayoría de los sistemas de gráficos, la mitad del tamaño de la pantalla (0.5) se utiliza para hacer (0, 0) el centro de la pantalla de forma predeterminada, pero puede usar cualquier valor (jugar alrededor ). ez es donde el campo de visión entra en juego. Esa es la única cosa que te estabas perdiendo. Elija un ángulo fov y calcule ez como:

ez = 1 / tan (fov / 2)

Finalmente, para obtener bx y por píxeles reales, tiene que escalar por un factor relacionado con el tamaño de la pantalla. Por ejemplo, si b se asigna de (0, 0) a (1, 1), podría escalar x en 1920 e y en 1080 para una pantalla de 1920 x 1080. De esa forma cualquier tamaño de pantalla mostrará lo mismo. Por supuesto, hay muchos otros factores involucrados en un sistema de gráficos 3D real, pero esta es la versión básica.


Suponiendo que la cámara está en (0, 0, 0) y apuntada hacia adelante, las ecuaciones serían:

ScreenData.x = SomePointIn3DSpace.x / SomePointIn3DSpace.z * constant; ScreenData.y = SomePointIn3DSpace.y / SomePointIn3DSpace.z * constant;

donde "constante" es algún valor positivo. Establecerlo en el ancho de la pantalla en píxeles generalmente da buenos resultados. Si lo configura más alto, la escena se verá más "ampliada" y viceversa.

Si desea que la cámara se encuentre en una posición o ángulo diferente, deberá mover y rotar la escena para que la cámara se encuentre en (0, 0, 0) y apunte hacia adelante, y luego puede usar las ecuaciones de arriba. .

Básicamente, está calculando el punto de intersección entre una línea que atraviesa la cámara y el punto 3D, y un plano vertical que flota un poco frente a la cámara.