矩阵计算啥的就不提了
这里看一下齐次坐标:
用n+1维向量表示n维向量, 主要解决透视空间的问题, 在OpenGL中, 使用的都是齐次坐标:
具体的可以参考这片博客:
https://blog.csdn.net/zhuiqiuzhuoyue583/article/details/95228010
基础的三种图形变换:
其余的变换通常都能转化为这三种最基础的变换
感觉二维变换中无法使用glut提供的三个3D矩阵变换函数来进行变换, 最终还是得手算矩阵…
反正最后大作业肯定用的3D, 这里的2D还是先放着吧
这个是实验上机时做的, 时间不太够, 所以完全是百度的仿制版
其中也没用到矩阵计算啥的, 感觉不太好, 之后重做一份
#define NDEBUG
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#include
#include
#include
#include
#include
using namespace std;
const int windowWidge=600, windowHeight=600;
void setPixel(GLint xCoord, GLint yCoord){
glBegin (GL_POINTS);
glVertex2i (xCoord, yCoord);
glEnd();
}
//---------------------------------------------
// Bresenham 画圆
class screenPt {
private:
GLint x, y;
public:
screenPt() { x = y = 0; }
void setCoords(GLint xCoordValue, GLint yCoordValue) {
x = xCoordValue;
y = yCoordValue;
}
GLint getx() const { return x; }
GLint gety() const { return y; }
void incremetx() { x++; }
void decrementy() { y--; }
};
void circleMidp(GLint xc, GLint yc, GLint radius) {
screenPt circPt;
GLint p = 1 - radius;
circPt.setCoords(0, radius);
void circlePlotPoints(GLint, GLint, screenPt);
circlePlotPoints(xc, yc, circPt);
while (circPt.getx() < circPt.gety()) {
circPt.incremetx();
if (p < 0)
p += 2 * circPt.getx() + 1;
else {
circPt.decrementy();
p += 2 * (circPt.getx() - circPt.gety()) + 1;
}
circlePlotPoints(xc, yc, circPt);
}
}
void circlePlotPoints(GLint xc, GLint yc, screenPt circPt) {
setPixel(xc + circPt.getx(), yc + circPt.gety());
setPixel(xc - circPt.getx(), yc + circPt.gety());
setPixel(xc + circPt.getx(), yc - circPt.gety());
setPixel(xc - circPt.getx(), yc - circPt.gety());
setPixel(xc + circPt.gety(), yc + circPt.getx());
setPixel(xc - circPt.gety(), yc + circPt.getx());
setPixel(xc + circPt.gety(), yc - circPt.getx());
setPixel(xc - circPt.gety(), yc - circPt.getx());
}
//---------------------------------------------
//组合模型变换: 时钟
const GLfloat PI = 3.141592653f;
// 显示的时间,时 分 秒
float h = 0.0f;
float m = 0.0f;
float s = 0.0f;
//定时器回调函数:
void timerFunc(int value){
//设置时分秒针
s += 1;
int carry1 = 0;
if (s >= 60){
s = 0;
carry1 = 1;
}
m += carry1;
int carry2 = 0;
if (m >= 60){
m = 0;
carry2 = 1;
}
h += carry2;
if (h >= 24){
h = 0;
}
// 重绘
glutPostRedisplay();
glutTimerFunc(1000, timerFunc, 1); // 每1000ms中执行一次
return ;
}
//绘制函数
void clockDisplay(){
// 用当前清除色清除颜色缓冲区,即设定窗口的背景色
glClear(GL_COLOR_BUFFER_BIT);
// 黑色
glColor3f(0.1f, 0.2f, 0.1f);
// 绘制时钟外边框
int cx=windowWidge/2, cy=windowHeight/2;
int R=150;
circleMidp (cx, cy, R); //这里用的 Bresenham 画圆
circleMidp (cx, cy, R-3);
//绘制时钟刻度:
int lineNum=60;
int w1=5, w2=2;
float len1=10, len2=5;
for(int i=0;i<lineNum;++i){
//12条粗线
if(i%5==0){
glLineWidth(w1);
//glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINES);
glVertex2f(cx + (R - len1)*sin(2 * PI / lineNum * i), cy + (R - len1)*cos(2 * PI / lineNum * i));
glVertex2f(cx + R*sin(2 * PI / lineNum * i), cy + R*cos(2 * PI / lineNum * i));
glEnd();
}
//其余细线
else{
glLineWidth(w2); //其他的刻度
//glColor3f(0.0, 0.0, 1.0);
glBegin(GL_LINES);
glVertex2f(cx + (R - len2)*sin(2 * PI / lineNum * i), cy + (R - len2)*cos(2 * PI / lineNum * i));
glVertex2f(cx + R*sin(2 * PI / lineNum * i), cy + R*cos(2 * PI / lineNum * i));
glEnd();
}
}
//绘制时钟中心点
int dotWidth=3;
for(int i=1;i<=dotWidth;++i){
circleMidp (cx, cy, i);
}
//绘制时分秒针
int hLen=R-len1-50;
int mLen=R-len1-25;
int sLen=R-len1-5;
//12小时制
int h12= h >= 12 ? (h - 12) : h;
float sAngle=s/60.0;
float mAngle=(m * 60 + s) / 3600.0;
float hAngle=(h12 * 60 * 60 + m * 60 + s) / (12 * 60 * 60);
// 秒
glLineWidth(1);
glBegin(GL_LINES);
glVertex2f(cx, cy);
glVertex2f(cx + sLen*sin(2 * PI*sAngle), cy + sLen*cos(2 * PI*sAngle));
glEnd();
// 分
glLineWidth(3);
glBegin(GL_LINES);
glVertex2f(cx, cy);
glVertex2f(cx + mLen*sin(2 * PI*mAngle), cy + mLen*cos(2 * PI*mAngle));
glEnd();
// 时
glLineWidth(5);
glBegin(GL_LINES);
glVertex2f(cx, cy);
glVertex2f(cx + hLen*sin(2 * PI*hAngle), cy + hLen*cos(2 * PI*hAngle));
glEnd();
glFlush ();
return ;
}
//---------------------------------------------
//初始化绘制
void init(){
glClearColor(1.0,1.0,1.0,0.0);//清除颜色设置
glMatrixMode(GL_PROJECTION);//设置投影方式
//获取本地时间
SYSTEMTIME sys;
GetLocalTime(&sys);
h = sys.wHour;
m = sys.wMinute;
s = sys.wSecond;
gluOrtho2D (0.0,windowWidge*1.0,0.0,windowHeight*1.0);
return ;
}
int main(int argc, char** argv){
glutInit(&argc, argv);//初始化glut
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//设置显示模式为单缓冲,RGB模式
glutInitWindowPosition(0,0);//设置窗口位置
glutInitWindowSize(windowWidge,windowHeight);//设置窗口大小
glutCreateWindow("时钟");//设置窗口标题
init();
glutDisplayFunc(clockDisplay);
glutTimerFunc(1000, timerFunc, 1);
glutMainLoop();
return 0;
}
几个新知识点:
定时器:
注册一个函数, 间隔一定时间再执行, 只执行一次, 所以源码中在调用函数中又添加了glutTimerFunc()
glutTimerFunc(unsigned int msecs,void(*func)(int value),int value)
msecs
在调用func函数之前要等待的时间(单位:毫秒)
func
注册一个调用函数,在等待msecs毫秒之后执行
注意func的返回值为void, 参数为int
value
作为参数传递给func