Como fazer com que as linhas do Renderizador de linha fiquem planas?

10

Percebi que, à medida que adiciono mais vértices a uma linha de Renderizador de Linhas, a linha torce e deixa de ser uma linha suave.

insira a descrição da imagem aqui

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

Todas as linhas estão no mesmo nível z, mesmo se eu remover os materiais, as linhas ainda parecem torcer.

Não faço ideia por que isso ocorre ou como resolvê-lo, com alguma sugestão?

Douglas Gaskell
fonte
Esse é um problema com o algoritmo que o LineRenderer usa para posicionar seus vértices, que lida mal com cantos afiados. Você pode melhorar um pouco adicionando mais pontos para arredondar os cantos, mas o método mais robusto que encontrei é duplicar sua funcionalidade para si mesmo com um algoritmo melhor, criando uma malha dinâmica com os vértices que você precisa ou de forma criativa explorando um ParticleSystem para desenhar a cadeia de pontos.
DMGregory
1
Atualização: Versões posteriores do Unity (5 5+) aprimoraram o algoritmo do LineRenderer ; portanto, os usuários que pensam em usar o LineRenderers podem achar que o resultado imediato é substancialmente melhor atualmente.
DMGregory

Respostas:

11

O problema é basicamente este:

insira a descrição da imagem aqui

O LineRenderer está tentando conectar as posições dos pontos vermelhos. Está criando os vértices verdes para fazer uma malha. Portanto, o segmento de primeira linha parece ótimo. Mas o LineRenderer tenta ser econômico, reutilizando os vértices do final de um segmento de linha no final do segundo segmento de linha. Quando há um ângulo agudo, você obtém o problema que está vendo. O segundo segmento de linha é comprimido na interseção porque sua 'tampa final' não é perpendicular a sua outra 'tampa final'.

A solução é criar seu próprio renderizador de linha e não torná-lo tão econômico. Você pode fazer isso gerando uma malha dinâmica . A malha consistirá em uma série de quadriláteros finos. Para cada segmento de linha, você pode calcular os quatro cantos do quad calculando o normal da linha e uma largura de linha especificada:

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

Aqui, a, b, ce dcompõem os quatro cantos de um único segmento de linha, assim como os pontos verdes na imagem acima. Esses vértices seriam adicionados à malha e você também adicionaria os índices para transformar os quatro vértices em dois triângulos (assim, seis índices seriam adicionados, abc e bdc).

Obviamente, isso pode ficar bastante complexo. Acredito que outra razão pela qual a Unity tenha implementado o LineRenderer da maneira que eles fizeram foi porque fazê-lo dessa maneira evita outro problema, os cantos. Quando você começa a desenhar cada segmento de linha, começa a ver onde os dois segmentos de linha se juntam e formam uma junção feia. Existem maneiras de lidar com isso calculando o normal compartilhado entre as duas linhas e atualizando seus vértices para o normal compartilhado, mas isso resolve apenas parcialmente o problema, pois você ainda pode acabar facilmente com linhas comprimidas. A solução mais robusta é gerar vértices adicionais nas juntas para atuar como cantos.

MichaelHouse
fonte
1
Você também pode usar o renderizador de linha de unidade e inserir pontos adicionais para criar uma pequena mitra. Basta colocar um ponto um pouco mais próximo do ponto anterior.
mklingen
Ótima explicação Byte, obrigado. Provavelmente vou tentar e ver se não consigo gerar mais pontos em cada um dos cantos; se isso não der certo, vou em frente e tentarei fazer uma malha dinâmica. Obrigado.
Douglas Gaskell 12/02
1

Eu tive o mesmo problema e resolvi adicionando mais pontos às bordas suaves. Não é uma solução elegante, é simples e funciona. Pelo menos para mim. Eu escrevi uma função para fazer isso:

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
fonte
0

Uma maneira de resolver isso para linhas opacas é renderizar um círculo em cada junta. O círculo precisa ter um diâmetro igual à largura da linha. Isso requer que alguns vértices extras sejam renderizados, mas parece muito bom. Você também pode se livrar das normais compartilhadas entre as articulações.

Isso ainda exige que você escreva seu próprio código de renderização em vez de usar o Unity Line Renderer.

Fiz um ativo que faz exatamente isso em http://u3d.as/nFE

jjxtra
fonte
0

A maneira como evitei isso é que sempre defino a posição z como 0 no método LineRenderer.SetPosition (). Então, ao invés de escrever

LineRenderer.SetPosition(i, myVector3);

eu escrevi

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

Mas essa não é a melhor solução, pois você ainda terá essas linhas estranhas. A melhor solução que eu consegui pensar foi criar linhas separadas. Isso funcionou perfeitamente para mim. Espero que isso ajude você.

Alexionder
fonte