Jak sprawić, by linie renderowania linii pozostały płaskie?


10

Zauważyłem, że dodając więcej wierzchołków do linii renderującej linie, linia skręca się i przestaje być gładką linią.

wprowadź opis zdjęcia tutaj

.GIF Tutaj: http://i.imgur.com/hRAhCXM.gif

Wszystkie linie są na tym samym poziomie Z, nawet jeśli usunę materiały, linie nadal wydają się skręcać.

Nie mam pojęcia, dlaczego to robi lub jak to rozwiązać, jakieś sugestie? C #


Jest to problem związany z algorytmem używanym przez LineRenderer do pozycjonowania wierzchołków, który źle radzi sobie z ostrymi narożnikami. Możesz go nieco poprawić, dodając więcej punktów w celu zaokrąglenia narożników, ale najbardziej niezawodną metodą, jaką znalazłem, jest zduplikowanie jego funkcjonalności dla siebie za pomocą lepszego algorytmu, poprzez utworzenie dynamicznej siatki z potrzebnymi wierzchołkami lub twórczo wykorzystując ParticleSystem do narysowania łańcucha punktów.
DMGregory

1
Aktualizacja: Późniejsze wersje Unity (5 5+) ulepszyły algorytm LineRenderer , więc użytkownicy rozważający użycie LineRenderers mogą stwierdzić, że natychmiastowy wynik jest znacznie lepszy.
DMGregory

Odpowiedzi:


11

Problem polega w zasadzie na tym:

wprowadź opis zdjęcia tutaj

LineRenderer próbuje połączyć pozycje z czerwoną kropką. Tworzy zielone wierzchołki, aby utworzyć siatkę. Tak więc segment górnej linii wygląda świetnie. Ale potem LineRenderer stara się być ekonomiczny, ponownie wykorzystuje wierzchołki od końca jednego segmentu linii na końcu drugiego segmentu linii. Gdy jest ostry kąt, pojawia się problem, który widzisz. Drugi segment linii jest ściśnięty na przecięciu, ponieważ jego „zaślepka” nie jest prostopadła do drugiego „zaślepki”.

Rozwiązaniem jest stworzenie własnego renderera linii, a nie uczynienie go tak ekonomicznym. Możesz to zrobić, generując dynamiczną siatkę . Siatka będzie się składać z szeregu cienkich quadów. Dla każdego segmentu linii można obliczyć cztery rogi kwadratu, obliczając normalną linię i określoną szerokość linii:

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);

Tutaj a, b, ci dtworzą cztery narożniki jednego segmentu linii, podobnie jak zielone kropki na obrazie powyżej. Te wierzchołki zostaną dodane do siatki, a także dodasz indeksy, aby przekształcić cztery wierzchołki w dwa trójkąty (a więc dodanych zostanie sześć indeksów, abc i bdc).

Może to oczywiście stać się dość skomplikowane. Uważam, że innym powodem, dla którego Unity zaimplementowało swój LineRenderer, było to, że w ten sposób unika się innego problemu, narożników. Kiedy zaczniesz rysować każdy segment linii, zaczniesz widzieć, gdzie dwa segmenty linii łączą się i tworzą brzydkie połączenie. Istnieją sposoby, aby sobie z tym poradzić, obliczając wspólną normalną między obiema liniami i aktualizując ich wierzchołki do wspólnej normalnej, ale to tylko częściowo rozwiązuje problem, ponieważ nadal możesz łatwo skończyć z zaciśniętymi liniami. Najbardziej niezawodnym rozwiązaniem jest wygenerowanie dodatkowych wierzchołków w stawach, które będą działać jako narożniki.


1
Prawdopodobnie możesz też uciec od korzystania z renderera linii jedności i wstawiania dodatkowych punktów, aby utworzyć małą mitrę. Wystarczy umieścić punkt na kilka sposobów, aby przejść do następnego punktu z poprzedniego punktu.
mklingen

Świetne wyjaśnienie Bajt, dzięki. Prawdopodobnie postaram się sprawdzić, czy nie uda mi się wygenerować więcej punktów na każdym z rogów, jeśli to nie zadziała dobrze, spróbuję wykonać dynamiczną siatkę. Dziękuję Ci.
Douglas Gaskell,

1

Miałem ten sam problem i rozwiązuję go, dodając więcej punktów do gładkich krawędzi, nie jest to eleganckie rozwiązanie, ale jest proste i działa. Przynajmniej dla mnie. Napisałem funkcję, aby to zrobić:

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;
}


0

Jednym ze sposobów rozwiązania tego problemu dla nieprzezroczystych linii jest narysowanie okręgu w każdym złączu. Okrąg musi mieć średnicę równą szerokości linii. Wymaga to renderowania kilku dodatkowych wierzchołków, ale wygląda naprawdę ładnie. Możesz także pozbyć się wspólnych norm między stawami.

Nadal wymaga to napisania własnego kodu renderującego zamiast korzystania z modułu Unity Line Renderer.

Zrobiłem zasób, który właśnie to robi na http://u3d.as/nFE


0

Unikałem tego, ponieważ zawsze ustawiałem pozycję z na 0 w metodzie LineRenderer.SetPosition (). Więc zamiast pisać

LineRenderer.SetPosition(i, myVector3);

napisałem

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

Ale to nie jest najlepsze rozwiązanie, ponieważ nadal będziesz otrzymywać te dziwne linie. Najlepszym rozwiązaniem, jakie mogłem wymyślić, było utworzenie oddzielnych linii. To działało idealnie dla mnie. Mam nadzieję, że to ci pomoże.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.