2011-12-13 18 views
7

Creo un'applicazione FireMonkey con 3 tImage3D semitrasparenti. Ecco il codice e lo schermo. Tutto sembra bene.Firemonkey semitrasparente Image3D è talvolta opaco

procedure TForm1.Form3DCreate(Sender: TObject); 

// create a new semi-transparent timage3d 
// object with color and Z position. 
procedure NewImage (const nColor : tColor; 
        const nZ  : integer); 
begin 
    // create the image 
    with tImage3D . Create (self) do 
    begin 
     // put it on the screen 
     Parent := self; 
     // set the size 
     Width := 10; 
     Height := 10; 
     // set the image to a single pixel. 
     Bitmap . Width := 1; 
     Bitmap . Height := 1; 
     // set the Alpha to $80 to make it 
     // semi-transparent 
     Bitmap . Pixels [ 0, 0 ] := $80000000 + nColor; 
     // set the z position 
     Position . Z := nZ; 
    end; 
end; 

begin 
    NewImage (claRed, +10); 
    NewImage (claGreen, 0); 
    NewImage (claBlue, -10); 
end; 

All is well

Ora invertire l'ordine. Ora sono opachi.

begin 
    NewImage (claRed, -10); 
    NewImage (claGreen, 0); 
    NewImage (claBlue, +10); 
end; 

Now they are opaque

Che cosa mi manca?

+3

Apparentemente un oggetto è solo semi-trasparente per un oggetto creato in precedenza. Se questo ha un senso. La casella rossa appare rosa perché puoi vedere lo sfondo bianco, ma non puoi vedere le caselle verdi o blu attraverso di essa. Attraverso la scatola verde, puoi vedere lo sfondo bianco e la scatola rossa, ma non la scatola blu. Ho fatto accadere la stessa cosa anche con oggetti text3d. –

+0

Penso che @user abbia ragione. Prova a ridisegnare gli oggetti di fronte. Se l'oggetto non rileva nulla sotto di esso, probabilmente salta le funzioni di fusione e lo sfondo bianco non conta. –

+0

Cosa intendi per ridisegnare gli oggetti in primo piano? Questo è un esempio molto semplificato per illustrare il problema. L'app originale aveva diverse immagini e testi fluttuanti, e la posizione di ogni oggetto veniva cambiata ogni 50 ms, e quindi veniva continuamente ridisegnata. –

risposta

4

FireMonkey (al momento) non supporta il rendering di oggetti semitrasparenti in 3D.

FireMonkey supporta solo miscelazione di oggetti semi-trasparenti (sia attraverso la proprietà Opacità o a causa della loro consistenza, per esempio un'immagine semitrasparente PNG), ma blending da sola non è sufficiente per farlo bene in 3D con a Z-Buffer (che è ciò che FMX e la maggior parte delle applicazioni 3D stanno utilizzando).

Per una spiegazione tecnica, è possibile leggere su Transparency sorting, l'articolo è su OpenGL, ma si applica anche a DirectX.

Quindi, per ottenere il rendering corretto, è necessario che gli oggetti semitrasparenti siano ordinati di fronte al punto di vista della telecamera.

è possibile ottenere maggiori dettagli e un certo codice in questo post per aggirare il problema:

Rendering semi-transparent object in FireMonkey

ma di tenere presente che sarà solo una soluzione.

Idealmente questo dovrebbe essere gestito dal grafico di scena FireMonkey, in quanto dipende dal rendering, altrimenti, si finisce per dover cambiare la struttura del grafico scena, che può avere vari altri effetti collaterali, ed è ancora di più problematico se hai più di una telecamera che guarda la stessa scena.

Inoltre, l'approccio ordinamento funziona solo con oggetti convessi che non si intersecano, e per i quali non si dispone di triple-sovrappongono, come in:

Triple Overlap example

per i quali non esiste alcuna ordinamento corretto (nessuno degli elementi è di fronte agli altri).

0

Come hai già scoperto, devi disegnare oggetti trasparenti dal retro al fronte.

Quando si disegna un oggetto trasparente, l'oggetto viene disegnato e mescolato con i pixel che si trovano dietro di esso.

Quindi questo accade quando si disegna da dietro in avanti:
Si disegna l'immagine rossa, si fonde con lo sfondo bianco. Si può dire dal "rosa" invece che dal colore rosso puro che si fonde con lo sfondo bianco. Quindi si disegna l'immagine verde, si fonde con lo sfondo bianco già disegnato e l'immagine rossa. Finalmente si disegna l'immagine blu, che si fonde con gli oggetti già disegnati.

ma ora siamo trarre da davanti a dietro:
disegniamo il piano di rosso prima. Si fonde con lo sfondo bianco che puoi vedere perché è rosa invece che rosso. Ora disegniamo il piano verde. Si fonde con lo sfondo bianco, lo si capisce dal colore, non è puro, profondo, verde. Ma, il renderer vede che una parte cade dietro il piano rosso, quindi non disegna quella parte. Ma, tu pensi: il piano rosso è trasparente, il renderer dovrebbe disegnare dietro quel piano rosso! Beh no, il renderer tiene traccia solo della profondità/ordine z dei pixel nel buffer z/depth-buffer, non sa se quel pixel è trasparente o meno. La stessa storia vale per il piano blu, viene disegnata solo la parte che non è oscurata da altri oggetti.

Qual è il buffer di profondità di cui parli?
Nel buffer di profondità viene memorizzata la profondità di ogni pixel. Quando si disegna un pixel a 2,2 con az di 1, il depth buffer a 2,2 viene aggiornato con il valore 1. Ora quando si disegna una linea da 1,2 a 3,2 con az di 3, il renderer disegnerà solo i pixel dove il depth-buffer ha un valore di> = 3. Quindi viene disegnato il pixel 1,2 (e il depth-buffer in 1,2 è impostato su 3). Pixel 2,2 non è disegnato, perché il depth-buffer indica che quel pixel è già disegnato con una profondità minore (1 vs 3). Il pixel 3,2 viene disegnato e il depth buffer a 3,2 è impostato su 3.
Quindi il depth-buffer viene utilizzato per tenere traccia dell'ordine z di ogni pixel per evitare di sovrascrivere quel pixel con un pixel che è più lontano.

Se si desidera disegnare oggetti trasparenti nel modo giusto, vedere this answer.

Estratto da quella risposta:

  • Prima disegnare oggetti opachi.
  • Disabilita le scritture del buffer di profondità (quindi il depth-buffer non viene aggiornato), ma mantiene abilitato il controllo del depth-buffer.
  • Disegna oggetti trasparenti. Poiché il depth-buffer non viene aggiornato, non si ha il problema di oggetti trasparenti che si oscurano l'un l'altro.Poiché il controllo del depth-buffer è abilitato, non si disegna dietro oggetti opachi.

Non so se FireMonkey supporti la disabilitazione delle scritture di profondità del buffer, devi scoprirlo da solo.

Problemi correlati