如何构建透视投影矩阵(无API)

时间:2013-08-23 14:08:00

标签: math graphics 3d transformation projection

我开发了一个简单的3D引擎(没有使用API​​),成功地将我的场景转换为世界和视图空间,但是使用透视投影矩阵(OpenGL样式)无法投影我的场景(从视图空间)。我不确定fov,近和远的值,我得到的场景是扭曲的。 我希望有人能指导我如何使用示例代码正确构建和使用透视投影矩阵。在此先感谢您的帮助。

矩阵构建:

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

矩阵使用:

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

2 个答案:

答案 0 :(得分:27)

以下是透视投影矩阵的典型实现。 这里有一个解释所有内容的良好链接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;
}

答案 1 :(得分:3)

另一个可能有用的功能。

这个参数基于left / right / top / bottom / near / far参数(在OpenGL中使用):

router.get('/:date/:page', function(req, res){

    var db = req.db;
    var collection = db.get('collectionXYZ');

    collection.find([...], function(e, docs){
        res.json(docs);
    });
});

// this gets skipped  (because it thinks it's a parameter to the page route?)
router.get('/:date/count', function(req, res){
    var dateStart = new Date(req.params.date);

    var db = req.db;
    var collection = db.get('collectionXYZ');

    collection.count([...], function(e, docs){
        res.json(docs);
    });
});