2013-08-23 35 views
13

Opracowuję prosty silnik 3D (bez użycia API), z powodzeniem zmieniłem moją scenę w świat i wyświetlam przestrzeń, ale mam problem z rzutowaniem mojej sceny (z przestrzeni widoku) za pomocą perspektywy macierz projekcji (styl OpenGL). Nie jestem pewien co do wartości fov, bliskich i dalekich, a scena, którą widzę, jest zniekształcona. Mam nadzieję, że jeśli ktoś może skierowad mnie, jak poprawnie zbudować i wykorzystać matrycę projekcji perspektywicznej za pomocą przykładowych kodów. Z góry dziękuję za pomoc.Jak zbudować matrycę z rzutowaniem perspektywicznym (bez interfejsu API)

Powstawanie matrix

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

Zastosowanie matrycy:

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/perspektywa-i-ortograficzna-macierz-projekcja Polecam również poprzednie lekcje (rzutowanie punktów i oglądanie 3D). – user18490

Odpowiedz

23

Poniżej przedstawiono typowy implementacja macierzy projekcji perspektywicznym. I tu jest dobry link, aby wyjaśnić wszystko 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

Bardzo pomocne, dzięki –

+0

Przepraszam, ale co tu uh i u? Szerokość użytkownika i wysokość użytkownika? – ReX357

+2

@ ReX357 uw = w pobliżu/w prawo, i uh = blisko/na górze, gdzie prawy jest współrzędne prawego planu klipu, a góra jest współrzędną górnej płaszczyzny klipu. Ponieważ powyższy rzut perspektywiczny jest symetryczny, czyli prawy = połowa szerokości horyzontu i góra = połowa wysokości pionowej, to uw/uh = góra/prawa = wysokość/szerokość = 1/aspekt –

0

innej funkcji, które mogą być użyteczne.

Ten opiera się na lewo/prawo/góra/dół/w pobliżu/daleko parametry (stosowane w 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; 

}