EGE专栏:EGE专栏
上一篇:EGE基本介绍(6):基本图形
下一篇:EGE基本介绍(8):清屏和重绘
一、 组合图形
1. 复杂图形由基本图形组成
??可以使用复杂的图形多边形可由多个三角形组成。 ??同一图形也可以以不同的方式由基本图形组合。并且可以使用后绘制的图形将首先绘制图形覆盖的原理。 
2. 绘制的顺序性
??图形的绘制有序,不能随意按任何顺序绘制。 ??
??如下图所示,当物体存在一定的遮挡关系时,需要按由远到近的顺序,先画远处的物体,再画近处的物体,这样绘制出的图形才会符合实际。否则,图中的树木会被草地和高山所覆盖。 ??在三维物体渲染中,也叫,通过按照远离视点的顺序对物体进行排序,然后按顺序绘制物体,以获得正确的渲染结果。 ??如下图所示,图为通过,得到两种不同的绘制结果,右侧按压二叉树图形是我们想要的。
二、组合图形的绘制
??
1. 彭罗斯三角形
??它是一种利用视觉错觉构造的不可能图形,在三维空间中并不真实和客观。这种图形可以从特定的角度观察到二维空间"不可能图形",因此,彭罗斯三角形是二维图形三维投影形成的光学错觉。彭罗斯三角形广泛应用于纪念碑谷。
??在二维绘图中,绘图方法有很多种,可以看作是三个不重叠的多边形组合,也可以看作是的投影(纪念碑谷的做法适合三维模型),也可以改变三维物体表面投影的屏蔽关系。 ??在这里,我们通过构建三维模型来绘制彭罗斯三角形。 ??我们首先根据物体在三维坐标系中的位置得到顶点的三维坐标,然后投影到平面上,得到平面上的二维坐标,然后转换到窗口坐标系,得到每个顶点的多边形坐标 绘图即可。
??通过对单位立方体的分析,可以发现立方体被投影成正六角形。因为投影面垂直于向量 v v v,与 v v v垂直线段投影后长度不变。从图中可以看出平面ABC垂直于向量 v v v,所以投影后 A B 、 A C 和 B C AB、AC和BC AB、AC和BC长度不变,长度为 2 \sqrt{2} 2
完整代码如下:
#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)=(列号col⋅列宽width,行号row⋅行高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基础入门篇(八):清屏与重绘