3d图形学基础(一):向量与坐标系

文章目录

    • 1.1 向量与坐标系
      • 1.1.1 向量与坐标系的应用
      • 1.1.2 完整测试代码

1.1 向量与坐标系

1.1.1 向量与坐标系的应用

零向量: 零向量是没有方向的向量;

负向量: 负向量是与原向量方向相反、长度相等的向量;

向量的模: 即向量的长度,向量中各标量的平方和开根可以得到向量的模;

请添加图片描述

/*
* 三维坐标取模
*/
float mod(const Vector3& pos)
{if (*this == VEC3_ZERO)return 0;float squaresSum = x * x + y * y + z * z;return sqrt(squaresSum);
}

单位向量: 长度为1的向量,向量除以向量的模等于该向量的单位向量;

请添加图片描述

/*
* 归一化,获取单位向量
*/
Vector3 normal() const 
{ float tep = mod();if (tep == 0)return VEC3_ZERO;return *this/tep;
}

坐标间的距离: 将两个坐标相减所得到的新坐标进行取模就能得到坐标间的距离;

/*
* 计算与指定坐标的距离
*/
float distance(const Vector3& vec) {Vector3 tep = *this - vec;float distance = tep.mod();return distance;
}
/*
* 计算两个坐标间的距离
*/
inline float Distance(const Vector3& vec1, const Vector3& vec2) {Vector3 tep = vec1 - vec2;float distance = tep.mod();return distance;
}

向量点乘: 向量点乘的结果是一个标量,公式如下;
在这里插入图片描述
在这里插入图片描述

利用向量点乘可以获得两个向量的方向:点乘结果等于 0 两个向量垂直,大于 0 方向相同,小于 0 方向相反;

利用向量点乘还可以获得夹角:

a * b = || a || || b || cosθ => cosθ = (a * b) / (|| a || || b || ) => θ = arccos((a * b) / (|| a || || b || ))

/*
* 点乘
*/
inline float Dot(const Vector3& vec1, const Vector3& vec2) {float result = vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;return result;
}
/*
* 计算与指定坐标的夹角
*/
float angle(const Vector3& vec) const{float dot = Dot(*this, vec);float mod1 = mod();float mod2 = vec.mod();if (mod1 == 0.0f || mod2 == 0.0f)return 0.0f;float result = acosf(dot / (mod1 + mod2));return result;
}
/*
* 获取两个向量间的夹角
*/
inline float Angle(const Vector3& vec1, const Vector3& vec2) {float dot = Dot(vec1, vec2);float mod1 = vec1.mod();float mod2 = vec2.mod();if (mod1 == 0.0f || mod2 == 0.0f)return 0.0f;float angle = acosf(dot / (mod1 + mod2));return angle;
}

向量叉乘: 向量叉乘的结果是一个向量,叉乘的结果垂直于进行叉乘的两个向量,公式如下;
在这里插入图片描述
在这里插入图片描述

叉乘获得的结果进行模运算的结果是进行叉乘前的两个向量所映射出的平行四边形的面积;

叉乘还可用来判断两个向量是否平行,如果叉乘结果是零向量则两个向量是平行的;

/*
* 叉乘
*/
inline Vector3 Cross(const Vector3& vec1, const Vector3& vec2) {return Vector3(vec1.y * vec2.z - vec1.z * vec2.y,vec1.z * vec2.x - vec1.x * vec2.z,vec1.x * vec2.y - vec1.y * vec2.x);
}
/*
* 两个向量的方向是否平行
*/
inline bool IsParallel(const Vector3& vec1, const Vector3& vec2) {Vector3 result = Cross(vec1, vec2);return result == VEC3_ZERO;
}
/*
* 计算与指定坐标的方向是否平行
*/
bool isParallel(const Vector3& vec) {Vector3 result = Cross(*this, vec);return result == VEC3_ZERO;
}

1.1.2 完整测试代码

#include <cmath>
#include <sstream>
#ifndef __VECTOR3_H_INCLUDED__
#define __VECTOR3_H_INCLUDED__
class Vector3
{
public:float x, y, z;Vector3() {}Vector3(const Vector3& pos) : x(pos.x), y(pos.y), z(pos.z) {}Vector3(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {}Vector3 operator +() const { return Vector3(fabs(x), fabs(y), fabs(z)); }Vector3 operator -() const { return Vector3(-x, -y, -z); }Vector3 operator +(Vector3 vec) const { return Vector3(x + vec.x, y + vec.y, z + vec.z); }Vector3 operator +=(Vector3 vec) {x += vec.x;y += vec.y;z += vec.z;return *this;}Vector3 operator -(Vector3 vec) const { return Vector3(x - vec.x, y - vec.y, z - vec.z); }Vector3 operator -=(Vector3 vec) {x -= vec.x;y -= vec.y;z -= vec.z;return *this;}Vector3 operator *(float num) const { return Vector3(x * num, y * num, z * num); }Vector3 operator *=(float num) {x *= num;y *= num;z *= num;return *this;}Vector3 operator /(float num) const { float tep = 1.0f / num;const float threshold = 1e-6; if (tep < threshold)return VEC3_ZERO;Vector3 result = Vector3(x * tep , y * tep, z * tep);return result;}Vector3 operator /=(float num) {float tep = 1.0f / num;float tep = 1.0f / num;const float threshold = 1e-6;if (tep < threshold) *this = VEC3_ZERO;else*this *= tep;return *this;}bool operator ==(const Vector3 &vec) const{bool isbool = vec.x == x && vec.y == y && vec.z == z;return isbool;}/** 坐标置0*/void zero() { x = y = z = 0.0f; }/** 取向量模*/float mod() const{if (*this == VEC3_ZERO)return 0;float squaresSum = x * x + y * y + z * z;return sqrt(squaresSum);}/** 归一化,获取单位向量*/Vector3 normal() const { float tep = mod();if (tep == 0)return VEC3_ZERO;return *this/tep;}/** 返回坐标字符串*/std::string string() const {std::stringstream ss;ss << "Vector3:" << "(" << x << ", " << y << ", " << z << ")";return ss.str();}/** 计算与指定坐标的距离*/float distance(const Vector3& vec) const{Vector3 tep = *this - vec;float distance = tep.mod();return distance;}/** 计算与指定坐标的夹角*/float angle(const Vector3& vec) const{float dot = Dot(*this, vec);float mod1 = mod();float mod2 = vec.mod();if (mod1 == 0.0f || mod2 == 0.0f)return 0.0f;float result = acosf(dot / (mod1 + mod2));return result;}/** 计算与指定坐标的方向是否平行*/bool isParallel(const Vector3& vec) {Vector3 result = Cross(*this, vec);return result == VEC3_ZERO;}
};
const Vector3 VEC3_ZERO = Vector3(0, 0, 0);
const Vector3 VEC3_ONE = Vector3(1, 1, 1);
inline Vector3 operator *(float num, const Vector3 &vec) {return vec * num;
}
/*
* 计算两个坐标间的距离
*/
inline float Distance(const Vector3& vec1, const Vector3& vec2) {Vector3 tep = vec1 - vec2;float distance = tep.mod();return distance;
}
/*
* 点乘
*/
inline float Dot(const Vector3& vec1, const Vector3& vec2) {float result = vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;return result;
}
/*
* 叉乘
*/
inline Vector3 Cross(const Vector3& vec1, const Vector3& vec2) {return Vector3(vec1.y * vec2.z - vec1.z * vec2.y,vec1.z * vec2.x - vec1.x * vec2.z,vec1.x * vec2.y - vec1.y * vec2.x);
}
/*
* 获取两个向量间的夹角
*/
inline float Angle(const Vector3& vec1, const Vector3& vec2) {float dot = Dot(vec1, vec2);float mod1 = vec1.mod();float mod2 = vec2.mod();if (mod1 == 0.0f || mod2 == 0.0f)return 0.0f;float angle = acosf(dot / (mod1 + mod2));return angle;
}
/*
* 两个向量的方向是否平行
*/
inline bool IsParallel(const Vector3& vec1, const Vector3& vec2) {Vector3 result = Cross(vec1, vec2);return result == VEC3_ZERO;
}
#endif // ! __VECTOR3_H_INCLUDED__
```\

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/710426.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一些好玩的小游戏

​ 入口 比较好玩&#xff08;作者亲测&#xff09; 别忘了点赞o(&#xffe3;▽&#xffe3;)ブ ​

docker-compose搭建php开发环境

Docker Compose简介 Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose&#xff0c;您可以使用 YML 文件来配置应用程序需要的所有服务。然后使用一个命令&#xff0c;就可以从 YML 文件配置中创建并启动所有服务。而DockerCompose作为一种容器编排工具&…

学不动系列-git-hooks和husky+lintstage

git-hooks 为了保证提交的代码符合规范&#xff0c;可以在上传代码时进行校验。常用husky来协助进行代码提交时的eslint校验。husky是基于git-hooks来实现&#xff0c;在使用husky之前&#xff0c;我们先来研究一下git-hooks。 构建git-hooks测试项目 需要使用git-hooks就需…

Java与JavaScript:深入剖析两种语言之间的相似性与差异

大家都知道JavaScript这个名字,听起来就像是Java的“小弟”或者“跟班”,但实际上,它们之间的关系远比这复杂。你可能会想,Java是大哥,JavaScript是小弟,那它们肯定有很多相似之处吧?错了!错了!错了!这完全是个误会。 JavaScript其实是个“蹭热点”的家伙。当Java这…

C++的设计模式:工厂方法模式(Factory Method)

工厂方法模式&#xff08;Factory Method&#xff09;是一种常用的创建型设计模式&#xff0c;它提供了一种创建对象的最佳方式。在工厂方法模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;并且是通过使用一个共同的接口来指向新创建的对象。 意图 …

Git LFS提交大文件到GitHub

一、前言 关于 GitHub 上的大文件 GitHub Enterprise Cloud 限制存储库中允许的文件大小。 如果尝试添加或更新大于 50 MiB 的文件&#xff0c;您将从 Git 收到警告。 更改仍将成功推送到仓库&#xff0c;但您可以考虑删除提交&#xff0c;以尽量减少对性能的影响。 GitHub Ent…

QPaint绘制自定义仪表盘组件03

网上视频抄的&#xff0c;用来自己看一下&#xff0c;看完就删掉 ui mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QDebug> #include <QtMath> #include <QDialog> #include <QPainter> #include …

网络安全概述(一)

目录 资产保护 资产的类型 资产损失类型 资产保护考虑因素 安全强度、安全代价和侵入可能性的关系 信息安全技术发展 单机系统的信息保密阶段 信息保障阶段 信息保障技术框架IATF PDRR模型 网络攻击类型 阻断攻击、截取攻击、篡改攻击、伪造攻击 被动攻击和主动攻…

C#,双向链表(Doubly Linked List)归并排序(Merge Sort)算法与源代码

1 双向链表 双向链表也叫双链表&#xff0c;是链表的一种&#xff0c;它的每个数据结点中都有两个指针&#xff0c;分别指向直接后继和直接前驱。所以&#xff0c;从双向链表中的任意一个结点开始&#xff0c;都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循…

用来检查 CUDA、Conda 和 PyTorch 的版本的python文件

提供的 Python 代码片段包括几个语句&#xff0c;用来检查 CUDA、Conda 和 PyTorch 的版本&#xff0c;以及一些与 CUDA 相关的系统配置。让我们分解一下&#xff1a;PyTorch 版本和配置&#xff1a;torch.__config__.show()&#xff1a;显示 PyTorch 的构建配置。 torch.__ver…

LNMP架构介绍及配置--部署Discuz社区论坛与wordpress博客

一、LNMP架构定义 1、LNMP定义 LNMP&#xff08;Linux Nginx Mysql Php&#xff09;是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写&#xff1b;Linux系统下NginxMySQLPHP这种网站服务器架构。 Linux是一类Unix计算机操作系统的统称&#xff0c;是目…

基于单片机负载控制的无人机电气设备监测系统设计

摘要:为深入分析无人机电气设备的电子负载性能,实现对传输电子量的合理性监管与控制,设计基于单片机负载控制的无人机电气设备监测系统;利用电气信号发生电路,构建负载网络控制器与以太网模块运行所需的电气设备负载环境,借助PCB监控板建立PLC扩展负载模块与核心监控主机…

nftables 测试一拒绝所有流量

要配置 nftables 先拒绝所有流量&#xff0c;然后再添加允许的规则&#xff0c;您可以按照以下步骤操作&#xff1a; 创建一个空的 nftables 配置文件&#xff08;例如 /etc/nftables.conf&#xff09;并添加如下内容&#xff1a; flush rulesettable inet filter {chain input…

Java学习—Stream流

Java 8引入的Stream API是对集合操作的一种高级抽象。Stream API不仅使代码更加简洁易读&#xff0c;还引入了函数式编程的强大功能&#xff0c;使得对集合的操作更加灵活和强大。让我们更详细地探讨Stream的核心概念、操作以及它在实际编程中的应用。 核心概念 Stream&#…

王者荣耀,急于补齐内容短板

问十个人&#xff0c;有九个人知道《王者荣耀》&#xff1b;但如果再问十个知道《王者荣耀》的人&#xff0c;这款游戏到底讲了一个什么故事&#xff0c;每个角色又有怎样的背景&#xff0c;可能十个人都不知道。 整个新年档口&#xff0c;《王者荣耀》都很忙碌。 1月&#x…

《HelloGitHub》第 95 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、Java、Go、C/C、Swift...让你在短时间内…

ODOO12设置收发邮件服务器教程

一、设置-技术 二、设置–技术–发件服务器 信息填写完整后&#xff0c;点击‘测试连接’&#xff0c;若提示成功&#xff0c;则发件服务器设置成功。 三、设置–技术–收件服务器 四、设置–参数–系统参数 修改之前的email系统参数&#xff1a; mail.catchall.alias: 收件服…

Vue页面更新后刷新页面不会渲染解决

小编今天犯了个很低级的错误&#xff0c;导致VUE页面刷新样式不会更新的问题&#xff01; 解决方法&#xff1a;查看你的路由路径大小写是否正确&#xff01;小编是犯了这种错误&#xff0c;特此分享下&#xff01;

Linux中docker项目提示No such file or directory

本来以为是文件权限问题&#xff0c;后来发现是个非常蠢的问题 文件没有映射到容器中 docker文件映射语法 Docker 使用 -v 或 --volume 参数来指定文件映射。 增加在运行命令后 -v <宿主机目录>:<容器目录> 其中&#xff0c;宿主机目录 是指要映射的宿主机上的…

【Django】执行查询—创建和修改对象

创建对象和修改对象 直接上例子&#xff1a; # 创建对象 >>> from blog.models import Blog >>> b Blog(name"Beatles Blog", tagline"All the latest Beatles news.") >>> b.save() # 修改对象 >>> b5.name &quo…