2015-02-04 3 views
1

Я пытаюсь 3D-проект несколько точек. из того, что я прочитал, после того, как матрица проекции применяется к вершине, вершина заканчивается в пространстве клипа. в этом случае, если -w < x, y, z < w Видно, что вершина видна, иначе она находится за пределами видимой области, и ее нужно обрезать. проблема в том, что я не могу получить вершину, которая будет равна -w < x, y, z < w. я должен делать что-то неправильно, но я не могу понять, что это такое. Я стараюсь придерживаться соглашений openGL, где это возможно (система координат и т. д.). пожалуйста, ознакомьтесь с этим SSCCE.Координаты 3D-проекции перспективы в пространстве клипов

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

#define DEG2RAD 0.01745329f 

// multiplies two matrices 
void m3d_matrixMul(const float matrix1[], const float matrix2[], float destination[]) 
{ 
    int i, row, col; 

    for (i = 15; i >= 0; i--) 
    { 
     row = i % 4; 
     col = i/4 * 4; 
     destination[i] = matrix1[row] * matrix2[col] + matrix1[row + 4] * matrix2[col + 1] + matrix1[row + 8] * matrix2[col + 2] + matrix1[row + 12] * matrix2[col + 3]; 
    } 
} 

// multiplies matrix with vector/vertex 
void m3d_matVecMul(const float matrix[], const float vector[], float destination[]) 
{ 
    float x = vector[0], y = vector[1], z = vector[2], w = vector[3]; 

    destination[0] = x * matrix[0] + y * matrix[4] + z * matrix[8] + w * matrix[12]; 
    destination[1] = x * matrix[1] + y * matrix[5] + z * matrix[9] + w * matrix[13]; 
    destination[2] = x * matrix[2] + y * matrix[6] + z * matrix[10] + w * matrix[14]; 
    destination[3] = x * matrix[3] + y * matrix[7] + z * matrix[11] + w * matrix[15]; 
} 

// creates the projection matrix (column major) 
void m3d_getFrustum(float left, float right, float bottom, float top, float near, float far, float matrix[]) 
{ 
    matrix[0] = 2.0f * near/(right - left); 
    matrix[1] = 0.0f; 
    matrix[2] = 0.0f; 
    matrix[3] = 0.0f; 
    matrix[4] = 0.0f; 
    matrix[5] = 2.0f * near/(top - bottom); 
    matrix[6] = 0.0f; 
    matrix[7] = 0.0f; 
    matrix[8] = (right + left)/(right - left); 
    matrix[9] = (top + bottom)/(top - bottom); 
    matrix[10] = -(far + near)/(far - near); 
    matrix[11] = -1.0f; 
    matrix[12] = 0.0f; 
    matrix[13] = 0.0f; 
    matrix[14] = -2.0f * far * near/(far - near); 
    matrix[15] = 0.0f; 
} 

void m3d_getPerspective(float vfov, float aspect, float near, float far, float matrix[]) 
{ 
    float height = tanf(vfov * 0.5f * DEG2RAD) * near; 
    float width = aspect * height; 
    m3d_getFrustum(-width, width, -height, height, near, far, matrix); 
} 

void m3d_getIdentity(float matrix[]) 
{ 
    matrix[0] = 1.0f; 
    matrix[1] = 0.0f; 
    matrix[2] = 0.0f; 
    matrix[3] = 0.0f; 
    matrix[4] = 0.0f; 
    matrix[5] = 1.0f; 
    matrix[6] = 0.0f; 
    matrix[7] = 0.0f; 
    matrix[8] = 0.0f; 
    matrix[9] = 0.0f; 
    matrix[10] = 1.0f; 
    matrix[11] = 0.0f; 
    matrix[12] = 0.0f; 
    matrix[13] = 0.0f; 
    matrix[14] = 0.0f; 
    matrix[15] = 1.0f; 
} 

void m3d_translate(float x, float y, float z, float matrix[]) 
{ 
    matrix[12] += x; 
    matrix[13] += y; 
    matrix[14] += z; 
} 

int main(void) 
{ 
    float vertex[4] = {0.5f, 0.5f, 0.5f, 1.0f}; 
    float modelView[16]; 
    float projection[16]; 
    float mvp[16]; 
    char buffer[4]; 

    // initialize model-view matrix with identity matrix 
    m3d_getIdentity(modelView); 
    // add z-translation to model-view matrix 
    m3d_translate(0.0f, 0.0f, -2.0f, modelView); 
    // get perspective projection matrix 
    m3d_getPerspective(45.0f, 800.0f/600.0f, -0.5f, -1000.0f, projection); 
    // fuse projection and model-view matrix into one matrix 
    m3d_matrixMul(projection, modelView, mvp); 
    // apply model-view-projection matrix to vertex 
    m3d_matVecMul(mvp, vertex, vertex); 

    printf("Projected vertex: %f, %f, %f, %f\n", vertex[0], vertex[1], vertex[2], vertex[3]); 
    printf("Press ENTER to quit."); 
    fgets(buffer, 4, stdin); 
    return EXIT_SUCCESS; 

    // Projected vertex: 0.905330, 1.207107, 2.502001, 1.500000 
} 

thx заблаговременно.

+0

По крайней мере, 'm3d_matVecMul (ПМК, вершина, вершина)' перезаписывает входную вершину с частями результата при размножении, если я не ошибаюсь. Массивы всегда передаются указателем, поэтому вы не можете изменять вершину через вектор-константу, но по мере того, как пункты назначения указывают на тот же адрес, вы можете через пункт назначения. Я предлагаю вам также проверить другие методы и взять ручку и бумагу, чтобы проверить матричные вычисления, по крайней мере, для одного нетривиального примера (или matlab). – Thomas

+0

привет! thx для вашего комментария. на самом деле это предназначено. значения переопределяются, потому что старые значения больше не нужны. в конце я хочу только проецируемые координаты. насколько я могу видеть, что это не проблема, не так ли? плохо проверяйте вычисления вручную, но я не уверен, что это приведет к решению. – user3563584

ответ

0

Хорошо, я снова посмотрел на ваш код, и я думаю, что что-то не так с вашим вычислением матрицы проекций. Я заменил этот метод m3d_getPerspective с определением от gluPerspective и добавил метод printMatrix (pm). В некоторых примерах результаты теперь кажутся разумными (код ниже).

Я не нашел вашу ошибку, так как не знаю, почему именно вы делаете эту усечку - обходной путь. Подсказка может показаться, что вы использовали tanf, где я теперь использовал cotangens, но это была не полная проблема, я думаю. Кроме того, установка ближнего и дальнего к отрицательным значениям не является интуитивным, поскольку они должны представлять расстояния. Ваши умножения, похоже, все в порядке, я не узнал, что вы сначала копировали вершину в x, y, z, w.

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

#define DEG2RAD 0.01745329f 

void m3d_matrixMul(const float matrix1[], const float matrix2[], float destination[]) 
{ 
    int i, row, col; 

    for (i = 15; i >= 0; i--) 
    { 
     row = i % 4; 
     col = i/4 * 4; 
     destination[i] = matrix1[row] * matrix2[col] + matrix1[row + 4] * matrix2[col + 1] + matrix1[row + 8] * matrix2[col + 2] + matrix1[row + 12] * matrix2[col + 3]; 
    } 
} 

void m3d_matVecMul(const float matrix[], const float vector[], float destination[]) 
{ 
    float x = vector[0], y = vector[1], z = vector[2], w = vector[3]; 

    destination[0] = x * matrix[0] + y * matrix[4] + z * matrix[8] + w * matrix[12]; 
    destination[1] = x * matrix[1] + y * matrix[5] + z * matrix[9] + w * matrix[13]; 
    destination[2] = x * matrix[2] + y * matrix[6] + z * matrix[10] + w * matrix[14]; 
    destination[3] = x * matrix[3] + y * matrix[7] + z * matrix[11] + w * matrix[15]; 
} 

//not used anymore 
void m3d_getFrustum(float left, float right, float bottom, float top, float near, float far, float matrix[]) 
{ 
    matrix[0] = 2.0f * near/(right - left); 
    matrix[1] = 0.0f; 
    matrix[2] = 0.0f; 
    matrix[3] = 0.0f; 
    matrix[4] = 0.0f; 
    matrix[5] = 2.0f * near/(top - bottom); 
    matrix[6] = 0.0f; 
    matrix[7] = 0.0f; 
    matrix[8] = (right + left)/(right - left); 
    matrix[9] = (top + bottom)/(top - bottom); 
    matrix[10] = -(far + near)/(far - near); 
    matrix[11] = -1.0f; 
    matrix[12] = 0.0f; 
    matrix[13] = 0.0f; 
    matrix[14] = -2.0f * far * near/(far - near); 
    matrix[15] = 0.0f; 
} 

void m3d_getPerspective(float vfov, float aspect, float near, float far, float matrix[]) 
{ 
    float f = 1.0f/tanf(vfov * 0.5f * DEG2RAD); 

    matrix[0] = f/aspect; 
    matrix[1] = 0.0f; 
    matrix[2] = 0.0f; 
    matrix[3] = 0.0f; 

    matrix[4] = 0.0f; 
    matrix[5] = f; 
    matrix[6] = 0.0f; 
    matrix[7] = 0.0f; 

    matrix[8] = 0; 
    matrix[9] = 0; 
    matrix[10] = (near+far)/(near-far); 
    matrix[11] = -1; 

    matrix[12] = 0.0f; 
    matrix[13] = 0.0f; 
    matrix[14] = 2.0f * far * near/(near-far); 
    matrix[15] = 0.0f; 



} 

void m3d_getIdentity(float matrix[]) 
{ 
    matrix[0] = 1.0f; 
    matrix[1] = 0.0f; 
    matrix[2] = 0.0f; 
    matrix[3] = 0.0f; 
    matrix[4] = 0.0f; 
    matrix[5] = 1.0f; 
    matrix[6] = 0.0f; 
    matrix[7] = 0.0f; 
    matrix[8] = 0.0f; 
    matrix[9] = 0.0f; 
    matrix[10] = 1.0f; 
    matrix[11] = 0.0f; 
    matrix[12] = 0.0f; 
    matrix[13] = 0.0f; 
    matrix[14] = 0.0f; 
    matrix[15] = 1.0f; 
} 

void m3d_translate(float x, float y, float z, float matrix[]) 
{ 
    matrix[12] += x; 
    matrix[13] += y; 
    matrix[14] += z; 
} 

void pm(float* m) { 
    printf("%f, %f, %f, %f\n", m[0], m[4], m[8], m[12]); 
    printf("%f, %f, %f, %f\n", m[1], m[5], m[9], m[13]); 
    printf("%f, %f, %f, %f\n", m[2], m[6], m[10], m[14]); 
    printf("%f, %f, %f, %f\n", m[3], m[7], m[11], m[15]); 
    printf("\n"); 
} 

int main(void) 
{ 
    //float vertex[4] = {0.0f, 0.0f, -1000.0f, 1.0f}; //point at center & far 
    //float vertex[4] = {0.0f, 0.0f, -0.5f, 1.0f}; //point at center & near 
    float vertex[4] = {(800.0f/600.0f)*1.0f, 1.0f, -2.0f, 1.0f}; //point at one quater of the x and y range 
    float modelView[16]; 
    float projection[16]; 
    float mvp[16]; 
    char buffer[4]; 

    m3d_getIdentity(modelView); 
    pm(modelView); 
    m3d_translate(0.0f, 0.0f, 0.0f, modelView); 
    pm(modelView); 
    m3d_getPerspective(90.0f, 800.0f/600.0f, 0.5f, 1000.0f, projection); 
    pm(projection); 
    m3d_matrixMul(projection, modelView, mvp); 
    pm(mvp); 
    m3d_matVecMul(mvp, vertex, vertex); 

    printf("Projected vertex: %f, %f, %f, %f\n", vertex[0], vertex[1], vertex[2], vertex[3]); 
    printf("Press ENTER to quit."); 
    fgets(buffer, 4, stdin); 
    return EXIT_SUCCESS; 
} 
+0

благодарит за ваше терпение! im в настоящее время очень занят, поэтому я не могу проверить его прямо сейчас, но скоро. вы мне уже много помогли. по крайней мере теперь я знаю, на что смотреть. «усечение - обходное решение» - это просто метод удобства. Я получил это от [scratchapixel] (http://www.scratchapixel.com/). Я использую отрицательные значения z, потому что, насколько я знаю, в openGL камера находится на 0,0,0 и смотрит вниз на нагативную ось z, поэтому, если ближняя и дальняя плоскости должны быть перед камерой, они должны быть отрицательным. может быть неправильным ... – user3563584

+0

Код для «обходного пути frustum» также можно найти в [OpenGL wiki] (https://www.opengl.org/wiki/GluPerspective_code) – user3563584

+0

Отрицательные z-значения для zNear и zFar похоже, проблема. Он работает безупречно с положительными значениями. Thx снова. – user3563584

Смежные вопросы