Come posso disegnare un contorno in Unity3d?


13

Sto cercando di evidenziare un rettangolo di altezza arbitraria. Ho pensato che il modo più semplice per farlo fosse quello di creare un oggetto di gioco "box" separato che delinea il rettangolo.

Ho provato sia con un MeshRenderer + Transparent Texture, sia con un LineRenderer per delineare i quattro punti del rettangolo. Né sono molto soddisfacenti.

inserisci qui la descrizione dell'immagine

(Line renderer attivo al centro, cubo ridimensionato a destra)

Qual è il modo giusto di procedere? Sto cercando di ottenere qualcosa come il rettangolo sinistro: un semplice perimetro di larghezza fissa attraverso quattro punti di mia scelta.

Risposte:


8

Usa GUI.Box().

Se hai solo bisogno di un rettangolo 2D, la GUI è la strada da percorrere. Crea un nuovo GUIStyle usando un semplice rettangolo come trama (l'interno del rettangolo dovrebbe essere trasparente, ovviamente), imposta il suo Bordervalore in modo che non sia allungato e chiama GUI.Box(new Rect(...),"",myGuiStyle);.

Puoi usare il Camera.WorldToScreenPointmetodo se vuoi delineare qualcosa nelle coordinate del mondo (cioè 3D), ricorda solo che nelle coordinate del mondo di Unity y va dal basso verso l'alto e nella GUI y va dall'alto verso il basso.

Esempio di codice:

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

A meno che non mi sbagli, GUI.Box () sarà sempre disegnato sopra qualsiasi oggetto nella scena? È possibile avere un elemento GUI dietro o parzialmente dietro un oggetto di gioco?
Raven Dreamer,

Sì, la GUI viene sempre disegnata dopo altri oggetti. C'è un trucco che puoi usare per eseguire il rendering di una telecamera separata nella parte superiore della GUI, ma è un po 'ingombrante.
Nevermind,

Questa risposta mi ha dato ciò di cui avevo bisogno, ma per ora la tengo aperta nella speranza che ci sia un modo migliore per farlo nel caso generale.
Raven Dreamer,

Ho accettato la tua modifica aggiungendo un esempio di codice e risolto il bug della GUI-y-up-down-down.
Nevermind

1

Di seguito è riportato un approccio non shader.

Pensa alla tua casella 2d come nient'altro che quattro linee, in cui ogni linea è allungata in una sola dimensione (le altre due dimensioni sono la sezione del bordo). Questo è molto simile a se costruissi una scatola nella vita reale, dove stai mettendo insieme lunghezze variabili di legno che hanno tutte le stesse dimensioni della sezione trasversale.

Tenendo presente ciò, è possibile ideare un Componente, ad esempio BoxBuilder, che, quando collegato a un GameObject, crea e gestisce quattro GameObject figlio. Ogni oggetto di gioco figlio è uno dei bordi della scatola e può essere semplicemente un cubo 3d che viene allungato in una sola dimensione. Con una widthe heightdefinito BoxBuilderlivello, è possibile calcolare il posizionamento necessaria e la scala non uniforme dei quattro bordi bambino. Sarà un sacco di pos.x=w/2, pos.y=h/2, ..., scale.x=h, scale.y=w, ecc sorta di codice.

Anche se credo che tu stia chiedendo solo 2-d, nota che questa stessa idea può essere applicata a caselle 3d se necessario, in cui BoxBuilderora è necessario creare e gestire 12 bordi figlio, ma ridimensionare di nuovo solo ogni bordo in una dimensione locale.


Funzionale, ma MODO troppo complicato.
Nevermind,

Se dovessi farlo in questo modo, utilizzerei semplicemente i renderer a 4 righe ...
Raven Dreamer,

Questo tuttavia gestisce correttamente la profondità.
DuckMaestro,

1

Un modo semplice è usare uno Shader con due Pass: il primo Pass utilizza lo shader di vertice per ridimensionare un po 'l'oggetto e usa il pixel shader per colorarlo in un colore solido corrispondente al colore che si desidera avere il contorno, e quindi il secondo passaggio esegue il rendering regolare.


Potresti dare un esempio di codice per spiegare meglio cosa intendi?
Raven Dreamer,

Funzionerebbe solo per oggetti convessi (come un rettangolo) la cui origine è al centro geometrico.
rootlocus,

1

Ho avuto lo stesso problema durante la creazione di un contorno, tranne per il fatto che avevo bisogno di creare il "tratto" per un cubo 3d e ho trovato un nuovo modo di farlo che non ho visto altrove online.

Nell'immagine qui sotto ci sono due forme con contorni. Quello a destra è un cubo costruito con LineRenderer, che crea facce piatte che ruotano sempre verso l'utente. Ho trovato questo metodo super glitch, con "tratti" casuali che apparivano che imitavano i triangoli che compongono il viso.

Quello a sinistra è la mia "innovazione" con 12 cubi sottili separati che costruiscono quello che sembra un contorno. Per modificare la dimensione del "tratto" nel contorno, devo aumentare / ridurre le dimensioni di due lati di ciascuno dei 12 cubi magri. Questo funzionerebbe anche per i contorni 2d. Basta applicare un materiale per cambiare colore e voilà!

due contorni diversi

In questa immagine puoi vedere un dettaglio della struttura di questo cubo. Tutto questo poteva essere creato in fase di esecuzione ma l'ho realizzato a mano e l'ho usato come prefabbricato.

dettaglio


0

Attualmente sto affrontando lo stesso problema, e la mia soluzione è esattamente ciò che DuckMaestro e Raven Dreamer hanno suggerito: avere uno script che crei 4 oggetti figlio in fase di esecuzione ciascuno dei quali rappresenta un lato del bordo e allega i renderizzatori di linee a ciascuno.

Nel mio caso avevo bisogno di ridimensionare costantemente il bordo per tenerlo attorno al mio oggetto (una mesh di testo [che utilizza un renderer di mesh] per un campo di testo personalizzato), quindi ad ogni aggiornamento ho fatto questo:


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() accede semplicemente al renderer di riga appropriato (specificato dal primo parametro) e imposta rispettivamente l'inizio e la fine del primo e del secondo vettore.

Nota che ho usato renderercome riferimento per le dimensioni, ma ovviamente puoi usare qualsiasi rettangolo, purché x, y sia l'angolo in alto a sinistra.

Da quello che posso dire questo funziona davvero bene, sembra fantastico nel gioco perché posso facilmente spostare il mio oggetto bordato in giro in tutti e 3 gli assi (anche ruotarlo, e poiché i renderizzatori di linee sono sempre rivolti verso la telecamera non sembra strano), ed è non è difficile da implementare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.