Como posso desenhar um esboço no Unity3d?

13

Estou tentando destacar um retângulo de altura arbitrária. Eu pensei que a maneira mais fácil de fazer isso seria criar um objeto de jogo "caixa" separado que contorne o retângulo.

Eu tentei com um MeshRenderer + Transparent Texture e um LineRenderer para delinear os quatro pontos do retângulo. Nem são muito satisfatórios.

insira a descrição da imagem aqui

(Renderizador de linha ativado no meio, cubo dimensionado à direita)

Qual é o caminho certo para fazer isso? Estou tentando obter algo como o retângulo esquerdo - um perímetro simples de largura fixa através de quatro pontos de minha escolha.

Sonhador Corvo
fonte

Respostas:

8

Use GUI.Box().

Se você só precisa de um retângulo 2D, a GUI é o caminho a percorrer. Crie um novo GUIStyle usando um retângulo simples como textura (a parte interna do retângulo deve ser transparente, é claro), configure seu Bordervalor para que não seja esticado e chame GUI.Box(new Rect(...),"",myGuiStyle);.

Você pode usar o Camera.WorldToScreenPointmétodo se desejar esboçar algo nas coordenadas mundiais (isto é, 3D), lembre-se de que no mundo do Unity as coordenadas y vão de baixo para cima e na GUI y vão de cima para baixo.

Exemplo de código:

void OnGUI()
{
    //top left point of rectangle
    Vector3 boxPosHiLeftWorld = new Vector3(0.5f, 12, 0);
    //bottom right point of rectangle
    Vector3 boxPosLowRightWorld = new Vector3(1.5f, 0, 0);

    Vector3 boxPosHiLeftCamera = Camera.main.WorldToScreenPoint(boxPosHiLeftWorld);
    Vector3 boxPosLowRightCamera = Camera.main.WorldToScreenPoint(boxPosLowRightWorld);

    float width = boxPosHiLeftCamera.x - boxPosLowRightCamera.x;
    float height = boxPosHiLeftCamera.y - boxPosLowRightCamera.y;


     GUI.Box(new Rect(boxPosHiLeftCamera.x, Screen.Height - boxPosHiLeftCamera.y, width, height),"", highlightBox);
}
deixa pra lá
fonte
A menos que eu esteja enganado, GUI.Box () sempre será desenhado em cima de qualquer objeto na cena? É possível ter um elemento GUI atrás ou parcialmente atrás de um objeto de jogo?
Raven Dreamer
Sim, a GUI é sempre desenhada após outros objetos. Há um truque que você pode usar para renderizar uma câmera separada em cima da GUI, mas é meio complicado.
Nevermind
Essa resposta me deu o que eu precisava, mas estou mantendo-a aberta por enquanto, na esperança de que haja uma maneira melhor de fazer isso no caso geral.
Corvo Dreamer
Aceitei a sua edição adicionando amostra de código e corrigi o bug da GUI-y de cabeça para baixo.
Nevermind
1

Abaixo está uma abordagem sem sombreador.

Pense na sua caixa 2D como nada mais que quatro linhas, onde cada linha é esticada em apenas uma dimensão (as outras duas dimensões são a seção transversal da aresta). É como se você construísse uma caixa na vida real, onde você está juntando comprimentos variáveis ​​de madeira com todos o mesmo tamanho de seção transversal.

Com isso em mente, você pode criar um Componente, digamos BoxBuilder, que quando anexado a um GameObject, cria e gerencia quatro GameObjects filhos. Cada objeto de jogo filho é uma das arestas da sua caixa e pode ser simplesmente um cubo 3D que é estendido em apenas uma dimensão. Com um widthe heightdefinido BoxBuildernível, você pode calcular o posicionamento necessário e escala não uniforme das quatro bordas da criança. Vai ser um monte de pos.x=w/2, pos.y=h/2, ..., scale.x=h, scale.y=w, etc. tipo de código.

Embora eu acredite que você esteja solicitando apenas 2-d, observe que essa mesma idéia pode ser aplicada às caixas 3D, se necessário, onde o BoxBuilderagora deve criar e gerenciar 12 arestas filho, mas novamente dimensionar cada aresta em uma dimensão local.

DuckMaestro
fonte
Exequível, mas MUITO complicado.
Nevermind
Se eu tivesse que fazê-lo desta maneira, eu simplesmente usar 4 prestadores de linha ...
Corvo Sonhador
Isso lida adequadamente com a profundidade, no entanto.
DuckMaestro
1

Uma maneira simples é usar um sombreador com duas passagens: a primeira passagem usa o sombreador de vértice para dimensionar um pouco o objeto e usa o sombreador de pixel para colori-lo com uma cor sólida correspondente à cor que você deseja que o contorno tenha; e então o segundo passe faz a renderização regular.

UBSophung
fonte
Você poderia dar um exemplo de código para explicar melhor o que você quer dizer?
Raven Dreamer
Isso funcionaria apenas para objetos convexos (como um retângulo) cuja origem está no centro geométrico.
método do lugar das raízes
1

Eu tive o mesmo problema ao criar um esboço, exceto que precisava criar o "traçado" para um cubo 3D e encontrei uma nova maneira de fazer isso que nunca vi em nenhum outro lugar online.

Na imagem abaixo, existem duas formas com contornos. O da direita é um cubo construído com o LineRenderer, que cria faces planas que sempre se voltam para o usuário. Achei esse método super glitchy, com "golpes" aleatórios aparecendo que imitavam os triângulos que compõem o rosto.

O da esquerda é a minha "inovação", com 12 cubos finos separados, construindo o que parece um contorno. Para alterar o tamanho do “traçado” no contorno, preciso aumentar / diminuir os tamanhos de dois lados de cada um dos 12 cubos finos. Isso também funcionaria para contornos 2D. Basta aplicar um material para mudar a cor e pronto!

dois contornos diferentes

Nesta imagem, você pode ver um detalhe da estrutura deste cubo. Tudo isso poderia ser criado em tempo de execução, mas eu o fiz manualmente e o usei como pré-fabricado.

detalhe

ow3n
fonte
0

Atualmente, estou enfrentando o mesmo problema, e minha solução é exatamente o que DuckMaestro e Raven Dreamer sugeriram - Tenha um script que crie 4 objetos filhos em tempo de execução, cada um representando um lado da borda e anexando renderizadores de linha a cada um.

No meu caso, eu precisava redimensionar constantemente a borda para mantê-la em volta do meu objeto (uma malha de texto [que usa um renderizador de malha] para um campo de texto personalizado), para cada atualização que eu fazia isso:


float width = Mathf.Max(renderer.bounds.size.x + paddingX * 2, minWidth);      
float x = renderer.bounds.center.x - width / 2;
float height = renderer.bounds.size.y + paddingY * 2;
float y = renderer.bounds.center.y - height / 2;

AlterBorder(0, new Vector3(x - thickness / 2, y, 0), new Vector3(x + width + thickness / 2, y, 0)); //Bottom edge going left to right
AlterBorder(1, new Vector3(x + width, y + thickness / 2, 0), new Vector3(x + width, y + height - thickness / 2, 0)); //Right edge going bottom to top
AlterBorder(2, new Vector3(x + width + thickness / 2, y + height, 0), new Vector3(x - thickness / 2, y + height, 0)); //Top edge going right to left
AlterBorder(3, new Vector3(x, y + height - thickness / 2, 0), new Vector3(x, y + thickness / 2, 0)); //Left edge going top to bottom

AlterBorder() simplesmente acessa o renderizador de linha apropriado (especificado pelo primeiro parâmetro) e define seu início e fim para o primeiro e o segundo vetor, respectivamente.

Observe que eu usei renderercomo minha referência para o tamanho, mas obviamente você pode usar qualquer retângulo, desde que x, y seja o canto superior esquerdo.

Pelo que sei, isso funciona muito bem, fica ótimo no jogo porque posso mover meu objeto com bordas facilmente em todos os 3 eixos (até girá-lo e, como os renderizadores de linha sempre encaram a câmera, não parece estranho), e é não é difícil de implementar.

romano
fonte