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

投影

正交投影

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

示例,球的消隐

在这里插入图片描述

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

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
关于图形 的二次图形消隐和相关文档 长方体的自隐藏线消隐上机指导 1. 实验目的与要求:掌握长方体的表面模型的建立;掌握三维图形的显示流程;掌握长方体自消隐算法。 2. 实验步骤: (1)长方体表面模型的定义 三维齐次坐标结构的定义,面结构的定义,面结构中添加可见性属性;顶点表的定义,面表、与顶点表的关系。 (2)几何变换的实现 分别对顶点进行绕X轴旋转和绕Y轴旋转,旋转角度为参数,以实现轴测投影。 (3)消隐 计算每个面的外法向量,与视向量进行点积,给该面的可见性属性赋值。 (4)投影变换的实现 平行投影中正投影投影变换公式及矩阵,要求以XOY平面为投影平面,Z轴正方向为视线方向。 (3)窗口-视区变换的实现 窗口大小的选取——一般将所有图形都取在窗口内;注意投影变换时投影平面的选取,投影平面上的坐标与视区坐标x,y的对应。 (4)图形显示 显示面表中的每一个面,对于不可见面用虚线绘制该面各边,对于可见面用实线绘制各边。 3. 具体任务 在已给出程序Draw3D2中,在视图类中分别添加绕X轴旋转和绕Y轴旋转的函数void RotateX(int angle)和void RotateY(int angle);在视图类中添加计算外法向量的函数HOMOCOORD GetN(HOMOCOORD p1, HOMOCOORD p2, HOMOCOORD p3),其返回值为外法向量。注意面结构中添加的可见性属性,注意显示图形时对于不可见和可见面的处理。 4. 说明 绕X轴的旋转变化的公式实现: 考虑到旋转变化不影响w分量,可得 其他变换类似。对顶点表每个顶点进行更新。 计算外法向量函数的: P1,p2,p3为面上逆时针依次相连的三个顶点,由此外法向量N=(p2-p1)×(p3-p2); 若令x1=p2.x-p1.x, y1=p2.y-p1.y, z1=p2.z-p1.z; x2=p3.x-p2.x, y2=p3.x-p2.x, z2=p3.x-p2.x; 则外法向量可以由下列行列式求出 即
### 回答1: 计算机图形学消隐是指在计算机图形学中,为了避免多个物体在同一位置上重叠显示而产生的遮挡现象,需要对这些物体进行处理,使图像显示更加真实和清晰。 具体来说,消隐技术可以分为物理消隐算法消隐两种方法。 物理消隐主要通过硬件方面的处理来实现,如使用深度缓冲区(Depth Buffer)来存储像素的深度信息,当物体被绘制时,会与缓冲区中的深度信息进行比较,如果当前物体的深度值小于缓冲区中对应像素的深度值,则将该像素绘制出来,否则进行遮挡。 算法消隐则是通过计算机算法来实现,常见的算法有扫描线算法、边缘表算法和光线追踪等。扫描线算法通过扫描每一行像素,检查每个像素与物体的交点,来确定需要绘制的像素。边缘表算法则是通过记录轮廓边缘的交点信息,进行边缘的连接和填充。光线追踪是通过跟踪光线的路径,计算出物体表面各点的颜色和亮度值,从而确定需要显示的图像。 计算机图形学消隐对于实现真实感和视觉效果至关重要,可以使得图像在显示过程中更加准确和逼真。不同的消隐方法适用于不同的应用场景,在实际应用中需要根据需求和性能进行选择和优化。 ### 回答2: 计算机图形学消隐是指对于三维场景中的隐藏面或者隐藏线的处理技术,以实现在计算机屏幕上绘制逼真的二维图像。在三维场景中,物体之间可能会相互遮挡,如何准确地确定哪些物体显示在前面,哪些物体被其他物体遮挡,是图形学中一个重要的问题。 消隐算法通常根据场景中物体的深度信息来进行处理。其中,深度缓冲是一种常用的技术。深度缓冲是一张与屏幕大小相同的二维数组,用于记录每个像素的深度值。在绘制三维物体时,会根据物体的深度信息将像素的深度值存储到对应位置的深度缓冲中。当绘制下一个物体时,会对比当前像素的深度值与深度缓冲中对应位置的深度值,若当前像素的深度值较小,则将其存储到深度缓冲中,并覆盖之前的像素值。 除了深度缓冲,还有其他的消隐算法,如后背面消隐和边界绘制算法。后背面消隐算法基于物体的投影面的法向量来判断物体是面朝观察者还是背对观察者,只绘制面朝观察者的部分。而边界绘制算法则根据物体的边界信息来决定哪些像素需要绘制,减少不必要的绘制过程。 计算机图形学消隐的概念是为了解决物体在三维场景中的遮挡问题,使得在计算机屏幕上呈现出逼真的二维图像。通过合理的消隐算法,可以提高图形渲染的效率和真实感,使得观察者可以看到视觉上连续和逼真的场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值