之前介绍了几何阶段坐标变换的原理,接下来使用C++来进行实现。

Transform

首先定义一个Transform类,它存储了之前介绍的3个重要的变换矩阵和屏幕的宽高,负责处理顶点的变换,剔除

class Transform
{public:Matrix4f _worldTransform, _viewTransform, _perspectiveTransform, _transform;_INT32 _width, _height;public:Transform(){}Transform(Matrix4f worldTransform, Matrix4f viewTransform, Matrix4f perspectiveTransform,_INT32 width, _INT32 height);Transform(const Transform& other);public:void Init(_INT32 width, _INT32 height);void Init(Camera* camera, _INT32 width, _INT32 height, Matrix4f wordTransform);Vector4f ApplyTransform(const Vector4f& v) const;_INT32 CheckCVV(const Vector4f& v) const;Vector4f Homogenize(const Vector4f& v) const;void UpdateTransform();};
Transform::Transform(Matrix4f worldTransform, Matrix4f viewTransform, Matrix4f perspectiveTransform,_INT32 width, _INT32 height)
{_worldTransform = worldTransform;_viewTransform = viewTransform;_perspectiveTransform = perspectiveTransform;_transform = _worldTransform * _viewTransform * _perspectiveTransform;_width = width;_height = height;
}Transform::Transform(const Transform& other)
{_worldTransform = other._worldTransform;_viewTransform = other._viewTransform;_perspectiveTransform = other._perspectiveTransform;_width = other._width;_height = other._height;
}

Transform类初始化的方式有两种,一种是先创建Transform类,之后再自行修改其变换矩阵

void Transform::Init(_INT32 width, _INT32 height)
{_FLOAT aspect = (_FLOAT)width / (_FLOAT)height;_width = width;_height = height;_worldTransform.SetIdentity();_viewTransform.SetIdentity();_perspectiveTransform.SetIdentity();_transform = _worldTransform * _viewTransform * _perspectiveTransform;
}

另一种是传入一个摄像机对象和世界变换矩阵,利用摄像机来生成视图变换和透视变换矩阵,初始化一个完整的Transform对象

void Transform::Init(Camera* camera, _INT32 width, _INT32 height, Matrix4f worldTransform)
{_FLOAT aspect = (_FLOAT)width / (_FLOAT)height;_width = width;_height = height;_worldTransform = worldTransform;_viewTransform = camera->GetViewTransformMatrix();_perspectiveTransform = camera->GetPerspectiveTransformMarix();_transform = _worldTransform * _viewTransform * _perspectiveTransform;
}

当用户自行修改了变换矩阵后需要调用UpdateTransform函数更新Transform类

void Transform::UpdateTransform()
{_transform = _worldTransform * _viewTransform * _perspectiveTransform;
}

ApplyTransform函数负责对顶点进行变换

Vector4f Transform::ApplyTransform(const Vector4f& v) const
{return v * _transform;
}

CheckCVV函数负责检查顶点变换后是否在规则长方体内

_INT32 Transform::CheckCVV(const Vector4f& v) const
{_FLOAT w = v._w;_INT32 check = 0;if (v._z < 0){check |= 0x01;}if (v._z > w){check |= 0x02;}if (v._x < -w){check |= 0x04;}if (v._x > w){check |= 0x08;}if (v._y < -w){check |= 0x10;}if (v._y > w){check |= 0x20;}return check;
}

Homogenize负责将进行CVV检查后的顶点进行其次除法,并通过一个简单的线性变换将顶点的归一化坐标映射变换为屏幕坐标

Vector4f Transform::Homogenize(const Vector4f& v) const
{_FLOAT inverse = 1.0f / v._w;return Vector4f((v._x * inverse + 1.0f) * _width * 0.5f,(1.0f - v._y * inverse) * _height * 0.5f,v._z * inverse,1.0f);
}

Camera

视图变换矩阵和透视变换矩阵的生成都和摄像机相关,所以还需要定义一个摄像机类Camera,相机类中包含了相机的朝向(position、direction、up和horizontal向量),屏幕的宽高比,视锥体的视角,近裁剪平面和远裁剪平面到摄像机的距离

class Camera
{public:Vector3f _position, _direction, _up, _horizontal;_FLOAT _aspect, _angle, _near, _far;public:Camera(){}Camera(Vector3f position, Vector3f direction, Vector3f up,_FLOAT aspect, _FLOAT angle, _FLOAT near, _FLOAT far);Camera(Camera& other);public:Matrix4f GetViewTransformMatrix();static Matrix4f GetViewTransformMatrix(Vector4f position, Vector4f direction, Vector4f up);Matrix4f GetPerspectiveTransformMarix();static Matrix4f GetPerspectiveTransformMarix(_FLOAT angle, _FLOAT aspect, _FLOAT near, _FLOAT far);};

Camera在构造的时候只需要传入摄像机正对的方向和摄像机的正上方即可,摄像机正对的方向可以通过摄像机目标点的左边减去摄像机本身的位置得到,在构造函数中会通过叉乘来计算摄像机水平方向的向量

Camera::Camera(Vector3f position, Vector3f direction, Vector3f up,_FLOAT aspect, _FLOAT angle, _FLOAT near, _FLOAT far)
{_position = position;_direction = direction.Normalize();_up = up.Normalize();_horizontal = _up.Cross(_direction).Normalize();_aspect = aspect;_angle = angle;_near = near;_far = far;
}Camera::Camera(Camera& other)
{_position = other._position;_direction = other._direction.Normalize();_up = other._up.Normalize();_horizontal = _up.Cross(_direction).Normalize();_aspect = other._aspect;_angle = other._angle;_near = other._near;_far = other._far;
}

GetViewTransformMatrix函数根据前面的介绍的试图变换矩阵的原理构造出视图变换矩阵

Matrix4f Camera::GetViewTransformMatrix()
{Matrix4f viewTransform = Matrix4f();viewTransform(0, 0) = _horizontal._x;viewTransform(1, 0) = _horizontal._y;viewTransform(2, 0) = _horizontal._z;viewTransform(3, 0) = -_position.Dot(_horizontal);viewTransform(0, 1) = _up._x;viewTransform(1, 1) = _up._y;viewTransform(2, 1) = _up._z;viewTransform(3, 1) = -_position.Dot(_up);viewTransform(0, 2) = _direction._x;viewTransform(1, 2) = _direction._y;viewTransform(2, 2) = _direction._z;viewTransform(3, 2) = -_position.Dot(_direction);viewTransform(0, 3) = 0.0f;viewTransform(1, 3) = 0.0f;viewTransform(2, 3) = 0.0f;viewTransform(3, 3) = 1.0f;return viewTransform;
}Matrix4f Camera::GetViewTransformMatrix(Vector4f position, Vector4f direction, Vector4f up)
{direction = direction.Normalize();up = up.Normalize();Vector4f horizontal = up.Cross(direction).Normalize();Matrix4f viewTransform = Matrix4f();viewTransform(0, 0) = horizontal._x;viewTransform(1, 0) = horizontal._y;viewTransform(2, 0) = horizontal._z;viewTransform(3, 0) = -position.Dot(horizontal);viewTransform(0, 1) = up._x;viewTransform(1, 1) = up._y;viewTransform(2, 1) = up._z;viewTransform(3, 1) = -position.Dot(up);viewTransform(0, 2) = direction._x;viewTransform(1, 2) = direction._y;viewTransform(2, 2) = direction._z;viewTransform(3, 2) = -position.Dot(direction);viewTransform(0, 3) = 0.0f;viewTransform(1, 3) = 0.0f;viewTransform(2, 3) = 0.0f;viewTransform(3, 3) = 1.0f;return viewTransform;
}

GetPerspectiveTransformMarix函数根据前面的介绍的试图透视矩阵的原理构造出视图变换矩阵

Matrix4f Camera::GetPerspectiveTransformMarix()
{Matrix4f perspectiveTransform = Matrix4f();perspectiveTransform.SetZero();float cotHalfAngle = 1.0f / tanf(_angle * 0.5f);perspectiveTransform(0, 0) = cotHalfAngle / _aspect;perspectiveTransform(1, 1) = cotHalfAngle;perspectiveTransform(2, 2) = _far / (_far - _near);perspectiveTransform(2, 3) = 1.0f;perspectiveTransform(3, 2) = _far * _near / (_near - _far);return perspectiveTransform;
}Matrix4f Camera::GetPerspectiveTransformMarix(_FLOAT angle, _FLOAT aspect, _FLOAT near, _FLOAT far)
{Matrix4f perspectiveTransform = Matrix4f();perspectiveTransform.SetZero();float cotHalfAngle = 1.0f / tanf(angle * 0.5f);perspectiveTransform(0, 0) = cotHalfAngle / aspect;perspectiveTransform(1, 1) = cotHalfAngle;perspectiveTransform(2, 2) = far / (far - near);perspectiveTransform(2, 3) = 1.0f;perspectiveTransform(3, 2) = far * near / (near - far);return perspectiveTransform;
}

一个简单光栅器的实现(四) 几何阶段的坐标变换的C++实现相关推荐

  1. 一个简单光栅器的实现(五) 光栅化阶段

    在几何阶段我们通过顶点变换获得了世界坐标下的顶点最终渲染到屏幕上的位置和它们的深度值,并且在剔除掉了不在视锥体内顶点,接下来要做的就是根据顶点的位置和三角形索引渲染出模型的每一个三角形. 这个简单的光 ...

  2. 如何用FFmpeg编写一个简单播放器详细步骤介绍

    如何用FFmpeg编写一个简单播放器详细步骤介绍(转载) FFMPEG是一个很好的库,可以用来创建视频应用或者生成特定的工具.FFMPEG几乎为你把所有的繁重工作都做了,比如解码.编码.复用和解复用. ...

  3. 一个简单的blog系统(四) 实现用户页面和文章页面

    一个简单的blog系统(四) 实现用户页面和文章页面 1.现在我们来给博客添加用户页面和文章页面. 1.1 所谓用户页面就是当单击某个用户名链接时,跳转到:域名/u/用户名,并且跳出该用户的所有文章. ...

  4. 如何用 FFmpeg 编写一个简单播放器.pdf

    An ffmpeg and SDL Tutorial.pdf 如何用 FFmpeg 编写一个简单播放器.pdf 中文版

  5. Verilog——一个简单仲裁器的实现

    Verilog--一个简单仲裁器的实现 仲裁器基本功能 仲裁器(arbiter) 的主要功能是,多个source源同时发出请求时,根据当前的优先级来判断应响应哪一个source. 仲裁器分为轮询优先级 ...

  6. python批量下载文件只有1kb_详解如何用python实现一个简单下载器的服务端和客户端...

    话不多说,先看代码: 客户端: import socket def main(): #creat: download_client=socket.socket(socket.AF_INET,socke ...

  7. 一个简单限速器的java实现[1]

    在日常开发过程中,经常遇到对资源使用频度的限制,例如:某个接口只允许每秒调用300次,或者某个资源对象只允许每秒使用300等等,下面是一个简单的限速器的java实现,它可以实现对一个资源在若干时间(毫 ...

  8. FFmpeg编写一个简单播放器 -1

    2019独角兽企业重金招聘Python工程师标准>>> 指导1:制作屏幕录像 概要   电影文件有很多基本的组成部分.首先,文件本身被称为容器Container,容器的类型决定了信息 ...

  9. 使用PlayCanvas制作一个简单的小游戏(四)

    原文: 足球 足球是掂球游戏的焦点.它响应玩家的输入,响应环境(如重力),发出声音等.它也许是游戏中最复杂的部分.幸运的是,我们会尽可能的深入浅出. ball.js pc.script.attribu ...

最新文章

  1. Firewall防火墙应用案例
  2. linux安装tune2fs工具,linux tune2fs简解(每日一令之五)
  3. HDU 1372 Knight Moves
  4. 1020. Tree Traversals (25) PAT甲级真题
  5. linux制作成后台服务,把dotnetcore 控制台app设置成linux后台服务
  6. leetcode28. 实现 strStr()
  7. 快准狠!Intel论文揭示自家车牌识别算法:LPRNet
  8. 2019安卓机皇已定?三星Note10系列被曝将在8月10日发布
  9. C++如何禁止函数的传值调用
  10. 使用Timer的schedule()方法
  11. 【CCCC】L2-003 月饼 (25分),贪心
  12. java线程同步: synchronized详解(转)
  13. jar包add to build path与放入lib下
  14. python、java、C三种方法打印乘法表
  15. p2p网络终结者最高权限使用教程
  16. 210920-车站问题
  17. html嵌入百度播放器
  18. Computer Science Theory for the Information Age-2: 高维空间中的正方体和Chernoff Bounds
  19. 科学家首次3D生物打印出血管化肿瘤,并成功使用免疫疗法治疗
  20. Python爬虫之爬取实习僧并导入Mysql

热门文章

  1. android其实很简单 -- roaster 以代码构建代码
  2. 建筑平面布置与防火防烟分区(一)
  3. Mounty 1.10免费版(NTFS硬盘工具)支持big sur
  4. 推荐一个在线查看函数图象的网站 —— Desmos
  5. Postman-APIs是干什么的?
  6. 文件夹右击一直转圈圈
  7. MYSQL数据库报错 1055
  8. 计算机前程似锦教程图片,这三个专业非常学起很累,但毕业后前程似锦
  9. labview自动保存报表_Labview如何快速保存数据到Excel
  10. csv逗号分割不兼容 解决_excel保存为csv 不兼容的功能