¿Cómo hacer que las líneas de Renderizador de línea permanezcan planas?

10

Me di cuenta de que a medida que agrego más vértices a una línea de Renderizador de línea, la línea se retuerce y deja de ser una línea suave.

ingrese la descripción de la imagen aquí

.GIF aquí: http://i.imgur.com/hRAhCXM.gif

Todas las líneas están en el mismo nivel z, incluso si elimino los materiales, las líneas todavía parecen torcerse.

No tengo idea de por qué hace esto, o cómo solucionarlo, ¿alguna sugerencia? C #

Douglas Gaskell
fuente
Este es un problema con el algoritmo que utiliza LineRenderer para posicionar sus vértices, que se ocupa mal de las esquinas afiladas. Puede mejorarlo un poco agregando más puntos para redondear las esquinas, pero el método más robusto que he encontrado es duplicar su funcionalidad con un mejor algoritmo, creando una malla dinámica con los vértices que necesita, o creativamente explotar un ParticleSystem para dibujar la cadena de puntos.
DMGregory
1
Actualización: las versiones posteriores de Unity (5 5+) han mejorado el algoritmo LineRenderer , por lo que los usuarios que consideran usar LineRenderers pueden encontrar que el resultado inmediato es sustancialmente mejor en estos días.
DMGregory

Respuestas:

11

El problema es básicamente esto:

ingrese la descripción de la imagen aquí

LineRenderer está intentando conectar las posiciones de los puntos rojos. Está creando los vértices verdes para hacer una malla. Entonces, el segmento de la línea superior se ve muy bien. Pero entonces el LineRenderer intenta ser económico, reutiliza los vértices desde el final de un segmento de línea en el final del segundo segmento de línea. Cuando hay un ángulo agudo, obtienes el problema que estás viendo. El segundo segmento de línea se pellizca en la intersección porque su 'tapa final' no es perpendicular con su otra 'tapa final'.

La solución es crear su propio renderizador de línea y no hacerlo tan económico. Puede hacer esto generando una malla dinámica . La malla consistirá en una serie de quads delgados. Para cada segmento de línea, puede calcular las cuatro esquinas del quad calculando la normalidad de la línea y un ancho de línea específico:

Vector3 normal = Vector3.Cross(start, end);
Vector3 side = Vector3.Cross(normal, end-start);
side.Normalize();
Vector3 a = start + side * (lineWidth / 2);
Vector3 b = start + side * (lineWidth / -2);
Vector3 c = end + side * (lineWidth / 2);
Vector3 d = end + side * (lineWidth / -2);

Aquí, a, b, cy dcompensar las cuatro esquinas de un solo segmento de línea, al igual que los puntos verdes en la imagen de arriba. Estos vértices se agregarían a la malla, y también agregaría los índices para convertir los cuatro vértices en dos triángulos (por lo tanto, se agregarían seis índices, abc y bdc).

Obviamente, esto puede ser bastante complejo. Creo que otra razón por la que Unity implementó su LineRenderer de la manera en que lo hicieron fue porque hacerlo de esa manera evita otro problema, las esquinas. Cuando comience a dibujar cada segmento de línea, comenzará a ver dónde se unen los dos segmentos de línea y forman una junta fea. Hay maneras de lidiar con esto calculando la normal compartida entre ambas líneas y actualizando sus vértices a la normal compartida, pero esto solo resuelve parcialmente el problema, ya que aún puede terminar fácilmente con líneas pinzadas. La solución más robusta es generar vértices adicionales en las juntas para actuar como esquinas.

MichaelHouse
fuente
1
Probablemente también pueda salirse con la suya utilizando el renderizador de línea de unidad e insertando puntos adicionales para crear un pequeño inglete. Simplemente ponga un punto un poco hacia el siguiente punto desde el punto anterior.
mklingen
Gran explicación Byte, gracias. Probablemente intentaré ver si no puedo generar más puntos en cada una de las esquinas, si eso no funciona bien, seguiré adelante e intentaré hacer una malla dinámica. Gracias.
Douglas Gaskell
1

Tuve el mismo problema y lo solucioné agregando más puntos a los bordes lisos, no es una solución elegante, pero es simple y funciona. Al menos para mi. Escribí una función para hacer esto:

Vector3[] Generate_Points(Vector3[] keyPoints, int segments=100){
    Vector3[] Points = new Vector3[(keyPoints.Length - 1) * segments + keyPoints.Length];
    for(int i = 1; i < keyPoints.Length;i++){
        Points [(i - 1) * segments + i - 1] = new Vector3(keyPoints [i-1].x,keyPoints [i-1].y,0);
        for (int j = 1;j<=segments;j++){
            float x = keyPoints [i - 1].x;
            float y = keyPoints [i - 1].y;
            float z = 0;//keyPoints [i - 1].z;
            float dx = (keyPoints [i].x - keyPoints [i - 1].x)/segments;
            float dy = (keyPoints [i].y - keyPoints [i - 1].y)/segments;
            Points [(i - 1) * segments + j + i - 1] = new Vector3 (x+dx*j,y+dy*j,z);
        }
    }
    Points [(keyPoints.Length - 1) * segments + keyPoints.Length - 1] = new Vector3(keyPoints [keyPoints.Length-1].x,keyPoints [keyPoints.Length-1].y,0);
    return Points;
}
Miguel Ángel Llorente
fuente
0

Una forma de resolver esto para las líneas opacas es representar un círculo en cada unión. El círculo debe tener un diámetro igual al ancho de la línea. Esto requiere algunos vértices adicionales para ser renderizado, pero se ve muy bien. También puede deshacerse de las normales compartidas entre las articulaciones.

Esto aún requiere que escriba su propio código de representación en lugar de usar el Unity Line Renderer.

Hice un activo que hace precisamente esto en http://u3d.as/nFE

jjxtra
fuente
0

La forma en que evité esto es que siempre establezco la posición z en 0 en el método LineRenderer.SetPosition (). Entonces en lugar de escribir

LineRenderer.SetPosition(i, myVector3);

escribí

LineRenderer.SetPosition(i, new Vector3(myVector3.x, myVector3.y, 0));

Pero esa no es la mejor solución, ya que aún obtendrás esas líneas extrañas. La mejor solución que se me ocurrió fue crear líneas separadas. Eso funcionó perfectamente para mí. Espero que esto te ayude.

Alexionder
fuente