Enigma di ereditarietà e polimorfismo

0

Ok, sto cercando di scrivere qualcosa che assomigli a un motore di gioco 3D. Ciò significa che devo fare i conti con le trasformazioni della matrice e cose simili.

Per ognuno di voi che non lo sa, è necessario utilizzare tre matrici di base per definire dove verrà posizionato un vertice sullo schermo: matrice di proiezione, matrice di visualizzazione e matrice di entità.

Visualizza matrice sposta la fotocamera, mentre la matrice di entità sposta un'entità nel mondo. Non ci interessa la matrice di proiezione qui. Poiché la telecamera non esiste, viene simulata spostando l'intera scena in modo inverso (nega i vettori di traslazione e i quaternioni di rotazione inversa).

Data la loro somiglianza, volevo scrivere una classe base per fungere da interfaccia e scrivere due implementazioni che avrebbero a che fare con ciascuna delle matrici, l'entità 1 utilizzando i valori forniti e visualizzarne una invertendole in modo appropriato. In questo modo il cliente può spostare la telecamera in modo più intuitivo, lasciando che l'enigma dell'inversione venga trattato internamente. Mi consente inoltre di scrivere metodi che funzionano su entrambi i tipi di matrice.

Ma ci sono due cose che si oppongono, rendendo questo un po 'difficile (o almeno disordinato).

La matrice di entità ha tre componenti: posizione, rotazione e scala. La matrice di visualizzazione ha solo i primi due: non ha senso scalare la fotocamera. Potrei codificare i primi due componenti nella classe base e fare in modo che la scala sia specifica per la matrice delle entità.

NOTA: quando dico tipo matrix, o si riferisce a una matrice, in realtà intendo un tipo personalizzato che contiene i componenti da cui posso creare la matrice, non un oggetto matrice.

Ma voglio scrivere un'altra classe che possa contenere un singolo metodo che possa prendere una matrice e trasformarla in base a delle regole (avrei un'interfaccia astratta e il client potrebbe implementare un numero qualsiasi di metodi che in qualche modo trasformano l'oggetto - spostare / ruotare l'oggetto in base all'ingresso del lettore, spostarlo lungo una curva specifica, ruotare attorno a un punto, ecc.). Puoi vedere che questi metodi possono essere eseguiti su entrambe le entità o le telecamere. Rendere possibile la classe base - Posso passare il tipo di matrice di base al metodo e farlo restituire la matrice trasformata, indipendentemente dal suo tipo concreto.

Tuttavia, se metto il componente di scala nella matrice delle entità, non sarò in grado di usarlo in quel metodo poiché prenderà il tipo di base che non lo avrà definito.

Se metto la scala nel tipo di base, rende tutto un po 'sporco, dal momento che ora posso ridimensionare la matrice della vista. In questo caso particolare, il ridimensionamento della matrice della vista non cambia nulla e non succede niente di male a causa del modo in cui costruisco la matrice effettiva dai dati, mi fa solo sentire male e sporca.

Ma immagina questa stessa situazione in un ambiente diverso. In questo modo, il tuo computer potrebbe sputare fuoco e draghi uscire dal tuo display e mangiarti la faccia.

La mia domanda non riguarda il mio caso specifico (dove posso ignorarlo, ma mi sento sporco e cattivo), ma generico (con draghi e fuoco). Come posso ottenere ciò che voglio senza avere un drago che mi morde la faccia?

    
posta Karlovsky120 05.11.2016 - 18:14
fonte

1 risposta

3

Qui stai usando lo strumento sbagliato, come spesso accade quando le persone cercano di utilizzare il polimorfismo basato sull'eredità su tipi di base.

Ad esempio, una matrice di visualizzazione è prima di tutto una matrice . Il fatto che tu lo usi per una videocamera riguarda il modo in cui generi i suoi contenuti, non quello che puoi fare con esso. Dargli un tipo separato da una matrice normale non è semplicemente un progetto ragionevole. Limita la tua capacità di fare cose che alla fine potresti voler fare. Lo stesso vale per la matrice prospettica.

Quindi non c'è bisogno che abbiano un tipo distinto da un tipo di "matrice". Ciò che li rende distinti sono i loro valori , non il tipo stesso.

Vale a dire, prendi in considerazione se hai un tipo speed . Non faresti tipi separati di "velocità della vettura" e "velocità del carrello"; automobili e camion avrebbero semplicemente un speed . Una speed è una "velocità dell'auto" perché il speed proviene da un car .

Lo stesso vale qui. Una "matrice di visualizzazione" è un matrix che viene utilizzato per la parte della trasformazione della videocamera.

La tua definizione di "matrice di entità" con "tre componenti: posizione, rotazione e scala" (RPS) rappresenta qualcosa che è effettivamente distinta da una matrice tradizionale. Quello che hai non è affatto una matrice; è un tipo specifico di trasformazione. Questo è separato dal concetto di una "matrice".

Puoi usare la trasformazione per generare una matrice, ma la trasformazione è non una matrice. Non è possibile moltiplicare una trasformazione RPS con una matrice 4x4 arbitraria e continuare ad avere una trasformazione RPS. Bene, è possibile, ma per farlo è necessario eseguire singular-value-decomposition sulla matrice risultante per ottenere il tuo RPS valori indietro. E questo può fallire se la matrice arbitraria includesse proprietà di sheering o proiezione.

Poiché una trasformazione RPS non è una matrice, non dovrebbe ereditare da un tipo di matrice. Dovrebbe essere il suo tipo con le proprie operazioni. Lo converti in una matrice, se necessario, ma non è la stessa cosa di una matrice.

Ora, ho avuto bisogno di un tipo speciale che rappresenta una trasformazione RPS, ma può anche essere combinato con una matrice. Fondamentalmente, quello che ho fatto è stato memorizzare un variant<RPS, matrix> . Quindi l'oggetto potrebbe essere una trasformazione RPS o una matrice 4x4 standard.

Se era in forma RPS scomposta, allora potevi influenzare la posizione, l'orientamento o la scala della forma scomposta con operazioni scomposte. Ma se provavi a combinarlo con una matrice 4x4, passava alla forma della matrice. Una volta che ciò è accaduto, non è possibile influenzare direttamente i componenti RPS; dovevi usare le operazioni con la matrice su di esso.

Ma nota che questo tipo non era una "matrice". Era una trasformazione componibile, un tipo distinto che aveva un'interoperabilità con le matrici. Ma non è possibile sostituire ragionevolmente matrix con composable transform o viceversa. Quindi non c'era bisogno di usare l'ereditarietà.

    
risposta data 05.11.2016 - 18:48
fonte

Leggi altre domande sui tag