我有透视投影的矩阵。但我不知道如何将这些矩阵相乘。

huangapple go评论75阅读模式
英文:

I have matrices for perspective projection. but I don't know how to multiply the matrices

问题

我有一段代码,其中有一个带有顶点和三角形的Object3D结构体,我还有一个类,模拟透视摄像机,但我不知道如何像这样乘以矩阵:

projectionMatrix * (vertices+cameraPos) * toScreenMatrix

代码(3D.h):

#include <list>
#include <cmath>
#include <iostream>

struct Object3D {
    float vertices;//{ {1.0, 1.0, -1.0, 1}, {1.0, -1.0, -1.0, 1}, {1.0, 1.0, 1.0, 1}, {1.0, -1.0, 1.0, 1}, {-1.0, 1.0, -1.0, 1}, {-1.0, -1.0, -1.0, 1}, {-1.0, 1.0, 1.0, 1}, {-1.0, -1.0, 1.0, 1} };
    float triangles;//{ {4, 2, 0}, {2, 7, 3}, {6, 5, 7}, {1, 7, 5}, {0, 3, 1}, {4, 1, 5}, {4, 6, 2}, {2, 6, 7}, {6, 4, 5}, {1, 3, 7}, {0, 2, 3}, {4, 0, 1} };
};

class PerspectiveProjectionCamera {
public:
    float projectionMatrix[4][4];
    float toScreenMatrix[4][4];
    float position[3];
    int hwidth;
    int hheight;
    void init(float nearplane, float farplane, int width, int height, float FOV) { //FOV: 14719667 (π/3)
        vFOV = FOV * (height / width);
        right = tan(FOV / 2);
        left = -right;
        top = tan(vFOV / 2);
        bottom = -top;
        hwidth = (int)width / 2;
        hheight = (int)height / 2;
        m00 = 2 / (right - left);
        m11 = 2 / (top - bottom);
        m22 = (farplane + nearplane) / (farplane - nearplane);
        m32 = -2 * nearplane * farplane / (farplane - nearplane);
        float projectionMatrix[4][4] = {
            {m00, 0, 0, 0 },
            {0, m11, 0, 0},
            {0, 0, m22, 1},
            {0, 0, m32, 0}
        };
        float toScreenMatrix[4][4] = {
            {(float)width / 2, 0, 0, 0},
            {0, -(float)height / 2, 0 ,0},
            {0, 0, 1, 0},
            {(float)width / 2, (float)height / 2, 0, 0}
        };
    }
private:
    double vFOV;
    double right;
    double left;
    double top;
    double bottom;
    double m00;
    double m11;
    double m22;
    double m32;
};

如果你需要其他代码,我可以提供给你!

我尝试过三次使用不同的矩阵乘法函数,其中一个导致了我的计算机崩溃(不要问),它们都产生了错误。

我期望能够以每秒超过10帧的速度绘制100,000个三角形。

英文:

I have a bit of code that has a Object3D struct with vertices and triangles
and I have a class that replicates a perspective camera, but I don't know how to multiply the matrices like:

projectionMatrix * (vertices+cameraPos) * toScreenMatrix

Code (3D.h):


#include&lt;list&gt;
#include &lt;cmath&gt;
#include &lt;iostream&gt;

struct Object3D {
    float vertices;//{ {1.0, 1.0, -1.0, 1}, {1.0, -1.0, -1.0, 1}, {1.0, 1.0, 1.0, 1}, {1.0, -1.0, 1.0, 1}, {-1.0, 1.0, -1.0, 1}, {-1.0, -1.0, -1.0, 1}, {-1.0, 1.0, 1.0, 1}, {-1.0, -1.0, 1.0, 1} };
    float triangles;//{ {4, 2, 0}, {2, 7, 3}, {6, 5, 7}, {1, 7, 5}, {0, 3, 1}, {4, 1, 5}, {4, 6, 2}, {2, 6, 7}, {6, 4, 5}, {1, 3, 7}, {0, 2, 3}, {4, 0, 1} };
};

class PerspectiveProjectionCamera {
public:
    float projectionMatrix[4][4];
    float toScreenMatrix[4][4];
    float position[3];
    int hwidth;
    int hheight;
    void init(float nearplane, float farplane, int width, int height, float FOV) { //FOV: 14719667 (π/3)
        vFOV = FOV * (height / width);
        right = tan(FOV / 2);
        left = -right;
        top = tan(vFOV / 2);
        bottom = -top;
        hwidth = (int)width / 2;
        hheight = (int)height / 2;
        m00 = 2 / (right - left);
        m11 = 2 / (top - bottom);
        m22 = (farplane + nearplane) / (farplane - nearplane);
        m32 = -2 * nearplane * farplane / (farplane - nearplane);
        float projectionMatrix[4][4] = {
            {m00, 0, 0, 0 },
            {0, m11, 0, 0},
            {0, 0, m22, 1},
            {0, 0, m32, 0}
        };
        float toScreenMatrix[4][4] = {
            {(float)width / 2, 0, 0, 0},
            {0, -(float)height / 2, 0 ,0},
            {0, 0, 1, 0},
            {(float)width / 2, (float)height / 2, 0, 0}
        };
    }
private:
    double vFOV;
    double right;
    double left;
    double top;
    double bottom;
    double m00;
    double m11;
    double m22;
    double m32;
};

If you need the other code I can give it to you!

I have tried three times using different functions for matrix multiplication and one made my computer crash (don't ask) and they all give errors.

I'm expecting to be able to draw 100K Triangles at more that 10FPS

答案1

得分: 1

以下是代码的翻译部分:

"在内部学习如何完成此操作并避免链接到第三方库,这可能会很麻烦,您基本上只需使用简单的C风格代数例程,如下所示

#include <cstdint>
#include <iostream>

using Matrix = float[4][4];

void multiply(const Matrix &a, const Matrix &b, Matrix &c) {
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            float sum = 0;
            for (int k = 0; k < 4; ++k) {
                sum += a[i][k] * b[k][j];
            }
            c[i][j] = sum;
        }
    }
}

void sum(const Matrix &a, const Matrix &b, Matrix &c) {
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            c[i][j] = a[i][j] + b[i][j];
        }
    }
}

void print(const Matrix &a) {
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            std::cout << a[i][j] << " ";
        }
        std::cout << std::endl;
    }
}

由于它们是C风格的函数,您无法获得C++语法糖,必须直接调用它们,坦率地说,这不是什么大问题。

Matrix I = {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
Matrix x = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};

int main() {
    Matrix res;
    multiply(I, x, res);
    print(res);
    sum(I, x, res);
    print(res);
}

结果是

程序标准输出
1 2 3 4 
5 6 7 8 
9 10 11 12 
13 14 15 16 
2 2 3 4 
5 7 7 8 
9 10 12 12 
13 14 15 17 

Godbolt链接:https://godbolt.org/z/f4MWExjMM"

英文:

In the interest of learning how this is done internally and to avoid linking against 3rd party libraries, which can be a pain, you can basically just use simple C-style algebra routines as follows

#include &lt;cstdint&gt;
#include &lt;iostream&gt;

using Matrix = float[4][4];

void multiply( const Matrix&amp;a, const Matrix&amp;b, Matrix&amp;c ) {
    for ( int i=0; i&lt;4; ++i ) {
        for ( int j=0; j&lt;4; ++j ) {
            float sum = 0;
            for ( int k=0; k&lt;4; ++k ) {
                sum += a[i][k]*b[k][j];
            }
            c[i][j] = sum;
        }
    }
}

void sum( const Matrix&amp;a, const Matrix&amp;b, Matrix&amp;c ) {
    for ( int i=0; i&lt;4; ++i ) {
        for ( int j=0; j&lt;4; ++j ) {
            c[i][j] = a[i][j]+b[i][j];
        }
    }
}

void print( const Matrix&amp; a ) {
    for ( int i=0; i&lt;4; ++i ) {
        for ( int j=0; j&lt;4; ++j ) {
            std::cout &lt;&lt; a[i][j] &lt;&lt; &quot; &quot;;
        }
        std::cout &lt;&lt; std::endl;
    }
}

As they are C-style functions, you do not get the C++ syntax sugar and have to call them directly, which is not a big deal to be frank.

Matrix I = {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
Matrix x = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};

int main() {
    Matrix res;
    multiply(I,x,res);
    print( res );
    sum(I,x,res);
    print( res );
}

Results in

Program stdout
1 2 3 4 
5 6 7 8 
9 10 11 12 
13 14 15 16 
2 2 3 4 
5 7 7 8 
9 10 12 12 
13 14 15 17 

Godbolt: https://godbolt.org/z/f4MWExjMM

答案2

得分: 1

对于更健壮和类似C++的解决方案,您可以按照以下步骤进行:

#include <iostream>
#include <vector>

struct Object3D {
    std::vector<std::vector<float>> vertices;
    std::vector<std::vector<int>> triangles;
};

class PerspectiveProjectionCamera {
public:
    std::vector<std::vector<float>> projectionMatrix;
    std::vector<std::vector<float>> toScreenMatrix;
    std::vector<float> position;
    int hwidth;
    int hheight;

    void init(float nearplane, float farplane, int width, int height, float FOV) {
        // 初始化代码在这里

        // 示例矩阵初始化
        projectionMatrix = {
            { m00, 0, 0, 0 },
            { 0, m11, 0, 0 },
            { 0, 0, m22, 1 },
            { 0, 0, m32, 0 }
        };

        toScreenMatrix = {
            { static_cast<float>(width) / 2, 0, 0, 0 },
            { 0, -static_cast<float>(height) / 2, 0, 0 },
            { 0, 0, 1, 0 },
            { static_cast<float>(width) / 2, static_cast<float>(height) / 2, 0, 0 }
        };
    }

    std::vector<std::vector<float>> multiplyMatrix(const std::vector<std::vector<float>>& matrixA, const std::vector<std::vector<float>>& matrixB) {
        // 省略部分
    }

    std::vector<std::vector<float>> transformVertices(const Object3D& object) {
        // 省略部分
    }

    std::vector<float> addVectors(const std::vector<float>& vectorA, const std::vector<float>& vectorB) {
        // 省略部分
    }
};

int main() {
    // 省略部分

    return 0;
}

即使这段代码也不能保证最佳性能。

要实现更优化的性能,您应该考虑使用第三方库,例如:

#include <iostream>
#include <Eigen/Dense>
#include <vector>

struct Object3D {
    std::vector<Eigen::Vector4f> vertices; // 将顶点存储为 Eigen 向量
    std::vector<Eigen::Vector3i> triangles; // 将三角形存储为 Eigen 向量
};

class PerspectiveProjectionCamera {
public:
    Eigen::Matrix4f projectionMatrix;
    Eigen::Matrix4f toScreenMatrix;
    Eigen::Vector3f position;
    int hwidth;
    int hheight;

    void init(float nearplane, float farplane, int width, int height, float FOV) {
        // 初始化代码在这里

        // 示例矩阵初始化
        projectionMatrix << m00, 0, 0, 0,
                            0, m11, 0, 0,
                            0, 0, m22, 1,
                            0, 0, m32, 0;

        toScreenMatrix << static_cast<float>(width) / 2, 0, 0, 0,
                          0, -static_cast<float>(height) / 2, 0, 0,
                          0, 0, 1, 0,
                          static_cast<float>(width) / 2, static_cast<float>(height) / 2, 0, 0;
    }

    std::vector<Eigen::Vector3f> transformVertices(const Object3D& object) {
        // 省略部分
    }
};

int main() {
    // 省略部分

    return 0;
}
英文:

For a more robust and cpp_like solution you can do as following :

#include &lt;iostream&gt;
#include &lt;vector&gt;
struct Object3D {
std::vector&lt;std::vector&lt;float&gt;&gt; vertices;
std::vector&lt;std::vector&lt;int&gt;&gt; triangles;
};
class PerspectiveProjectionCamera {
public:
std::vector&lt;std::vector&lt;float&gt;&gt; projectionMatrix;
std::vector&lt;std::vector&lt;float&gt;&gt; toScreenMatrix;
std::vector&lt;float&gt; position;
int hwidth;
int hheight;
void init(float nearplane, float farplane, int width, int height, float FOV) {
// Your initialization code here
// Example matrix initialization
projectionMatrix = {
{ m00, 0, 0, 0 },
{ 0, m11, 0, 0 },
{ 0, 0, m22, 1 },
{ 0, 0, m32, 0 }
};
toScreenMatrix = {
{ static_cast&lt;float&gt;(width) / 2, 0, 0, 0 },
{ 0, -static_cast&lt;float&gt;(height) / 2, 0, 0 },
{ 0, 0, 1, 0 },
{ static_cast&lt;float&gt;(width) / 2, static_cast&lt;float&gt;(height) / 2, 0, 0 }
};
}
std::vector&lt;std::vector&lt;float&gt;&gt; multiplyMatrix(const std::vector&lt;std::vector&lt;float&gt;&gt;&amp; matrixA, const std::vector&lt;std::vector&lt;float&gt;&gt;&amp; matrixB) {
int rowsA = matrixA.size();
int colsA = matrixA[0].size();
int colsB = matrixB[0].size();
std::vector&lt;std::vector&lt;float&gt;&gt; result(rowsA, std::vector&lt;float&gt;(colsB, 0));
for (int i = 0; i &lt; rowsA; ++i) {
for (int j = 0; j &lt; colsB; ++j) {
for (int k = 0; k &lt; colsA; ++k) {
result[i][j] += matrixA[i][k] * matrixB[k][j];
}
}
}
return result;
}
std::vector&lt;std::vector&lt;float&gt;&gt; transformVertices(const Object3D&amp; object) {
std::vector&lt;std::vector&lt;float&gt;&gt; transformedVertices;
for (const auto&amp; vertex : object.vertices) {
std::vector&lt;float&gt; transformedVertex = multiplyMatrix(projectionMatrix, addVectors(vertex, position));
transformedVertices.push_back(transformedVertex);
}
return transformedVertices;
}
std::vector&lt;float&gt; addVectors(const std::vector&lt;float&gt;&amp; vectorA, const std::vector&lt;float&gt;&amp; vectorB) {
int size = vectorA.size();
std::vector&lt;float&gt; result(size);
for (int i = 0; i &lt; size; ++i) {
result[i] = vectorA[i] + vectorB[i];
}
return result;
}
};
int main() {
PerspectiveProjectionCamera camera;
camera.init(/* nearplane, farplane, width, height, FOV */);
Object3D object;
// Initialize object.vertices and object.triangles
// Perform vertex transformations
std::vector&lt;std::vector&lt;float&gt;&gt; transformedVertices = camera.transformVertices(object);
// Example usage: printing transformed vertices
for (const auto&amp; vertex : transformedVertices) {
std::cout &lt;&lt; &quot;Transformed Vertex: &quot;;
for (const auto&amp; coordinate : vertex) {
std::cout &lt;&lt; coordinate &lt;&lt; &quot; &quot;;
}
std::cout &lt;&lt; std::endl;
}
return 0;
}

** Even this code doesn't guarantee best performance.**

To achieve more optimal performance, you should consider 3rd-party libraries like this:

#include &lt;iostream&gt;
#include &lt;Eigen/Dense&gt;
#include &lt;vector&gt;
struct Object3D {
std::vector&lt;Eigen::Vector4f&gt; vertices; // Store vertices as Eigen vectors
std::vector&lt;Eigen::Vector3i&gt; triangles; // Store triangles as Eigen vectors
};
class PerspectiveProjectionCamera {
public:
Eigen::Matrix4f projectionMatrix;
Eigen::Matrix4f toScreenMatrix;
Eigen::Vector3f position;
int hwidth;
int hheight;
void init(float nearplane, float farplane, int width, int height, float FOV) {
// Your initialization code here
// Example matrix initialization
projectionMatrix &lt;&lt; m00, 0, 0, 0,
0, m11, 0, 0,
0, 0, m22, 1,
0, 0, m32, 0;
toScreenMatrix &lt;&lt; static_cast&lt;float&gt;(width) / 2, 0, 0, 0,
0, -static_cast&lt;float&gt;(height) / 2, 0, 0,
0, 0, 1, 0,
static_cast&lt;float&gt;(width) / 2, static_cast&lt;float&gt;(height) / 2, 0, 0;
}
std::vector&lt;Eigen::Vector3f&gt; transformVertices(const Object3D&amp; object) {
std::vector&lt;Eigen::Vector3f&gt; transformedVertices;
transformedVertices.reserve(object.vertices.size());
for (const auto&amp; vertex : object.vertices) {
Eigen::Vector4f transformedVertex = projectionMatrix * (vertex + Eigen::Vector4f(position.x(), position.y(), position.z(), 1.0f));
transformedVertices.emplace_back(transformedVertex.head&lt;3&gt;());
}
return transformedVertices;
}
};
int main() {
PerspectiveProjectionCamera camera;
camera.init(/* nearplane, farplane, width, height, FOV */);
Object3D object;
// Initialize object.vertices and object.triangles
// Perform vertex transformations
std::vector&lt;Eigen::Vector3f&gt; transformedVertices = camera.transformVertices(object);
// Example usage: printing transformed vertices
for (const auto&amp; vertex : transformedVertices) {
std::cout &lt;&lt; &quot;Transformed Vertex: &quot; &lt;&lt; vertex.transpose() &lt;&lt; std::endl;
}
return 0;
}

huangapple
  • 本文由 发表于 2023年6月11日 21:13:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76450628.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定