【图形学】投影和消隐简介

投影

正交投影

对于物体上任意一点的三维坐标P(x,y,z),投影后的三维坐标为 P ′ ( x ′ , y ′ , z ′ ) P^\prime(x^\prime,y^\prime,z^\prime) P(x,y,z),那么正交投影的方程为 { x ′ = x y ′ = y z ′ = 0 \begin{cases} x^\prime=x\\y^\prime=y\\z^\prime=0 \end{cases} x=xy=yz=0

斜投影

在这里插入图片描述

如图所示,空间中一点 P 1 ( x , y , z ) P_1(x,y,z) P1(x,y,z)在xOy面上的斜投影坐标 P 2 ( x ′ , y ′ , 0 ) P_2(x^\prime,y^\prime,0) P2(x,y,0)正交投影点 P 3 ( x , y , 0 ) P_3(x,y,0) P3(x,y,0),那么有 { x ′ = x − L cos ⁡ β = x − z cot ⁡ α cos ⁡ β y ′ = y − L sin ⁡ β = y − z cot ⁡ α sin ⁡ β \begin{cases} x^\prime=x-L\cos\beta=x-z\cot\alpha\cos\beta\\ y^\prime=y-L\sin\beta=y-z\cot\alpha\sin\beta \end{cases} {x=xLcosβ=xzcotαcosβy=yLsinβ=yzcotαsinβ

透视投影

透视投影有三个坐标系,世界坐标系,观察坐标系,屏幕坐标系
在这里插入图片描述

在这里插入图片描述

观察坐标系到投影坐标系的转换可以用相似求出
在这里插入图片描述

{ x ′ = n ⋅ x z y ′ = n ⋅ y z \begin{cases} x^\prime=n\cdot \frac{x}{z}\\ y^\prime=n\cdot \frac{y}{z} \end{cases} {x=nzxy=nzy

建立投影类

class CProjection
{
public:
	CProjection();
	~CProjection();
	void SetViewPoint(double R);
	CPoint3 GetViewPoint();
	CPoint2 ObliqueProjection(CPoint3 WorldPoint);//正交投影
	CPoint2 OrthogonalProjection(CPoint3 WorldPoint);//斜二测投影
	CPoint2 PerspectiveProjection(CPoint3 WorldPoint);//透视投影
private:
	CPoint3 m_viewPoint;
	double R, d;
};

CProjection::CProjection()
{
    R = 1200; d = 800;
    m_viewPoint.m_x = 0;
    m_viewPoint.m_y = 0;
    m_viewPoint.m_z = R;
}

CProjection::~CProjection()
{
}

void CProjection::SetViewPoint(double R)
{
    this->R = R;
}

CPoint3 CProjection::GetViewPoint()
{
    return m_viewPoint;
}

CPoint2 CProjection::ObliqueProjection(CPoint3 WorldPoint)//斜二测投影
{
    CPoint2 ScreenPoint;
    ScreenPoint.m_x = WorldPoint.m_x - 0.3536 * WorldPoint.m_z;
    ScreenPoint.m_y = WorldPoint.m_y - 0.3536 * WorldPoint.m_z;
    return ScreenPoint;
}

CPoint2 CProjection::OrthogonalProjection(CPoint3 WorldPoint)//正交投影
{
    CPoint2 ScreenPoint;
    ScreenPoint.m_x = WorldPoint.m_x ;
    ScreenPoint.m_y = WorldPoint.m_y ;
    return ScreenPoint;
}

CPoint2 CProjection::PerspectiveProjection(CPoint3 WorldPoint)
{
    CPoint2 ScreenPoint;
    CPoint3 ViewPoint;
    ViewPoint.m_x = WorldPoint.m_x;
    ViewPoint.m_y = WorldPoint.m_y;
    ViewPoint.m_z = m_viewPoint.m_z - WorldPoint.m_z;
    ScreenPoint.m_x = d * ViewPoint.m_x / ViewPoint.m_z;
    ScreenPoint.m_y = d * ViewPoint.m_y / ViewPoint.m_z;
    return ScreenPoint;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

消隐,背面剔除算法

给定视点位置或视线方向后,确定场景中哪些物体表面是可见的、哪些物体表面是不可见的,即是消隐。
背面剔除算法主要是针对凸多面体,其表面要么可见,要么不可见。算法要给出测试每个表面是否可见的表达式。
在这里插入图片描述
如图所示,根据表面的外法向量 N ⃗ \vec N N 和式向量 V ⃗ \vec V V 的夹角 θ \theta θ来进行可见性判定。
N ⃗ = P 2 P 4 ⃗ × P 3 P 4 ⃗ \vec N=\vec {P_2P_4} \times \vec {P_3P_4} N =P2P4 ×P3P4
给定视点坐标 O ( x v , y v , z v ) O(x_v,y_v,z_v) O(xv,yv,zv)后,视向量表示为 V ⃗ = ( x v − x 4 , y v − y 4 , z v − z 4 ) \vec V=(x_v-x_4,y_v-y_4,z_v-z_4) V =(xvx4,yvy4,zvz4)
将法向量 N ⃗ \vec N N 归一化为单位向量 n ⃗ \vec n n ,将视向量归一化为单位向量 v ⃗ \vec v v ,则有
n ⃗ ⋅ v ⃗ = cos ⁡ θ \vec n \cdot \vec v=\cos\theta n v =cosθ
可见性的判定如下:

  • cos ⁡ θ > 0 \cos\theta>0 cosθ>0时,表面可见,绘制多边形的边界线
  • cos ⁡ θ = 0 \cos\theta=0 cosθ=0时,表面多边形退化为一条直线
  • cos ⁡ θ < 0 \cos\theta<0 cosθ<0时,表面多边形不可见
    为了实现背面剔除算法,这里设计一个三维向量类CVector3

这里给的例子是一个立方体,那如果是一个贝塞尔曲面拟合的物体(比如球),那么用递归曲面片的方式绘制曲面,对于每一个细分曲面片又可以看成一个平面四边形,求出法向量即可。
在这里插入图片描述

三维向量类CVector3

class CVector3
{
public:
	CVector3();
	virtual ~CVector3();
	CVector3(double x, double y, double z);//绝对向量
	CVector3(const CPoint3& p);
	CVector3(const CPoint3& p0, const CPoint3& p1);//相对向量
	double Magnitude();//计算向量的模
	CVector3 Normalize();//归一化向量
	friend CVector3 operator + (const CVector3& v0, const CVector3& v1);//运算符重载
	friend CVector3 operator - (const CVector3& v0, const CVector3& v1);
	friend CVector3 operator * (const CVector3& v, double t);
	friend CVector3 operator * (double t, const CVector3& v);
	friend CVector3 operator / (const CVector3& v, double t);
	friend double DotProduct(const CVector3& v0, const CVector3& v1);//计算向量的点积
	friend CVector3 CrossProduct(const CVector3& v0, const CVector3& v1);//计算向量的叉积
private:
	double m_x, m_y, m_z;
};
CVector3::CVector3(void)
{
	m_x = 0.0, m_y = 0.0, m_z = 1.0;//指向z轴正向
}


CVector3::~CVector3(void)
{
}

CVector3::CVector3(double x, double y, double z)//绝对向量
{
	m_x = x;
	m_y = y;
	m_z = z;
}
CVector3::CVector3(const CPoint3& p)
{
	m_x = p.m_x;
	m_y = p.m_y;
	m_z = p.m_z;
}
CVector3::CVector3(const CPoint3& p0, const CPoint3& p1)//相对向量
{
	m_x = p1.m_x - p0.m_x;
	m_y = p1.m_y - p0.m_y;
	m_z = p1.m_z - p0.m_z;
}
double CVector3::Magnitude(void)//向量的模
{
	return sqrt(m_x * m_x + m_y * m_y + m_z * m_z);
}
CVector3 CVector3::Normalize(void)//归一化为单位向量
{
	CVector3 vector;
	double magnitude = sqrt(m_x * m_x + m_y * m_y + m_z * m_z);
	if (fabs(magnitude) < 1e-6)
		magnitude = 1.0;
	vector.m_x = m_x / magnitude;
	vector.m_y = m_y / magnitude;
	vector.m_z = m_z / magnitude;
	return vector;
}
void CVector3::IntoOut()
{
	if (m_x * m_y < 0&&m_x*m_z>0) {
		m_x = -m_x, m_z = -m_z;
	}
	else if (m_x * m_z < 0 && m_x * m_y>0) {
		m_x = -m_x, m_y = -m_y;
	}
	else if (m_y * m_z < 0 && m_y * m_z>0) {
		m_y = -m_y, m_z = -m_z;
	}
}
CVector3 operator + (const CVector3& v0, const CVector3& v1)//向量的和
{
	CVector3 vector;
	vector.m_x = v0.m_x + v1.m_x;
	vector.m_y = v0.m_y + v1.m_y;
	vector.m_z = v0.m_z + v1.m_z;
	return vector;
}

CVector3 operator - (const CVector3& v0, const CVector3& v1)//向量的差
{
	CVector3 vector;
	vector.m_x = v0.m_x - v1.m_x;
	vector.m_y = v0.m_y - v1.m_y;
	vector.m_z = v0.m_z - v1.m_z;
	return vector;
}

CVector3 operator * (const CVector3& v, double t)//向量与常量的积
{
	CVector3 vector;
	vector.m_x = v.m_x * t;
	vector.m_y = v.m_y * t;
	vector.m_z = v.m_z * t;
	return vector;
}

CVector3 operator * (double t, const CVector3& v)//常量与向量的积
{
	CVector3 vector;
	vector.m_x = v.m_x * t;
	vector.m_y = v.m_y * t;
	vector.m_z = v.m_z * t;
	return vector;
}

CVector3 operator / (const CVector3& v, double scalar)//向量数除
{
	if (fabs(scalar) < 1e-6)
		scalar = 1.0;
	CVector3 vector;
	vector.m_x = v.m_x / scalar;
	vector.m_y = v.m_y / scalar;
	vector.m_z = v.m_z / scalar;
	return vector;
}

double DotProduct(const CVector3& v0, const CVector3& v1)//向量的点积
{
	return(v0.m_x * v1.m_x + v0.m_y * v1.m_y + v0.m_z * v1.m_z);
}

CVector3 CrossProduct(const CVector3& v0, const CVector3& v1)//向量的叉积
{
	CVector3 vector;
	vector.m_x = v0.m_y * v1.m_z - v0.m_z * v1.m_y;
	vector.m_y = v0.m_z * v1.m_x - v0.m_x * v1.m_z;
	vector.m_z = v0.m_x * v1.m_y - v0.m_y * v1.m_x;
	return vector;
}

示例,球的消隐

在这里插入图片描述

需要项目代码请评论区留言或私信

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2 月 7 日算法练习- 数据结构-并查集

并查集 并查集是一种图形数据结构&#xff0c;用于存储图中结点的连通关系。 每个结点有一个父亲&#xff0c;可以理解为“一只伸出去的手”&#xff0c;会指向另外一个点&#xff0c;初始时指向自己。 一个点的根节点是该点的父亲的父亲的的父亲&#xff0c;直到某个点的父亲…

【buuctf--来首歌吧】

用 Audacity 打开&#xff0c;左声道部分可以放大&#xff0c;可以按照长短转换成摩斯密码&#xff0c;放大后&#xff1a; ..... -... -.-. ----. ..--- ..... -.... ....- ----. -.-. -... ----- .---- ---.. ---.. ..-. ..... ..--- . -.... .---- --... -.. --... ----- -…

2024 年改变行业的人工智能主要趋势

1、导读 当我们迈入 2024 年时&#xff0c;了解人工智能趋势至关重要。它们不仅仅涉及技术进步&#xff1b;还涉及技术进步。它们意味着我们解决问题、做出决策和展望未来的方式发生了转变。本文旨在探索这些变革趋势&#xff0c;并强调人工智能如何不断突破可能性的界限&…

C++进阶(十二)lambda可变参数包装器

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、新的类功能1、默认成员函数2、类成员变量初始化3、 强制生成默认函数的关键字default:4、…

【软件设计师笔记】深入探究操作系统

【软件设计师笔记】计算机系统基础知识考点(传送门) &#x1f496; 【软件设计师笔记】程序语言设计考点(传送门) &#x1f496; &#x1f413; 操作系统的作用 1.通过资源管理提高计算机系统的效率 2.改善人机界面向用户提供友好的工作环境 &#x1f413; 操作系统的特征 …

leetcode(滑动窗口)483.找到字符中所有字母异位词(C++详细解释)DAY4

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串&#xff08;包括相同的字符串&a…

03-抓包_封包_协议_APP_小程序_PC应用_WEB应用

抓包_封包_协议_APP_小程序_PC应用_WEB应用 一、参考工具二、演示案例&#xff1a;2.1、WEB应用站点操作数据抓包-浏览器审查查看元素网络监听2.2、APP&小程序&PC抓包HTTP/S数据-Charles&Fiddler&Burpsuite2.3、程序进程&网络接口&其他协议抓包-WireSh…

three.js 向量方向(归一化.normalize)

效果&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div><p><el-button type"primary…

c#: 表达式树的简化

环境&#xff1a; .net 6 一、问题&#xff1f; 有下面的表达式&#xff1a; var nums new List<int> { 1, 2, 3 }; Expression<Func<int, bool>> exp i > i > nums.Max();我们知道&#xff0c;它其实就是&#xff1a;exp i > i > 3; 那么…

史上最全嵌入式(学习路线、应用开发、驱动开发、推荐书籍、软硬件基础)

废话不多说直接上思维导图&#xff01; 如果有觉得图片看不清楚的&#xff0c;有疑问的&#xff0c;可在评论区进行留言&#xff01; 群号&#xff1a; 228447240 嵌入式总括 嵌入式书籍推荐 嵌入式软件知识 嵌入式硬件知识 嵌入式应用开发 嵌入式驱动开发 嵌入式视频推荐: 韦…

5秒搭建PalWorld幻兽帕鲁游戏服务器,你信吗?

5秒搭建PalWorld幻兽帕鲁游戏服务器&#xff0c;你信吗&#xff1f;腾讯云推出幻兽帕鲁专属镜像系统&#xff0c;直接选择镜像&#xff0c;5秒搞定&#xff0c;全自动化部署。 幻兽帕鲁太火了&#xff0c;官方palworld服务器不稳定&#xff1f;不如自建服务器&#xff0c;基于…

双归同一运营商的 BGP 部署

一、拓朴如下&#xff1a; 要求&#xff1a; 1、AS100 只接收 AS200 和 300 的路由&#xff0c;不接收其它 AS 的明细路由&#xff1b; 2、对于 AS100 的业务流量出方向&#xff0c;所有到 AS200 和 300 的流量&#xff0c;优先选择 Line-1&#xff0c;而到 AS400 的流…

SpringBoot Security安全认证框架初始化流程认证流程之源码分析

SpringBoot Security安全认证框架初始化流程&认证流程之源码分析 以RuoYi-Vue前后端分离版本为例分析SpringBoot Security安全认证框架初始化流程&认证流程的源码分析 目录 SpringBoot Security安全认证框架初始化流程&认证流程之源码分析一、SpringBoot Security安…

5.electron之主进程起一个本地服务

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中&#xff0c;因此它允许你仅需一个代码仓库&#xff0c;就可以撰写支持 Windows、…

基于SpringBoot和PostGIS的震中影响范围可视化实践

目录 前言 一、基础数据 1、地震基础信息 2、全国行政村 二、Java后台服务设计 1、实体类设计 2、Mapper类设计 3、控制器设计 三、前端展示 1、初始化图例 2、震中位置及影响范围标记 3、行政村点查询及标记 总结 前言 地震等自然灾害目前还是依然不能进行准确的预…

基于Springboot的足球社区管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的足球社区管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

8.0 Zookeeper 四字命令教程详解

zookeeper 支持某些特定的四字命令与其交互&#xff0c;用户获取 zookeeper 服务的当前状态及相关信息&#xff0c;用户在客户端可以通过 telenet 或者 nc&#xff08;netcat&#xff09; 向 zookeeper 提交相应的命令。 安装 nc 命令&#xff1a; $ yum install nc …

[office] Excel 2016怎么绘图?Excel2016绘图图文教程 #媒体#经验分享

Excel 2016怎么绘图&#xff1f;Excel2016绘图图文教程 这篇文章主要为大家介绍了Excel 2016怎么绘图&#xff1f;这篇文章主要介绍了Excel2016绘图图文教程 Excel作为数据处理分析软件&#xff0c;是非常好用的软件。里面可以进行数据统计与分析&#xff0c;如果要使得 Exce…

坚持刷题|二叉树的最近公共祖先

文章目录 题目考察点代码实现实现总结为什么不用迭代的方法实现&#xff1f;二叉搜索树的最近公共祖先 Hello&#xff0c;大家好&#xff0c;我是阿月。坚持刷题&#xff0c;老年痴呆追不上我&#xff0c;今天刷&#xff1a;二叉树的最近公共祖先 题目 236.二叉树的最近公共祖…

JavaWeb后端开发(第一期):Maven基础、Maven的安装配置、如何创建maven项目模块、maven的生命周期

Java后端开发&#xff1a;2024年2月6日 -> LiuJinTao 文章目录 JavaWeb后端开发&#xff08;第一期&#xff09; &#xff1a; maven基础一、 maven介绍1.1 什么maven呢&#xff1a;1.2 maven的作用1.3 maven 模型1.4 maven 仓库 二、maven 安装2.1 配置本地仓库2.2 配置阿里…