我试图从上面3D sphare的8个顶点在3D空间中绘制8个点。
我使用了以下代码:
#include "Coordinates2d.h"
#include "Point3d.h"
const double zoom = 500;
int main()
{
Coordinates2d::ShowWindow("3D Primitives!");
std::vector<Point3d> points;
points.push_back(Point3d(0,0,20));
points.push_back(Point3d(0,100,20));
points.push_back(Point3d(120,100,20));
points.push_back(Point3d(120,0,20));
points.push_back(Point3d(0,0,120));
points.push_back(Point3d(0,100,120));
points.push_back(Point3d(120,100,120));
points.push_back(Point3d(120,0,120));
for(int i=0 ; i<points.size() ; i++)
{
Coordinates2d::Draw(points[i], zoom);
}
Coordinates2d::Wait();
}
其中,Point3D如下所示:
#ifndef _POINT_3D_
#define _POINT_3D_
#include "graphics.h"
#include "Matrix.h"
#include "Point2d.h"
#include <cmath>
#include <iostream>
struct Point3d
{
double x;
double y;
double z;
public:
Point3d();
Point3d(double x, double y, double z);
Point3d(Point3d const & point);
Point3d & operator=(Point3d const & point);
Point3d & operator+(int scalar);
bool operator==(Point3d const & point);
bool operator!=(Point3d const & point);
Point3d Round()
{
return Point3d(floor(this->x + 0.5), floor(this->y + 0.5), floor(this->z + 0.5));
}
void Show()
{
std::cout<<"("<<x<<", "<<y<<", "<<z<<")";
}
bool IsValid();
double Distance(Point3d & point);
void SetMatrix(const Matrix & mat);
Matrix GetMatrix() const;
Point2d ConvertTo2d(double zoom)
{
return Point2d(x*zoom/(zoom-z), y*zoom/(zoom-z));
}
};
#endif
#ifndef _COORDINATES_2D_
#define _COORDINATES_2D_
#include "graphics.h"
#include "Point2d.h"
#include "Point3d.h"
#include "Line3d.h"
class Coordinates2d
{
private:
static Point2d origin;
public:
static void Wait();
static void ShowWindow(char str[]);
private:
static void Draw(Point2d & pt);
public:
static void Draw(Point3d & pt, double zoom)
{
Coordinates2d::Draw(pt.ConvertTo2d(zoom));
}
};
#endif
我期待输出如下:
但输出结果如下:
我真的很想移动我的观察镜头。
如何达到我想要的效果?
答案 0 :(得分:3)
我从评论中看到,您通过巧妙的公式获得了理想的结果。如果你对使用矩阵的“标准”图形方式感兴趣,我希望这篇文章可以帮助你。
我发现了一个很好的页面,用于解释OpenGL的投影矩阵,它也扩展到投影的一般数学。
如果你想深入探讨here is the very well written article,请详细解释它的步骤,并且总体上非常值得称道。
下图显示了您要做的第一部分。
因此左侧的图像是您希望相机看到的“观看体积”。你可以看到,在这种情况下,投影中心(基本上是相机的焦点)位于原点。
但是等等,你说,我不希望投影的中心位于原点!我知道,我们稍后会介绍。
我们在这里做的是将左侧奇怪形状的音量转换为我们称之为右侧的“标准化坐标”。因此,我们将观察量映射到每个方向的-1到1的范围。基本上,我们通过数学方式将不规则形状的观察体积拉伸到以原点为中心的2x2x2立方体中。
此操作是通过以下矩阵完成的,再次来自我上面链接的优秀文章。
所以请注意,你有六个变量。
t = top
b = bottom
l = left
r = right
n = near
f =远
这六个变量定义了您查看音量。 Far
未在上图中标注,但它是图像中距离原点最远的平面的距离。
上图显示了将观看体积输出到标准化坐标的投影矩阵。一旦坐标处于这种形式,您可以通过简单地忽略z坐标使其平坦,这类似于您已经完成的一些工作(很好的工作!)。
所以我们都准备好从原点查看东西。但是,让我们说我们不希望从原点进行查看,而是希望从后面和后面的某个地方查看。
我们可以做到!但是不是移动我们的观察区域(我们在这里很好地计算了数学),它可能是直观的,更容易移动我们想要查看的所有点。
这可以通过将所有点乘以平移矩阵来完成。 这是the wikipedia page for translation,我从中获取了以下矩阵。
Vx,Vy和Vz是我们想要在x,y和z方向上移动物体的量。请记住,如果我们想要在正x方向上移动相机,我们需要负Vx,反之亦然。这是因为我们正在移动点而不是相机。如果你愿意的话,请随意尝试看看。
你可能也注意到我展示的两个矩阵都是4x4,你的坐标是3x1。这是因为矩阵意味着与齐次坐标一起使用。这些看似奇怪,因为它们使用4个变量来表示3D点,但它只是x,y,z和w,在这里你可以为你的点做w = 1。我相信这个变量用于深度缓冲,除此之外,它基本上普遍存在于图形的矩阵数学中,所以你会习惯于使用它。
现在你有这些矩阵,你可以将翻译应用到你的点,然后将视角应用到你得到的那些点。然后简单地忽略z组件,那就是你!您在x和y方向上有一个从-1到1的2D图像。