综述
最近在学习图形学的一些知识。现在做一个可交互的平面图形。
要求是:
1.三个不同的平面图形
2.可以通过鼠标“各自”进行指定的操作。
3.第二条中操作包括:旋转、平移、缩放
该文章:首先介绍一个图形时候的情况。多个图形不断更新。
环境
我是用xcode写的。但是不用担心,你需要修改的或许只是include头文件的两个字母。
基础知识:
你会在这个过程中遇到一些新的命令,如果你想弄明白可以仔细阅读下述内容。当然你也可以直接跳过。先去阅读最后的代码在回来补充知识
glPushMatrix()命令与glPopMatrix()命令
glPushMatrix、glPopMatrix操作其实就相当于栈里的入栈和出栈。许多人不明白的可能是入的是什么,出的又是什么。例如你当前的坐标系原点在你电脑屏幕的左上方。现在你调用glPushMatrix,然后再调用一堆平移、旋转代码等等,然后再画图。那些平移和旋转都是基于坐上角为原点进行变化的。而且都会改变坐标的位置,经过了这些变化后,你的坐标肯定不再左上角了。那如果想恢复怎么办呢?这时就调用glPopMatrix从栈里取出一个“状态”了,这个状态就是你调用glPushMatrix之前的那个状态。就如很多opengl的书上所讲:调用glPushMatrix其实就是把当前状态做一个副本放入堆栈之中。当你做了一些移动或旋转等变换后,使用glPushMatrix();OpenGL 会把这个变换后的位置和角度保存起来。然后你再随便做第二次移动或旋转变换,再用glPopMatrix();OpenGL 就把刚刚保存的那个位置和角度恢复。
比如:
glLoadIdentity();
glTranslatef(1,0,0);//向右移动(1,0,0)
glPushMatrix();//保存当前位置
glTranslatef(0,1,0);//现在是(1,1,0)了
更详细的可以参见如何理解glPushMatrix与glPopMatrix
glTranslatef()命令
在介绍glPushMatrix与glPopMatrix的例子时。我们看到了glTranslatef命令。那么这个命令是干嘛的呢?
其实这个就是核心:也就是我们的平移函数
glTranslatef()
当然还有旋转函数
glRotatef()
注意这系列函数都是依附于指定的坐标系
void glTranslatef(GLfloat x,GLfloat y,GLfloat z);
/*函数功能:沿X轴正方向平移x个单位(x是有符号数) 沿Y轴正方向平移y个单位(y是有符号数) 沿Z轴正方向平移z个单位(z是有符号数)*/
void glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z);
/*先解释一下旋转方向,做(0,0,0)到(x,y,z)的向量,用右手握住这条向量,大拇指指向向量的正方向,四指环绕的方向就是旋转的方向; 函数功能:以点(0,0,0)到点(x,y,z)为轴,旋转angle角度; */
这两个函数,不论是平移还是旋转都是针对于上一个矩阵来说的
glutSwapBuffers()命令
该命令就是双缓冲命令。可以避免更新时的闪烁现象。
具体可以参见:glutSwapBuffers()命令
具体实现
下面就是实现代码:(先给出一个图形时的样子)
代码不多请务必仔细阅读。
无交互的单图形移动代码
//
// main.cpp
// CG_Ep1
//
// Created by SDU_bigbean on 2018/4/3.
// Copyright © 2018年 SDU_bigbean. All rights reserved.
//
#include <iostream>
#include <GLUT/GLUT.h>
using namespace std;
int hmin,hmax; //记录扫描线开始和结束的位置
float window_size = 800;
GLfloat rtx = 0, rty = 0, rtz = 0;
/* 实验1说明: 有三个区域可以选择指定图形进行操作: 1.平移:使用方向键控制 2.缩放:支持滚轮缩放 3.旋转:支持自动控制旋转的速度(使用数字键1、2、3标志) */
//注意我们的正方形的大小是100*100的
void InitEnvironment()
{ /* 函数说明:对环境画布进行初始化操作 注意这里使用像素坐标系 */
glClearColor(0.0,0.0,0.0,0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluOrtho2D(0,window_size,0,window_size);
}
void move()
{
cout << "comming " <<endl;
static GLfloat step = 10;
if (rtx + step > 600|| rtx + step < -100)step = -step;
//限制范围不能出界
rtx += step;
glutPostRedisplay();
}
void display(void)
{ /*绘制三个不同的图形*/
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
//模型视图矩阵堆栈是干嘛用的呢?我们在三维空间中绘制模型,大部分时候需要对模
//型进行移动、旋转、缩放操作.
//而OpenGL移动的不是模型,而是坐标系
glTranslatef(rtx, rty, rtz);//指定坐标系
glBegin(GL_QUADS);
glColor3f(1.0f, 0.0f, 0.0f); //这个只是对点着色然后好看些
glVertex2f(100, 200);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(200, 200);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(200, 300);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex2f(100, 300);
glEnd();
glFlush();
glPopMatrix();
glutSwapBuffers();// 双缓冲操作。“后台先做好,再放在前台来。”可以有效避免刷新闪烁的问题。
}
int main(int argc, char *argv[])
{ glutInit(&argc, argv); //初始化GLUT
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(300, 100);
glutInitWindowSize(window_size, window_size);
glutCreateWindow("实验1");
InitEnvironment(); //初始化
glutDisplayFunc(display);
glutIdleFunc(move);//进行移动操作
glutMainLoop(); //持续显示,当窗口改变会重新绘制图形
return 0;
}
有交互的单图形移动代码
有交互的多图形移动代码