2013-08-23 16 views
13

Sviluppo un semplice motore 3D (Senza alcun utilizzo di API), trasformo con successo la mia scena nel mondo e visualizza lo spazio ma ho problemi a proiettare la mia scena (dallo spazio di visualizzazione) usando la prospettiva matrice di proiezione (stile OpenGL). Non sono sicuro dei valori del fov, del vicino e del lontano e la scena che ottengo è distorta. Spero che qualcuno possa dirmi come costruire e utilizzare correttamente la matrice di proiezione prospettica con i codici di esempio. Grazie in anticipo per qualsiasi aiuto.Come creare una matrice di proiezione prospettica (nessuna API)

La generazione matrice:

double f = 1/Math.Tan(fovy/2); 
return new double[,] { 

    { f/Aspect, 0, 0, 0 }, 
    { 0, f, 0, 0 }, 
    { 0, 0, (Far + Near)/(Near - Far), (2 * Far * Near)/(Near - Far) }, 
    { 0, 0, -1, 0 } 
}; 

L'uso matrice:

foreach (Point P in T.Points) 
{  
    . 
    .  // Transforming the point to homogen point matrix, to world space, and to view space (works fine) 
    .  

    // projecting the point with getProjectionMatrix() specified in the previous code :  

    double[,] matrix = MatrixMultiply(GetProjectionMatrix(Fovy, Width/Height, Near, Far) , viewSpacePointMatrix); 

    // translating to Cartesian coordinates (from homogen): 

    matrix [0, 0] /= matrix [3, 0]; 
    matrix [1, 0] /= matrix [3, 0]; 
    matrix [2, 0] /= matrix [3, 0]; 
    matrix [3, 0] = 1; 
    P = MatrixToPoint(matrix); 

    // adjusting to the screen Y axis: 

    P.y = this.Height - P.y; 

    // Printing... 
} 
+0

http://www.scratchapixel.com/lessons/3d-basic-rendering/prospettiva-e-ortografica-proiezione matrice- Raccomando anche le lezioni precedenti (punti di proiezione e visualizzazione 3D). – user18490

risposta

23

Segue un'implemenation tipico di matrice di proiezione prospettica. Ed ecco un buon collegamento a spiegare tutto OpenGL Projection Matrix

void ComputeFOVProjection(Matrix& result, float fov, float aspect, float nearDist, float farDist, bool leftHanded /* = true */) 
{ 
    // 
    // General form of the Projection Matrix 
    // 
    // uh = Cot(fov/2) == 1/Tan(fov/2) 
    // uw/uh = 1/aspect 
    // 
    // uw   0  0  0 
    // 0  uh  0  0 
    // 0   0  f/(f-n) 1 
    // 0   0 -fn/(f-n) 0 
    // 
    // Make result to be identity first 

    // check for bad parameters to avoid divide by zero: 
    // if found, assert and return an identity matrix. 
    if (fov <= 0 || aspect == 0) 
    { 
     Assert(fov > 0 && aspect != 0); 
     return; 
    } 

    float frustumDepth = farDist - nearDist; 
    float oneOverDepth = 1/frustumDepth; 

    result[1][1] = 1/tan(0.5f * fov); 
    result[0][0] = (leftHanded ? 1 : -1) * result[1][1]/aspect; 
    result[2][2] = farDist * oneOverDepth; 
    result[3][2] = (-farDist * nearDist) * oneOverDepth; 
    result[2][3] = 1; 
    result[3][3] = 0; 
} 
+0

Molto utile, grazie –

+0

Scusate ma cosa ci state uh e uw? Larghezza utente e altezza dell'utente? – ReX357

+2

@ ReX357 uw = near/right e uh = near/top, dove right è le coordinate del piano clip destro e top è le coordinate del piano clip superiore. Poiché la proiezione prospettica sopra è simmetrica, quindi a destra = metà della larghezza dell'orizzonte e superiore = metà dell'altezza verticale, quindi uw/uh = alto/destra = altezza/larghezza = 1/aspetto –

0

Un'altra funzione che può essere utile.

Questo si basa su sinistra/destra/alto/basso/vicino/lontano parametri (utilizzato OpenGL):

static void test(){ 
    float projectionMatrix[16]; 

    // width and height of viewport to display on (screen dimensions in case of fullscreen rendering) 
    float ratio = (float)width/height; 
    float left = -ratio; 
    float right = ratio; 
    float bottom = -1.0f; 
    float top = 1.0f; 
    float near = -1.0f; 
    float far = 100.0f; 

    frustum(projectionMatrix, 0, left, right, bottom, top, near, far); 

} 

static void frustum(float *m, int offset, 
        float left, float right, float bottom, float top, 
        float near, float far) { 

    float r_width = 1.0f/(right - left); 
    float r_height = 1.0f/(top - bottom); 
    float r_depth = 1.0f/(far - near); 
    float x = 2.0f * (r_width); 
    float y = 2.0f * (r_height); 
    float z = 2.0f * (r_depth); 
    float A = (right + left) * r_width; 
    float B = (top + bottom) * r_height; 
    float C = (far + near) * r_depth; 
    m[offset + 0] = x; 
    m[offset + 3] = -A; 
    m[offset + 5] = y; 
    m[offset + 7] = -B; 
    m[offset + 10] = -z; 
    m[offset + 11] = -C; 
    m[offset + 1] = 0.0f; 
    m[offset + 2] = 0.0f; 
    m[offset + 4] = 0.0f; 
    m[offset + 6] = 0.0f; 
    m[offset + 8] = 0.0f; 
    m[offset + 9] = 0.0f; 
    m[offset + 12] = 0.0f; 
    m[offset + 13] = 0.0f; 
    m[offset + 14] = 0.0f; 
    m[offset + 15] = 1.0f; 

} 
Problemi correlati