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

投影

正交投影

对于物体上任意一点的三维坐标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;
}

示例,球的消隐

在这里插入图片描述

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

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

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

相关文章

canvas绘制横竖坐标轴(带有箭头和刻度)

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

[项目管理] 如何使用git客户端管理gitee的私有仓库

最近发现即使翻墙也无法g使用ithub了&#xff0c;需要把本地的项目搬迁到新的git托管平台。 gitee 是一个国内开源项目托管平台&#xff0c;是开源开发者、团队、个人进行 git 代码管理和协作的首选平台之一。本文将详细介绍如何向 gitee 提交私有项目。 注册 Gitee 账号并创建…

P3372 【模板】线段树 1

网址如下&#xff1a; P3372 【模板】线段树 1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题如其名 昨天做了一道开关&#xff08;也是线段树的&#xff09; 想着今天复习一下 代码如下&#xff1a; #include<iostream> using namespace std; typedef long long…

golang 引入swagger(iris、gin)

golang 引入swagger&#xff08;iris、gin&#xff09; 在开发过程中&#xff0c;我们不免需要调试我们的接口&#xff0c;但是有些接口测试工具无法根据我们的接口变化而动态变化。文档和代码是分离的。总是出现文档和代码不同步的情况。这个时候就可以在我们项目中引入swagge…

【漏洞复现】多语言药房管理系统MPMS文件上传漏洞

Nx01 产品简介 多语言药房管理系统 (MPMS) 是用 PHP 和 MySQL 开发的, 该软件的主要目的是在药房和客户之间提供一套接口&#xff0c;客户是该软件的主要用户。该软件有助于为药房业务创建一个综合数据库&#xff0c;并根据到期、产品等各种参数提供各种报告。 Nx02 漏洞描述 …

显示器颜色显示技术原理

此图片来源于网络 1、人眼是如何看到颜色的 以下介绍如何定义颜色的基本知识。首先人眼是如何看到颜色的。可见光的光谱范围从380纳米到750纳米。在此范围内&#xff0c;可以看到每种可见颜色的相应波长。将讨论如何将可见光谱的波长组合成其他颜色&#xff0c;以及这一过程是…

2023年12月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,共50分) 第1题 一个非零的二进制正整数,在其末尾添加两个“0”,则该新数将是原数的?( ) A:10倍 B:2倍 C:4倍 D:8倍 答案:C 二进制进位规则是逢二进一,因此末尾添加一个0,是扩大2倍,添加两个0…

postman执行批量测试

1.背景 有许多的人常常需要使用第三方系统进行重复的数据查询&#xff0c;本文介绍使用PostMan的方式对数据进行批量的查询&#xff0c;减少重复的劳动。 2.工具下载 3.初入门 一、如图示进行点击&#xff0c;创建collection 二、输入对应的名称 三、创建Request并进行查…

C++后端开发之Sylar学习二:配置VSCode远程连接Ubuntu开发

C后端开发之Sylar学习二&#xff1a;配置VSCode远程连接Ubuntu开发 没错&#xff0c;我不能像大佬那样直接在Ubuntu上面用Vim手搓代码&#xff0c;只能在本地配置一下VSCode远程连接Ubuntu进行开发咯&#xff01; 本篇主要是讲解了VSCode如何配置ssh连接Ubuntu&#xff0c;还有…

无损音乐下载,最新音乐下载,mp3格式音乐下载,一键下载mp3格式音乐,我只用这个软件,歌曲资源丰富,全网音乐免费下载,稳定运行,告别收费

一、软件简介 现在很多支持一键下载mp3音乐/无损音质音乐的音乐播放器通常都是解析接口套了一个壳&#xff0c;一旦解析接口失效&#xff0c;软件就不能下载音乐了&#xff0c;因此一个稳定的解析接口是这类软件最大的保障。本次小编推荐的音乐下载软件接口非常稳定&#xff0…

单片机学习笔记---LED点阵屏的工作原理

目录 LED点阵屏分类 LED点阵屏显示原理 74HC595的介绍 一片74HC595的工作原理 多片级联工作原理 总结 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种公共场合&#xff0c;如汽…

第五篇【传奇开心果系列】vant开发移动应用示例:深度解读高度可定制

传奇开心果博文系列 系列博文目录Vant 开发移动应用示例系列 博文目录前言一、Vant高度可定制的重要作用二、样式定制介绍和示例代码三、组件定制介绍和示例代码四、组件库定制介绍和示例代码五、主题定制介绍和示例代码六、语言环境定制介绍和示例代码七、资源加载定制介绍和示…

网络层DoS

网络层是OSI参考模型中的第三层&#xff0c;介于传输层和数据链路层之间&#xff0c;其目的 是实现两个终端系统之间数据的透明传送&#xff0c;具体功能包括&#xff1a;寻址和路由选择、连 接的建立、保持和终止等。位于网络层的协议包括ARP 、IP和ICMP等。下面就 ICMP为例&…

创建一个VUE项目(vue2和vue3)

背景&#xff1a;电脑已经安装完vue2和vue3环境 一台Mac同时安装vue2和vue3 https://blog.csdn.net/c103363/article/details/136059783 创建vue2项目 vue init webpack "项目名称"创建vue3项目 vue create "项目名称"

diffusers单机多卡推理(全网首发)

起因 博主在部署InstantID项目时&#xff0c;显存不够&#xff0c;想要将模型分散在多张卡上。 翻到这篇发现是分布式推理&#xff0c;博主一直以为这个可以达到我想要的效果&#xff0c;但是效果是多线程并行推理&#xff0c;并不能将一个模型切片在多个GPU上。 Distributed …

一起玩儿物联网人工智能小车(ESP32)——57. SPI总线协议初探(一)

摘要&#xff1a;介绍SPI总线的基本知识 前面已经学习过IIC总线协议&#xff0c;今天开始介绍另一个总线协议——SPI。SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接口&#xff09;是由Motorola提出的一种高速、全双工、同步的通信总线。并且在芯片的管脚…

TI的电量计驱动在卸载时导致Linux卡死

背景 最近移植TI电量计芯片bq40z50的驱动&#xff0c;移植完毕后&#xff0c;能正常读取电池信息了&#xff0c;但是无意中发现驱动卸载会导致Linux卡死&#xff0c;死前终端闪过大量打印&#xff0c;将putty的缓冲区都耗尽了&#xff0c;必须启用syslog转发并用visual syslog…

L1-080 乘法口诀数列

一、题目 二、解题思路 三、代码 #include<iostream> using namespace std; int main() {int a1,a2,n;cin>>a1>>a2>>n;if(n1){cout<<a1;return 0; }int a[n*2];cout<<a1<<" "<<a2;a[0]a1;a[1]a2;for(int i2,j2;i&l…

ubuntu20安装mongodb

方法一&#xff1a;直接安装(命令是直接从mongo官网Install MongoDB Community Edition on Ubuntu — MongoDB Manual复制的&#xff09; cat /etc/lsb-release sudo apt-get install -y gnupg curl curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \sudo gp…

背包问题(01背包、完全背包、多重背包)详解(超详细!!!),及题目代码和题意,包含6个例题。

第一题&#xff1a;01背包问题 01背包问题 时间限制&#xff1a;1秒 内存限制&#xff1a;128M 题目描述 一个旅行者有一个最多能装 M 公斤的背包&#xff0c;现在有 n 件物品&#xff0c;它们的重量分别是 W1&#xff0c;W2&#xff0c;...,Wn ,它们的价值分别为 C1…