¿Alguien tiene un algoritmo para crear una esfera de procedimiento con la
cantidad de líneas de latitud, lo
cantidad de líneas de longitud y un radio de r
? Lo necesito para trabajar con Unity, por lo que las posiciones de los vértices necesitan ser definidas y luego, los triángulos definidos a través de índices ( más información ).
EDITAR
Logré que el código funcionara en unidad. Pero creo que podría haber hecho algo mal. Cuando enciendo detailLevel
, Todo lo que hace es agregar más vértices y polígonos sin moverlos. ¿Olvidé algo?
EDITAR 2
Traté de escalar la malla a lo largo de sus niveles normales. Esto es lo que conseguí. Creo que me estoy perdiendo algo. ¿Se supone que debo escalar solo ciertas normales?
unity
procedural-generation
3d-meshes
Daniel Pendergast
fuente
fuente
vertices[i] = normalize(vertices[i])
. Por cierto, esto también le da sus nuevas y correctas normales, por lo que debe hacernormals[i] = vertices[i]
después.Respuestas:
Para obtener algo como esto:
Cree un icosaedro (sólido regular de 20 lados) y subdivida las caras para obtener una esfera (vea el código a continuación).
La idea es básicamente:
Subdivida cada cara en cuatro caras del mismo tamaño. Cada vez que haces esto, cuadruplicará el número de caras en el modelo.
i0
,i1
yi2
son los vértices del triángulo original. (En realidad, los índices en el búfer de vértices, pero ese es otro tema).m01
es el punto medio del borde(i0,i1)
, m12 es el punto medio del borde(i1,12)
ym02
es, obviamente, el punto medio del borde(i0,i2)
.Siempre que subdivida una cara, asegúrese de no crear vértices duplicados. Cada punto medio será compartido por otra cara de origen (ya que los bordes se comparten entre caras). El código siguiente lo explica manteniendo un diccionario de puntos medios nombrados que se han creado y devolviendo el índice de un punto medio creado previamente cuando está disponible en lugar de crear uno nuevo.
Repita hasta que haya alcanzado el número deseado de caras para su cubo.
Cuando termines, normaliza todos los vértices para suavizar la superficie. Si no haces esto, obtendrás un icosaedro de mayor resolución en lugar de una esfera.
Voila! Ya terminaste Convertir los tampones de vector y el índice resultante en una
VertexBuffer
yIndexBuffer
, y dibujar conDevice.DrawIndexedPrimitives()
.Esto es lo que usaría en su clase "Esfera" para crear el modelo (tipos de datos XNA y C #, pero debería ser bastante claro):
Y la
GeometryProvider
clasefuente
int
matriz? ¿Y qué hace el.Select(i => i + vertices.Count)
?.Select(i => i + vertices.Count)
no funciona para mí en absoluto. ¿Es una característica única de XNA?Consideremos la definición paramétrica de una esfera:
donde theta y phi son dos ángulos incrementales, a los que nos referiremos como
var t
yvar u
y Rx, Ry y Rz son los radios independientes (radios) en las tres direcciones cartesianas, que, en el caso de una esfera, se definirán como una sola radiovar rad
.Consideremos ahora el hecho de que el
...
símbolo indica una iteración que sugiere el uso de un bucle. El concepto destacks
yrows
es "cuántas veces iterará". Como cada iteración agrega el valor de to u, cuanto más iteraciones, menor es el valor, por lo tanto, más precisa es la curvatura de la esfera.El 'dibujo esfera' condición previa de la función es tener los siguientes parámetros dados:
int latitudes, int longitudes, float radius
. Las condiciones de publicación (salida) son devolver o aplicar los vértices calculados. Dependiendo de cómo intente usar esto, la función podría devolver una matriz devector3
(vectores tridimensionales) o, si está utilizando algún tipo de OpenGL simple, antes de la versión 2.0, es posible que desee aplicar los vértices directamente al contexto.NB Aplicar un vértice en openGL es llamar a la siguiente función
glVertex3f(x, y, z)
. En el caso en el que almacenaríamos los vértices, agregaríamos uno nuevovector3(x, y, z)
para facilitar el almacenamiento.Además, la forma en que solicitó que funcionara el sistema de latitud y longitud necesitaba un ajuste en la definición de la esfera (básicamente cambiando z e y), pero esto solo muestra que la definición es muy maleable y que usted es libre de cambiar Parámetros x, y y z para alterar la dirección en la que se dibuja la esfera (donde están las latitudes y longitudes).
Ahora veamos cómo vamos a hacer las latitudes y longitudes. Las latitudes están representadas por la variable
u
, iteran de 0 a 2π radianes (360 grados). Por lo tanto, podemos codificar su iteración así:Ahora las longitudes están representadas por la variable
t
e iteran de 0 a π (180 grados). por lo tanto, el siguiente código es similar al anterior:(Tenga en cuenta que los bucles son Incluido de ahí condición terminal, ya que el intervalo de integración paramétrica es de 0 a 2p Incluido . Obtendrá una esfera parcial si sus condiciones son no incluido).
Ahora, siguiendo la definición simple de la esfera, podemos derivar la definición variable de la siguiente manera (supongamos
float rad = radius;
):¡Una advertencia más importante! En la mayoría de los casos, usará alguna forma de OpenGL, e incluso si no es así, es posible que aún deba hacerlo. Un objeto en tres dimensiones necesita varios vértices para ser definido. Esto generalmente se logra al proporcionar el siguiente vértice que es computable.
Exactamente cómo en la figura de arriba son las diferentes coordenadas
x+∂
yy+∂
, podemos generar fácilmente otros tres vértices para cualquier uso deseado. Los otros vértices son (supongamosfloat rad = radius;
):Finalmente, aquí hay una función completa que devolvería todos los vértices de una esfera, y la segunda muestra una implementación de OpenGL del código (esta es una sintaxis de estilo C y no JavaScript, esto debería funcionar con todos los lenguajes de estilo C, incluido C # cuando se usa Unity).
Código OpenGL:
PD: Puede que hayas notado esta afirmación
rad = radius;
. Esto permite que el radio se modifique en el bucle, en función de la ubicación o el ángulo. Esto significa que puede aplicar ruido a la esfera para endurecerla, haciendo que parezca más natural si el efecto deseado es similar al de un planeta. P.ejfloat rad = radius * noise[x][y][z];
Claude-Henry.
fuente
rad
. Ahora estás haciendo esa pata de un triángulo, e implicando que la hipotenusa de dicho triángulo también lo esrad
. Esto efectivamente le da un radio derad * sqrt(2)
.Creé algo como esto hace un tiempo para hacer una esfera de cubos, por diversión y ciencia. No es muy dificil. Básicamente, tomas una función que crea un círculo de vértices, luego pasas por los incrementos de altura que deseas crear círculos a cada altura en el radio requerido para hacer una esfera. Aquí he modificado el código para que no sea para cubos:
Ahora este código solo crearía puntos para la latitud. Sin embargo, casi puede usar el mismo código para hacer las líneas de longitud. Excepto que deberá rotar entre cada iteración y hacer un círculo completo en cada una
degreeStep
.Lo sentimos, esta no es una respuesta completa o específica de Unity, pero espero que te ayude a comenzar.
fuente
¿No podría simplemente comenzar con una forma simple, podría ser una caja con una distancia de r desde el centro a la esquina? Para hacer una esfera más detallada, subdivida todos los polígonos y luego mueva los vértices a una distancia r del centro, haciendo que el vector pase por su posición actual.
Sigue repitiendo hasta que sea lo suficientemente esférico para tus gustos.
fuente
¿Realmente necesitas la geometría 3D o solo la forma?
Puedes hacer una esfera 'falsa' usando un solo quad. Simplemente ponga un círculo sobre él y sombree correctamente. Esto tiene la ventaja de que tendrá exactamente la resolución requerida, independientemente de la distancia a la cámara o la resolución.
Hay un tutorial aquí .
fuente
Aquí hay un código para cualquier número de vértices igualmente espaciados de una esfera, es como una cáscara de naranja que enrolla una línea de puntos alrededor de una esfera en espiral. luego, cómo unir los vértices depende de usted. puedes usar puntos vecinos en el bucle como 2 de cada triángulo y luego encontrar que el tercero sería un giro proporcional alrededor de la esfera más arriba o más abajo ... también puedes hacer triángulos por bucle y el vecino más cercano en él, alguien conoce una mejor manera?
};
fuente
Aunque David es absolutamente correcto en su respuesta, quiero ofrecer una perspectiva diferente.
Para mi tarea de generación de contenido procesal, miré (entre otras cosas) icosaedro versus esferas subdivididas más tradicionales. Mire estas esferas generadas procesalmente:
Ambas parecen esferas perfectamente válidas, ¿verdad? Bueno, echemos un vistazo a sus wireframes:
Wow, ¿qué pasó allí? ¡La versión de estructura metálica de la segunda esfera es tan densa que parece texturizada! Te contaré un secreto: la segunda versión es un icosaedro. Es una esfera casi perfecta, pero tiene un alto precio.
La Esfera 1 usa 31 subdivisiones en el eje xy 31 subdivisiones en el eje z, para un total de 3,844 caras.
La Esfera 2 usa 5 subdivisiones recursivas, para un total de 109,220 caras.
Pero bueno, eso no es realmente justo. Reduzcamos la calidad considerablemente:
La esfera 1 usa 5 subdivisiones en el eje xy 5 subdivisiones en el eje z, para un total de 100 caras.
La Esfera 2 usa 0 subdivisiones recursivas, para un total de 100 caras.
Usan la misma cantidad de caras, pero en mi opinión, la esfera de la izquierda se ve mejor. Se ve menos grumoso y mucho más redondo. Echemos un vistazo a cuántas caras generamos con ambos métodos.
Icosaedro
Esfera subdividida:
Como puede ver, el icosaedro aumenta en caras a una tasa exponencial, ¡a una tercera potencia! Eso es porque para cada triángulo, debemos subdividirlos en tres triángulos nuevos.
La verdad es que no necesitas la precisión que te dará un icosaedro. Porque ambos esconden un problema mucho más difícil: texturizar un plano 2D en una esfera 3D. Así es como se ve la parte superior:
En la esquina superior izquierda, puede ver la textura que se está utilizando. Casualmente, también se está generando procesalmente. (Oye, fue un curso sobre generación de procedimientos, ¿verdad?)
Se ve terrible, ¿verdad? Bueno, esto es tan bueno como va a ser. Obtuve las mejores calificaciones para mi mapeo de texturas, porque la mayoría de las personas ni siquiera lo hacen bien.
Entonces, por favor, considere usar coseno y seno para generar una esfera. Genera muchas menos caras para la misma cantidad de detalles.
fuente
N
partes te daráN*N
nuevos triángulos, que son cuadráticos, exactamente como lo que haces con la esfera UV.El siguiente script creará un Icosaedro con n Polígonos ... base 12. También subdividirá los polígonos en mallas separadas y calculará el total de verts-duplicados y polígonos.
No pude encontrar nada similar, así que creé esto. Simplemente adjunte la secuencia de comandos a un GameObject y configure las subdivisiones en el Editor. Trabajando en la modificación de ruido a continuación.
fuente