Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
3d 如何应用变换矩阵?_3d_Projection - Fatal编程技术网

3d 如何应用变换矩阵?

3d 如何应用变换矩阵?,3d,projection,3d,Projection,我试图获得3D空间中某个点的2D屏幕坐标,也就是说,我知道摄像机的位置,它的平移、倾斜和滚动,我有我想要投影的点的3D x、y、z坐标 我很难理解变换/投影矩阵,我希望这里的一些聪明人能帮助我;) 以下是我迄今为止收集的测试代码: public class TransformTest { public static void main(String[] args) { // set up a world point (Point to Project) double[] wp

我试图获得3D空间中某个点的2D屏幕坐标,也就是说,我知道摄像机的位置,它的平移、倾斜和滚动,我有我想要投影的点的3D x、y、z坐标

我很难理解变换/投影矩阵,我希望这里的一些聪明人能帮助我;)

以下是我迄今为止收集的测试代码:

public class TransformTest {

public static void main(String[] args) {

    // set up a world point (Point to Project)
    double[] wp = {100, 100, 1};
    // set up the projection centre (Camera Location)
    double[] pc = {90, 90, 1};

    double roll = 0;
    double tilt = 0;
    double pan = 0;

    // translate the point
    vSub(wp, pc, wp);

    // create roll matrix
    double[][] rollMat = {
            {1, 0, 0},
            {0, Math.cos(roll), -Math.sin(roll)},
            {0, Math.sin(roll), Math.cos(roll)},
    };
    // create tilt matrix
    double[][] tiltMat = {
            {Math.cos(tilt), 0, Math.sin(tilt)},
            {0, 1, 0},
            {-Math.sin(tilt), 0, Math.cos(tilt)},
    };
    // create pan matrix
    double[][] panMat = {
            {Math.cos(pan), -Math.sin(pan), 0},
            {Math.sin(pan), Math.cos(pan), 0},
            {0, 0, 1},
    };

    // roll it
    mvMul(rollMat, wp, wp);
    // tilt it
    mvMul(tiltMat, wp, wp);
    // pan it
    mvMul(panMat, wp, wp);

}

public static void vAdd(double[] a, double[] b, double[] c) {
    for (int i=0; i<a.length; i++) {
        c[i] = a[i] + b[i];
    }
}

public static void vSub(double[] a, double[] b, double[] c) {
    for (int i=0; i<a.length; i++) {
        c[i] = a[i] - b[i];
    }      
}

public static void mvMul(double[][] m, double[] v, double[] w) {

    // How to multiply matrices?
} }
公共类测试{
公共静态void main(字符串[]args){
//设置世界点(点到项目)
double[]wp={100100,1};
//设置投影中心(摄像机位置)
双[]pc={90,90,1};
双辊=0;
双倾斜=0;
双盘=0;
//翻译要点
vSub(wp、pc、wp);
//创建滚动矩阵
双[][]辊垫={
{1, 0, 0},
{0,Math.cos(roll),-Math.sin(roll)},
{0,Math.sin(roll),Math.cos(roll)},
};
//创建倾斜矩阵
双[][]倾斜垫={
{Math.cos(tilt),0,Math.sin(tilt)},
{0, 1, 0},
{-Math.sin(tilt),0,Math.cos(tilt)},
};
//创建泛矩阵
双[][]窗格={
{Math.cos(pan),-Math.sin(pan),0},
{Math.sin(pan),Math.cos(pan),0},
{0, 0, 1},
};
//滚
mvMul(rollMat,wp,wp);
//倾斜
mvMul(tiltMat,wp,wp);
//平底锅
mvMul(panMat、wp、wp);
}
公共静态无效vAdd(双[]a,双[]b,双[]c){

对于(int i=0;i这个问题的范围太大了,无法在这里得到一个好的答案:我建议你阅读一本关于这个主题的好参考书。我一直喜欢…

这是一个复杂的东西。请阅读一本关于这个主题的书,了解所有的数学和细节。如果你打算详细研究这个东西,你需要知道答案这是一个简单的答案,这样你就可以全身湿透,四处闲逛了。

乘矩阵 首先要做的事。矩阵相乘是一个好方法

假设你有矩阵A,B和C,其中AB=C。假设你想计算第3行第2列矩阵C的值

  • 以A的第三行和B的第二列为例。现在,A和B中的值的数量应该相同。(如果没有定义这两个矩阵的矩阵乘法,则不能这样做。)如果两者都是4×4矩阵,则A(第3行)中应该有4个值,B(第2列)中应该有4个值
  • 将A的每个值与B的每个值相乘。最后应得到4个新值
  • 添加这些值
现在矩阵C的值位于第3行第2列。当然,挑战在于以编程方式实现这一点

/* AB = C

Row-major ordering
a[0][0] a[0][2] a[0][3]...
a[1][0] a[1][4] ...
a[2][0] ...
...*/
public static mmMul(double[][] a, double[][] b, double[][] c) {
    c_height = b.length; // Height of b
    c_width = a[0].length; // Width of a
    common_side = a.length; // Height of a, width of b

    for (int i = 0; i < c_height; i++) {
        for (int j = 0; j < c_width; j++) {
            // Ready to calculate value of c[i][j]
            c[i][j] = 0;

            // Iterate through ith row of a, jth col of b in lockstep
            for (int k = 0; k < common_side; k++) {
                c[i][j] += a[i][k] * b[k][j];
            }
        }
    }
}
在本例中,Av=v1,其中v1是变换点。像矩阵乘法一样执行此乘法,其中a为4×4,v为4×1。最终将得到一个4×1矩阵(这是另一个列向量)

现在,如果要应用多个变换矩阵,请首先将它们组合成一个变换矩阵。按照要应用的顺序将矩阵相乘即可

以编程方式,您应该从单位矩阵开始,并将每个变换矩阵右乘。让I4为4×4单位矩阵,让A1、A2、A3……为变换矩阵。让最终的变换矩阵为最终矩阵

最后← I4
最后← 最终A1
最后← 最终A2
最后← 最终A3

请注意,我使用该箭头表示赋值。当您实现此操作时,请确保在矩阵乘法计算中仍使用它时,不要覆盖final!复制一份

最后,执行与上面相同的乘法:最终v=v1


从头到尾 摄影机变换应表示为视图矩阵。在此处执行Aview v=v1操作。(v以4×1列向量表示世界坐标,最后是Aview。)

投影变换描述透视变换。这是使更近的对象更大、更远的对象更小的原因。这是在摄影机变换之后执行的。如果您还不想透视,只需将单位矩阵用于投影矩阵。无论如何,在此处执行v1=v2

接下来,你需要做一个透视图分割。这将深入研究同质坐标,我还没有描述。无论如何,用v2的最后一个分量来分割v2的每个分量。如果v2=[x,y,z,w]t,那么用w来分割每个分量(包括w本身)。你应该得到w=1。(如果您的投影矩阵是单位矩阵,如我前面所述,则此步骤不应执行任何操作。)

如果跳过透视图和透视图分割步骤,请使用
v_view
而不是上面的
v_ndc

这与的集合非常相似。区别在于您从世界坐标开始,而OpenGL从对象坐标开始。区别如下:

  • 从世界坐标开始
    • OpenGL从对象坐标开始
  • 使用视图矩阵将世界坐标转换为眼睛坐标
    • OpenGL使用ModelView矩阵将对象坐标转换为眼睛坐标
从那以后,一切都是一样的。

我已经发布了一些代码,可以满足您的大部分需求

它包含OpenGL
gluPerspective()
gluLookAt()函数的Java实现:

Camera camera = new Camera();

Point3d eye = new Point3d(3, 4, 8);
Point3d center = new Point3d(0, 0, 0);
Vector3d up = new Vector3d(0, 1, 0);

camera.perspective(60.0, 1.6, 0.1, 20); // vertical fov, aspect ratio, znear, zfar
camera.lookAt(eye, center, up);
要使用其中的
project()
函数,请使用:

void plot(Camera camera, Point4d p) {
    Point4d q = Camera.project(p);
    float x = q.x / q.w;
    float y = q.y / q.w;
    ...
}

返回的
x
y
值在-0.5…0.5

范围内,这与您要查找的类似吗?不,这不是我想要的,他们已经知道2d屏幕坐标,我正在尝试查找它们。他们也不知道相机位置,我知道。除了应用平移、倾斜和r之外,还有更多吗油毡
// A composite transformation matrix (roll, then tilt)

double a_final[4][4] =
{
    {1, 0, 0, 0},
    {0, 1, 0, 0},
    {0, 0, 1, 0},
    {0, 0, 0, 1}
}; // the 4 x 4 identity matrix

double a_final_copy[4][4];
mCopy(a_final, a_final_copy); // make a copy of a_final
mmMul(rollMat, a_final_copy, a_final);
mCopy(a_final, a_final_copy); // update the copy
mmMul(tiltMat, a_final_copy, a_final);
// Use the above matrix to transform v
mmMul(a_final, v, v_1);
// World coordinates to eye coordinates
// A_view is a_final from above
mmMult(a_view, v_world, v_view);
// Eye coordinates to clip coordinates
// If you don't care about perspective, SKIP THIS STEP
mmMult(a_projection, v_view, v_eye);
// Clip coordinates to normalized device coordinates
// If you skipped the previous step, SKIP THIS STEP
for (int i = 0; i < 4; i++) {
    v_ndc[i] = v_eye[i] / v[3];
}
x = v_ndc[0]
y = v_ndc[1]
z = v_ndc[2]  // unused; your screen is 2D
Camera camera = new Camera();

Point3d eye = new Point3d(3, 4, 8);
Point3d center = new Point3d(0, 0, 0);
Vector3d up = new Vector3d(0, 1, 0);

camera.perspective(60.0, 1.6, 0.1, 20); // vertical fov, aspect ratio, znear, zfar
camera.lookAt(eye, center, up);
void plot(Camera camera, Point4d p) {
    Point4d q = Camera.project(p);
    float x = q.x / q.w;
    float y = q.y / q.w;
    ...
}