2010-02-13 11 views
23

Ho una geometria 2D. Voglio prendere dei limiti attorno alla mia geometria, e quindi renderne una versione più piccola da qualche altra parte sull'aereo. Ecco, più o meno il codice che devo fare il ridimensionamento e la traduzione:OpenGL: ridimensiona, quindi traduci? e come?

// source and dest are arbitrary rectangles. 
float scaleX = dest.width/source.width; 
float scaleY = dest.height/source.height; 
float translateX = dest.x - source.x; 
float translateY = dest.y - source.y; 

glScalef(scaleX, scaleY, 0.0); 
glTranslatef(translateX, translateY, 0.0); 
// Draw geometry in question with its normal verts. 

Questo funziona esattamente come previsto per una data dimensione in cui l'origine dest è 0. Ma se l'origine per, diciamo, x, è diverso da zero, il risultato è ancora ridimensionato correttamente ma sembra (?) è tradotto in qualcosa vicino allo zero su quell'asse comunque-- risulta che non è esattamente lo stesso come se dest.x fosse zero.

Qualcuno può indicare qualcosa di ovvio mi manca?

Grazie!

FINALE AGGIORNAMENTO Per le risposte di Bahbar e Marcus in basso, ho fatto qualche altra sperimentazione e ho risolto questo problema. Il commento di Adam Bowen è stato il consiglio. Mi mancavano due fatti critici:

  1. Avevo bisogno di essere ridimensionato attorno al centro della geometria a cui tenevo.
  2. Avevo bisogno di applicare le trasformazioni nell'ordine opposto dell'intuizione (per me).

Il primo è ovvio in retrospettiva. Ma per quest'ultimo, per altri bravi programmatori/matematici cattivi come me: scopre che la mia intuizione era quella di operare in quello che lo Red Book chiama un "Grande sistema di coordinate fisse", in cui c'è un piano assoluto, e la tua geometria si muove su quella aereo usando le trasformazioni. Questo è OK, ma data la natura della matematica dietro l'impilamento di più trasformazioni in una matrice, è l'opposto di come funzionano davvero le cose (vedere le risposte di seguito o Red Book per ulteriori informazioni). Fondamentalmente, le trasformazioni sono "applicate" in "ordine inverso" a come appaiono nel codice. Ecco la soluzione finale:

// source and dest are arbitrary rectangles. 
float scaleX = dest.width/source.width; 
float scaleY = dest.height/source.height; 
Point sourceCenter = centerPointOfRect(source); 
Point destCenter = centerPointOfRect(dest); 

glTranslatef(destCenter.x, destCenter.y, 0.0); 
glScalef(scaleX, scaleY, 0.0); 
glTranslatef(sourceCenter.x * -1.0, sourceCenter.y * -1.0, 0.0); 
// Draw geometry in question with its normal verts. 

risposta

16

In OpenGL, le matrici specificate vengono moltiplicate a destra della matrice esistente e il vertice si trova all'estremità destra dell'espressione.

Pertanto, l'ultima operazione specificata si trova nel sistema di coordinate della geometria stessa. (Il primo è solitamente la trasformazione della vista, cioè l'inverso della trasformazione della tua fotocamera verso il mondo.)

Bahbar rende un buon punto che è necessario considerare il punto centrale per il ridimensionamento. (o il punto di rotazione per le rotazioni.) Di solito si traduce lì, ruotare/ridimensionare, quindi tradurre di nuovo. (o in generale, applica la trasformazione di base, l'operazione, quindi l'inverso).Questo è chiamato Change of Basis, che si potrebbe voler leggere su.

In ogni caso, per ottenere qualche intuizione su come funziona, provare con alcuni valori semplici (zero, ecc.) Quindi modificarli leggermente (forse un'animazione) e vedere cosa succede con l'output. Quindi è molto più facile vedere cosa stanno effettivamente facendo le tue trasformazioni alla tua geometria.

Aggiornamento

Che l'ordine "invertito" w.r.t. l'intuizione è piuttosto comune tra i principianti OpenGL-coder. Ho seguito un corso di computer grafica e molti hanno reagito in modo simile. Diventa più facile pensare a come funziona OpenGL se si considera l'uso di pushmatrix/popmatrix mentre si esegue il rendering di un albero (grafico di scena) di trasformazioni e geometrie. Allora l'attuale ordine delle cose diventa piuttosto naturale, e il contrario renderebbe piuttosto difficile ottenere qualcosa di utile.

+1

In breve, cambia l'ordine in glTranslate (dest); glScale (scala); glTranslate (source); –

+0

Adam: Questo non sembra funzionare come suggerisci, anche se sono incuriosito ... puoi approfondire il motivo per cui l'ordinamento sarebbe andato così, e forse offrire un'idea più esplicita su come questo sembrerebbe relativo al codice esistente ? Forse sto solo interpretando male il tuo pseudocodice. Grazie! –

+0

Nevermind: il "non funziona" era un valore fatfing in questo caso. Dopo aver risolto ciò, siamo in affari. Vedi la domanda aggiornata per ulteriori informazioni. Grazie! –

6

La scala, proprio come Ruota, funziona dall'origine. quindi se riduci di metà un oggetto che occupa il segmento [10:20] (sull'asse X, ad es.), ottieni [5:10]. L'oggetto è stato quindi ridimensionato e spostato più vicino all'origine. Esattamente quello che hai osservato.

Questo è il motivo per cui si applica prima Scala in generale (poiché gli oggetti tendono ad essere definiti intorno a 0).

Quindi, se si desidera ridimensionare un oggetto attorno al centro del punto, è possibile convertire l'oggetto dal centro all'origine, ridimensionarlo e ripristinarlo.

Nota a margine, se si traduce prima e poi si ridimensiona, la scala viene applicata alla traduzione precedente, motivo per cui probabilmente si sono verificati problemi con questo metodo.

+0

Grazie per la risposta. Riesci a precisare per un dimwit di matrice matematica quali operazioni dovrei fare, a fare l'appropriata traduzione-per-origine, poi ridimensionare, poi tradurre-back? Ho tentato di impilare queste tre cose in successione (tradurre dal negativo dell'origine della fonte, quindi ridimensionare per fattori di scala, quindi tradurre per origine di destinazione) in tre chiamate prima di disegnare la geometria ma non ottenere risultati visibili. –

+0

Ah, forse ho bisogno di fare le traduzioni relative al centro del retto piuttosto che all'origine. Ci proveremo. –

+0

No. Nessun dado con: translate-by-negative-center-of-source, quindi scala, quindi translate-by-positive-center-of-dest. –

1

Non ho giocato con OpenGL ES, solo un po 'con OpenGL.

Sembra che tu voglia trasformare da una posizione diversa rispetto all'origine, non è sicuro, ma puoi provare a fare le trasformazioni e disegnare quel bit all'interno di glPushMatrix() and glPopMatrix()?

e.g. 

// source and dest are arbitrary rectangles. 
float scaleX = dest.width/source.width; 
float scaleY = dest.height/source.height; 
float translateX = dest.x - source.x; 
float translateY = dest.y - source.y; 

glPushMatrix(); 
    glScalef(scaleX, scaleY, 0.0); 
    glTranslatef(translateX, translateY, 0.0); 
    // Draw geometry in question with its normal verts. 
    //as if it were drawn from 0,0 
glPopMatrix(); 

Ecco un semplice schizzo Processing ho scritto per illustrare il punto:

import processing.opengl.*; 
import javax.media.opengl.*; 


void setup() { 
    size(500, 400, OPENGL); 
} 

void draw() { 
    background(255); 
    PGraphicsOpenGL pgl = (PGraphicsOpenGL) g; 
    GL gl = pgl.beginGL(); 


    gl.glPushMatrix(); 
    //transform the 'pivot' 
    gl.glTranslatef(100,100,0); 
    gl.glScalef(10,10,10); 
    //draw something from the 'pivot' 
    gl.glColor3f(0, 0.77, 0); 
    drawTriangle(gl); 
    gl.glPopMatrix(); 
    //matrix poped, we're back to orginin(0,0,0), continue as normal 
    gl.glColor3f(0.77, 0, 0); 
    drawTriangle(gl); 
    pgl.endGL(); 
} 

void drawTriangle(GL gl){ 
    gl.glBegin(GL.GL_TRIANGLES); 
    gl.glVertex2i(10, 0); 
    gl.glVertex2i(0, 20); 
    gl.glVertex2i(20, 20); 
    gl.glEnd(); 
} 

Ecco un'immagine della corsa schizzo, lo stesso triangolo verde viene disegnato, con traduzione e scala applicato, allora la uno rosso, outsie il push/pop 'block', in modo che non è influenzato dal trasformare:

alt text

HTH, Ge orge

+0

Grazie George, ma il push/pop non è in realtà il problema; Sto già facendo un push/pop al di fuori del codice di cui ho creato lo snippet. Grazie per aver illustrato le immagini, però! Una buona visualizzazione. –