openGL-设计交互平面图形(旋转、平移、缩放)

时间:2022-11-04 10:23:25

综述

最近在学习图形学的一些知识。现在做一个可交互的平面图形。
要求是:
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;
}

有交互的单图形移动代码

有交互的多图形移动代码