EGE基础入门篇(七):组合图形

EGE基础入门篇(七):组合图形利用EGE中的基本图形绘制复杂的组合图形_ege绘制多个多边形

大家好,欢迎来到IT知识分享网。

EGE专栏:EGE专栏

上一篇:EGE基础入门篇(六):基本图形

下一篇:EGE基础入门篇(八):清屏与重绘

一、 组合图形

1. 复杂图形由基本图形组合而成

  复杂的图形可以由基本图形组合而成,如多边形可以由多个三角形组合而成。
  同一个图形也可由基本图形以不同的方式进行组合。并且可以利用后绘制的图形会将先绘制图形覆盖的原理。
在这里插入图片描述

2. 绘制的顺序性

  图形的绘制是有先后顺序的,并不能随意地按任意顺序进行绘制。
  当后绘制的图形和先绘制的图形重叠时,如果图形不透明,那么先绘制的图形会被后绘制的图形所覆盖。即使图形是透明的,也会造成混合后的颜色不相同。

  如下图所示,当物体存在一定的遮挡关系时,需要按由远到近的顺序,先画远处的物体,再画近处的物体,这样绘制出的图形才会符合实际。否则,图中的树木会被草地和高山所覆盖。
在这里插入图片描述
  在三维物体渲染中,深度排序算法也叫画家算法,通过先对物体按照离视点远近的顺序进行排序,再将物体按顺序进行绘制的方法来得到正确的渲染结果。
在这里插入图片描述
  如下图所示,图中为通过调整结点和边的绘制顺序,得到了两种不同的绘制结果,而右边按先边后结点顺序绘制出的二叉树图形才是我们想要的。
在这里插入图片描述

二、组合图形的绘制

  

1. 彭罗斯三角形

  彭罗斯三角形是利用视觉错觉构造的一种不可能图形,在三维空间中并不真实客观存在。在二维空间中,可以在某个特定角度观察到这种”不可能图形”,所以彭罗斯三角形是二维图形的三维投射形成的光学错觉。彭罗斯三角形在《纪念碑谷》中有着大量的运用。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  在二维绘图中,有多种绘图方式,既可以将彭罗斯三角形看作是三个互不重叠的多边形组合而成,也可以是特殊构造的三维图形的投影(纪念碑谷中的做法,适合三维模型),还可以改变三维物体表面投影的遮挡关系来形成。
  这里我们通过构造三维模型,利用其投影来绘制彭罗斯三角形。
  我们先根据物体在三维坐标系中的位置得到其顶点的三维坐标,然后将其投影到平面上,得到在平面上的二维坐标,然后在变换到窗口坐标系上,即可得到多边形每个顶点的坐标,调用ege_fillpoly() 绘图即可。

在这里插入图片描述

  我们对一个单位立方体进行分析,可以发现立方体被投影成了正六边形。由于投影面垂直于向量 v v v,与 v v v垂直的线段投影后长度不变。从图中可以看出平面ABC垂直于向量 v v v,所以投影后 A B 、 A C 和 B C AB、AC和BC ABACBC长度均不变,长度为 2 \sqrt{2} 2
。通过对在坐标轴上的三个点A、B、D映射关系分析,我们就能得到相应的变换关系。
  三维空间上的顶变换后到 x O y xOy xOy平面后,再通过视口变换转换成窗口坐标系上的坐标,就可以利用EGE中的绘图函数进行绘图了。
在这里插入图片描述

完整代码如下:

#include <graphics.h>
#include <cmath>

typedef struct Rect
{ 
   
	float x, y;
	float width, height;
} Rect;

typedef struct Vertex
{ 
   
	float x, y, z;
} Vertex;

//投影到xOy平面上
ege_point vertexPrejection(Vertex vertex)
{ 
   
	static const double sqrtOf2 = sqrt(2.0);
	static const double sqrtOf3 = sqrt(3.0);
	static const double sqrtOf6 = sqrt(6.0);
	// 根据点的投影:
	// (1, 0, 0)映射到(√2/2, √6/6, 0)
	// (0, 1, 0)映射到(0, √6/3, 0)
	// (0, 0, 1)映射到(√2/2, -√6/6, 0)
	// 得到:变换矩阵(坐标为列向量)
	// |x| = |√2/2, 0, √2/2| |x|
	// |y| = |√6/6, √6/3, -√6/6| |y|
	// |z| = | 0, 0, 0| |z|

	ege_point point;
	point.x = vertex.x * (sqrtOf2 / 2.0) + vertex.z * (sqrtOf2 / 2.0);
	point.y = vertex.x * (sqrtOf6 / 6.0) + vertex.y * (sqrtOf6 / 3.0) + vertex.z * (-sqrtOf6 / 6.0);
	return point;
}

int main() { 
   
	//定义窗口大小,以及窗口中心
	int winWidth = 640, winHeight = 640;
	Rect viewRect = { 
    -2.0f, -2.0f, 8.0f, 8.0f };		//投影截取范围:左下角(-2, -2),宽高为8x8的矩形区域
	int xCenter = winWidth / 2, yCenter = winHeight / 2;

	initgraph(winWidth, winHeight, INIT_RENDERMANUAL);
	ege_enable_aa(true);
	setbkcolor(EGERGB(0xFF, 0xFF, 0xFF));

	//三个多边形的顶点坐标(凹六边形)
	Vertex vertices[3][6] = { 
   
		{ 
   
			{ 
   0.0f, 0.0f, 0.0f}, { 
   0.0f, 0.0f, 1.0f}, { 
   0.0f, 5.0f, 1.0f}, 
			{ 
   0.0f, 5.0f, 4.0f}, { 
   0.0f, 6.0f, 5.0f}, { 
   0.0f, 6.0f, 0.0f},
		},
		{ 
   
			{ 
   0.0, 0.0f, 1.0f}, { 
   6.0f, 0.0f, 1.0f}, { 
   6.0f, 1.0f, 1.0f},
			{ 
   1.0, 1.0f, 1.0f}, { 
   1.0f, 4.0f, 1.0f}, { 
   0.0f, 5.0f, 1.0f},
		},
		{ 
   
			{ 
   0.0f, 6.0f, 0.0f}, { 
   0.0f, 6.0f, 5.0f}, { 
   2.0f, 1.0f, 0.0f},
			{ 
   1.0f, 1.0f, 1.0f}, { 
   6.0f, 1.0f, 1.0f}, { 
   1.0f, 6.0f, 0.0f},
		},
	};

	//多边形的颜色
	color_t colors[3] = { 
    EGEARGB(255, 2, 118, 191), EGEARGB(255, 94, 175, 228),EGEARGB(255, 146, 202, 239) };

	const int numPolys = 3;
	const int numPoints = 6;
	
	//计算缩放比例
	int xratio = (float)winWidth / viewRect.width;
	int yratio = (float)winHeight / viewRect.height;

	ege_point points[6];
	
	//将三维空间中的多边形顶点先投影到二维平面上,再转到窗口坐标系中,然后将多边形绘制出来
	for (int i = 0; i < numPolys; i++) { 
   
		
		for (int j = 0; j < numPoints; j++) { 
   
			//三维空间中的坐标投影到xOy平面上
			points[j]   = vertexPrejection(vertices[i][j]);

			//视口变换:ViewRect 变换到窗口[(0, 0), winWidth, winHeight]
			points[j].x = (points[j].x - viewRect.x) * xratio;
			points[j].y = winHeight - (points[j].y - viewRect.y) * yratio;
		}

		//设置颜色,绘制多边形
		setfillcolor(colors[i]);
		ege_fillpoly(numPoints, points);
	}

	getch();

	closegraph();
	return 0;
}

运行结果如图:
在这里插入图片描述

2. 国际象棋棋盘

在这里插入图片描述
  国际象棋棋盘为正方形,由64个黑白(深色与浅色)相间的格子组成;棋子分黑白(深色与浅色)两方共32枚,每方各16枚。棋盘格子颜色分深色浅色两种,颜色并不固定。每个格子的绘制只需要计算出左上角坐标格子宽高即可,然后使用填充矩形来绘制。

  先对每个格子进行坐标定义,用 (列号 c o l col col, 行号 r o w row row) 来表示每个格子 (行号row :0 ~ 7,列号col:0 ~ 7),可以得到格子左上角在窗口上的坐标 ( l e f t , t o p ) (left, top) (left,top)
窗 口 坐 标 ( l e f t , t o p ) = ( 列 号 c o l ⋅ 列 宽 w i d t h , 行 号 r o w ⋅ 行 高 h e i g h t ) 窗口坐标(left,top) = (列号col \cdot 列宽width, 行号row \cdot 行高height) (left,top)=(colwidth,rowheight)  调用ege_fillrect(left, top, width, height) 即可进行绘制。
在这里插入图片描述
完整代码如下

#include <graphics.h>
#include <cmath>


int main() { 
   
	//定义格子宽高及格子行列数
	int gridWidth = 80, gridHeight = 80;
	int numCol = 8, numRow = 8;

	//计算窗口宽高及中心位置
	int winWidth = numCol * gridWidth, winHeight = numRow * gridHeight;
	int xCenter = winWidth / 2, yCenter = winHeight / 2;

	//创建窗口
	initgraph(winWidth, winHeight, INIT_RENDERMANUAL);
	ege_enable_aa(true);

	setbkcolor_f(EGERGB(0xFF, 0xFF, 0xFF));

	//定义深色和浅色
	color_t darkColor  = EGEARGB(255, 34, 34, 34);
	color_t lightColor = EGEARGB(255, 216, 216, 216);
	
	//绘制格子
	for (int row = 0; row < numRow; row++) { 
   
		for (int col = 0; col < numCol; col++) { 
   
			int x = col * gridWidth, y = row * gridHeight;
			color_t gridColor = darkColor;

			//根据格子位置确定颜色()
			if ((row + col) % 2 == 0) { 
   
				gridColor = lightColor;
			}

			//绘制格子
			setfillcolor(gridColor);
			ege_fillrect(x, y, gridWidth, gridHeight);
		}
	}

	getch();

	closegraph();
	return 0;
}

运行结果如图

在这里插入图片描述


EGE专栏:EGE专栏

上一篇:EGE基础入门篇(六):基本图形

下一篇:EGE基础入门篇(八):清屏与重绘

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/27311.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信